{"id":42499963,"url":"https://github.com/osamingo/go-csvpp","last_synced_at":"2026-02-05T17:00:26.219Z","repository":{"id":335086124,"uuid":"1141881031","full_name":"osamingo/go-csvpp","owner":"osamingo","description":"A Go implementation of the IETF CSV++ specification","archived":false,"fork":false,"pushed_at":"2026-01-28T16:20:45.000Z","size":45,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-29T02:17:54.637Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/osamingo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-25T15:40:56.000Z","updated_at":"2026-01-28T16:20:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/osamingo/go-csvpp","commit_stats":null,"previous_names":["osamingo/go-csvpp"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/osamingo/go-csvpp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osamingo%2Fgo-csvpp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osamingo%2Fgo-csvpp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osamingo%2Fgo-csvpp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osamingo%2Fgo-csvpp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/osamingo","download_url":"https://codeload.github.com/osamingo/go-csvpp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osamingo%2Fgo-csvpp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29126040,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-05T14:05:12.718Z","status":"ssl_error","status_checked_at":"2026-02-05T14:03:53.078Z","response_time":65,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-28T13:03:53.663Z","updated_at":"2026-02-05T17:00:26.203Z","avatar_url":"https://github.com/osamingo.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# go-csvpp\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/osamingo/go-csvpp.svg)](https://pkg.go.dev/github.com/osamingo/go-csvpp)\n[![Go Report Card](https://goreportcard.com/badge/github.com/osamingo/go-csvpp)](https://goreportcard.com/report/github.com/osamingo/go-csvpp)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA Go implementation of the [IETF CSV++ specification](https://datatracker.ietf.org/doc/draft-mscaldas-csvpp/) (draft-mscaldas-csvpp-01).\n\nCSV++ extends traditional CSV to support **arrays** and **structured fields** within cells, enabling complex data representation while maintaining CSV's simplicity.\n\n## Features\n\n- Full IETF CSV++ specification compliance\n- Wraps `encoding/csv` for RFC 4180 compatibility\n- Four field types: Simple, Array, Structured, ArrayStructured\n- Struct mapping with `csvpp` tags (Marshal/Unmarshal)\n- Configurable delimiters\n- Security-conscious design (nesting depth limits)\n\n## Requirements\n\n- Go 1.24 or later\n\n## Installation\n\n```bash\ngo get github.com/osamingo/go-csvpp\n```\n\n## Quick Start\n\n### Reading CSV++ Data\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"io\"\n    \"strings\"\n\n    \"github.com/osamingo/go-csvpp\"\n)\n\nfunc main() {\n    input := `name,phone[],geo(lat^lon)\nAlice,555-1234~555-5678,34.0522^-118.2437\nBob,555-9999,40.7128^-74.0060\n`\n\n    reader := csvpp.NewReader(strings.NewReader(input))\n\n    for {\n        record, err := reader.Read()\n        if err == io.EOF {\n            break\n        }\n        if err != nil {\n            panic(err)\n        }\n\n        name := record[0].Value\n        phones := record[1].Values\n        lat := record[2].Components[0].Value\n        lon := record[2].Components[1].Value\n\n        fmt.Printf(\"%s: phones=%v, location=(%s, %s)\\n\", name, phones, lat, lon)\n    }\n}\n```\n\nOutput:\n```\nAlice: phones=[555-1234 555-5678], location=(34.0522, -118.2437)\nBob: phones=[555-9999], location=(40.7128, -74.0060)\n```\n\n### Writing CSV++ Data\n\n```go\npackage main\n\nimport (\n    \"bytes\"\n    \"fmt\"\n\n    \"github.com/osamingo/go-csvpp\"\n)\n\nfunc main() {\n    var buf bytes.Buffer\n    writer := csvpp.NewWriter(\u0026buf)\n\n    headers := []*csvpp.ColumnHeader{\n        {Name: \"name\", Kind: csvpp.SimpleField},\n        {Name: \"tags\", Kind: csvpp.ArrayField, ArrayDelimiter: '~'},\n    }\n    writer.SetHeaders(headers)\n\n    if err := writer.WriteHeader(); err != nil {\n        panic(err)\n    }\n    if err := writer.Write([]*csvpp.Field{\n        {Value: \"Alice\"},\n        {Values: []string{\"go\", \"rust\", \"python\"}},\n    }); err != nil {\n        panic(err)\n    }\n    writer.Flush()\n\n    fmt.Print(buf.String())\n}\n```\n\nOutput:\n```\nname,tags[]\nAlice,go~rust~python\n```\n\n### Struct Mapping\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"strings\"\n\n    \"github.com/osamingo/go-csvpp\"\n)\n\ntype Person struct {\n    Name   string   `csvpp:\"name\"`\n    Phones []string `csvpp:\"phone[]\"`\n    Geo    struct {\n        Lat string\n        Lon string\n    } `csvpp:\"geo(lat^lon)\"`\n}\n\nfunc main() {\n    input := `name,phone[],geo(lat^lon)\nAlice,555-1234~555-5678,34.0522^-118.2437\n`\n\n    var people []Person\n    if err := csvpp.Unmarshal(strings.NewReader(input), \u0026people); err != nil {\n        panic(err)\n    }\n\n    for _, p := range people {\n        fmt.Printf(\"%s: phones=%v, geo=(%s, %s)\\n\",\n            p.Name, p.Phones, p.Geo.Lat, p.Geo.Lon)\n    }\n}\n```\n\nOutput:\n```\nAlice: phones=[555-1234 555-5678], geo=(34.0522, -118.2437)\n```\n\n## Field Types\n\nCSV++ supports four field types in headers:\n\n| Type | Header Syntax | Example Data | Description |\n|------|---------------|--------------|-------------|\n| Simple | `name` | `Alice` | Plain text value |\n| Array | `tags[]` | `go~rust~python` | Multiple values with delimiter |\n| Structured | `geo(lat^lon)` | `34.05^-118.24` | Named components |\n| ArrayStructured | `addr[](city^zip)` | `LA^90210~NY^10001` | Array of structures |\n\n### Default Delimiters\n\n- Array delimiter: `~` (tilde)\n- Component delimiter: `^` (caret)\n\nCustom delimiters can be specified in the header:\n- `phone[|]` - uses `|` as array delimiter\n- `geo;(lat;lon)` - uses `;` as component delimiter\n\n### Delimiter Progression\n\nFor nested structures, the IETF specification recommends:\n\n| Level | Delimiter |\n|-------|-----------|\n| 1 (arrays) | `~` |\n| 2 (components) | `^` |\n| 3 | `;` |\n| 4 | `:` |\n\n## API Reference\n\n### Reader\n\n```go\nreader := csvpp.NewReader(r) // r is io.Reader\n\n// Configuration (same as encoding/csv)\nreader.Comma = ','           // Field delimiter\nreader.Comment = '#'         // Comment character\nreader.LazyQuotes = false    // Relaxed quote handling\nreader.TrimLeadingSpace = false\nreader.MaxNestingDepth = 10  // Nesting limit (security)\n\n// Methods\nheaders, err := reader.Headers()  // Get parsed headers\nrecord, err := reader.Read()      // Read one record\nrecords, err := reader.ReadAll()  // Read all records\n```\n\n### Writer\n\n```go\nwriter := csvpp.NewWriter(w) // w is io.Writer\n\n// Configuration\nwriter.Comma = ','      // Field delimiter\nwriter.UseCRLF = false  // Use \\r\\n line endings\n\n// Methods\nwriter.SetHeaders(headers)  // Set column headers\nwriter.WriteHeader()        // Write header row\nwriter.Write(record)        // Write one record\nwriter.WriteAll(records)    // Write all records\nwriter.Flush()              // Flush buffer\n```\n\n### Marshal/Unmarshal\n\n```go\n// Unmarshal CSV++ data into structs\nvar people []Person\nerr := csvpp.Unmarshal(reader, \u0026people)\n\n// Marshal structs to CSV++ data\nerr := csvpp.Marshal(writer, people)\n```\n\n### Struct Tags\n\nUse `csvpp` struct tags to map fields:\n\n```go\ntype Record struct {\n    Name     string   `csvpp:\"name\"`           // Simple field\n    Tags     []string `csvpp:\"tags[]\"`         // Array field\n    Location struct {                          // Structured field\n        Lat string\n        Lon string\n    } `csvpp:\"geo(lat^lon)\"`\n    Addresses []Address `csvpp:\"addr[](street^city)\"` // Array structured\n}\n```\n\n## JSON/YAML Conversion (csvpputil)\n\nThe `csvpputil` package provides utilities for converting CSV++ data to JSON and YAML formats.\n\n### Installation\n\n```bash\ngo get github.com/osamingo/go-csvpp/csvpputil\n```\n\n### Quick Conversion\n\n```go\nimport \"github.com/osamingo/go-csvpp/csvpputil\"\n\n// Convert to JSON\njsonData, err := csvpputil.MarshalJSON(headers, records)\n\n// Convert to YAML\nyamlData, err := csvpputil.MarshalYAML(headers, records)\n\n// Write directly to io.Writer\nerr = csvpputil.WriteJSON(w, headers, records)\nerr = csvpputil.WriteYAML(w, headers, records)\n```\n\n### Streaming Output\n\nFor large datasets, use streaming writers:\n\n```go\n// JSON streaming\nw := csvpputil.NewJSONArrayWriter(out, headers)\nfor _, record := range records {\n    if err := w.Write(record); err != nil {\n        return err\n    }\n}\nif err := w.Close(); err != nil {\n    return err\n}\n\n// YAML streaming\nw := csvpputil.NewYAMLArrayWriter(out, headers)\nfor _, record := range records {\n    if err := w.Write(record); err != nil {\n        return err\n    }\n}\nif err := w.Close(); err != nil {\n    return err\n}\n```\n\n### Example Output\n\nGiven CSV++ data:\n```\nname,tags[],geo(lat^lon)\nAlice,go~rust,35.6762^139.6503\n```\n\nJSON output:\n```json\n[{\"name\":\"Alice\",\"tags\":[\"go\",\"rust\"],\"geo\":{\"lat\":\"35.6762\",\"lon\":\"139.6503\"}}]\n```\n\nYAML output:\n```yaml\n- name: Alice\n  tags:\n  - go\n  - rust\n  geo:\n    lat: \"35.6762\"\n    lon: \"139.6503\"\n```\n\n## Compatibility\n\nThis package wraps `encoding/csv` and inherits:\n- Full RFC 4180 compliance\n- Quoted field handling\n- Configurable field/line delimiters\n- Comment support\n\n## Security\n\n- **MaxNestingDepth**: Limits nested structure depth (default: 10) to prevent stack overflow from malicious input\n- Header names are restricted to ASCII characters per IETF specification\n\n### CSV Injection Prevention\n\nWhen CSV files are opened in spreadsheet applications, values starting with `=`, `+`, `-`, or `@` may be interpreted as formulas. Use `HasFormulaPrefix` to detect and escape dangerous values:\n\n```go\nif csvpp.HasFormulaPrefix(value) {\n    value = \"'\" + value // Escape for spreadsheet safety\n}\n```\n\n## Specification\n\nThis implementation follows the IETF CSV++ specification:\n- [draft-mscaldas-csvpp-01](https://datatracker.ietf.org/doc/draft-mscaldas-csvpp/)\n\n## License\n\nMIT License - see [LICENSE](LICENSE) for details.\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fosamingo%2Fgo-csvpp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fosamingo%2Fgo-csvpp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fosamingo%2Fgo-csvpp/lists"}