{"id":32570907,"url":"https://github.com/netascode/xmldot","last_synced_at":"2025-10-29T08:21:24.290Z","repository":{"id":319480255,"uuid":"1073579815","full_name":"netascode/xmldot","owner":"netascode","description":"High-performance Go library for querying and manipulating XML using GJSON-inspired path syntax. Zero dependencies, blazing fast, security-first design.","archived":false,"fork":false,"pushed_at":"2025-10-27T19:28:27.000Z","size":363,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-27T21:25:50.999Z","etag":null,"topics":["golang","xml","xml-parser"],"latest_commit_sha":null,"homepage":"https://netascode.github.io/xmldot-playground/","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/netascode.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","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":"2025-10-10T10:11:18.000Z","updated_at":"2025-10-27T19:28:21.000Z","dependencies_parsed_at":"2025-10-19T08:05:26.089Z","dependency_job_id":"68fe0f77-0d32-4764-a5ad-16a88a8f77cd","html_url":"https://github.com/netascode/xmldot","commit_stats":null,"previous_names":["netascode/xmldot"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/netascode/xmldot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netascode%2Fxmldot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netascode%2Fxmldot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netascode%2Fxmldot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netascode%2Fxmldot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/netascode","download_url":"https://codeload.github.com/netascode/xmldot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netascode%2Fxmldot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281585785,"owners_count":26526366,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-29T02:00:06.901Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["golang","xml","xml-parser"],"created_at":"2025-10-29T08:19:41.243Z","updated_at":"2025-10-29T08:21:24.282Z","avatar_url":"https://github.com/netascode.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\".github/images/logo-dark.svg\"\u003e\n  \u003csource media=\"(prefers-color-scheme: light)\" srcset=\".github/images/logo.svg\"\u003e\n  \u003cimg src=\".github/images/logo.svg\" alt=\"xmldot logo\" width=\"120\"\u003e\n\u003c/picture\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://img.shields.io/badge/xmldot-v0.3.1-blue.svg?style=flat-square\" alt=\"xmldot\"\u003e\n\u003cbr\u003e\n\u003ca href=\"https://godoc.org/github.com/netascode/xmldot\"\u003e\u003cimg src=\"https://img.shields.io/badge/api-reference-blue.svg?style=flat-square\" alt=\"GoDoc\"\u003e\u003c/a\u003e\n\u003ca href=\"https://goreportcard.com/report/github.com/netascode/xmldot\"\u003e\u003cimg src=\"https://goreportcard.com/badge/github.com/netascode/xmldot?style=flat-square\" alt=\"Go Report Card\"\u003e\u003c/a\u003e\n\u003ca href=\"https://codecov.io/gh/netascode/xmldot\"\u003e\u003cimg src=\"https://codecov.io/gh/netascode/xmldot/branch/main/graph/badge.svg?style=flat-square\" alt=\"codecov\"\u003e\u003c/a\u003e\n\u003ca href=\"https://netascode.github.io/xmldot-playground/\"\u003e\u003cimg src=\"https://img.shields.io/badge/playground-try_online-green.svg?style=flat-square\" alt=\"Playground\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003ch3 align=\"center\"\u003eget and set xml values with dot notation\u003c/h3\u003e\n\nXMLDOT is a Go package that provides a [fast](docs/performance.md) and [simple](#get-a-value) way to get and set values in XML documents. It has features such as [dot notation paths](#path-syntax), [wildcards](#wildcards), [filters](#filters), [modifiers](#modifiers), and [array operations](#working-with-arrays).\n\nInspired by [GJSON](https://github.com/tidwall/gjson) and [SJSON](https://github.com/tidwall/sjson) for JSON.\n\nGetting Started\n===============\n\n## Installing\n\nTo start using XMLDOT, install Go and run `go get`:\n\n```sh\n$ go get -u github.com/netascode/xmldot\n```\n\nThis will retrieve the library.\n\n## Try It Online\n\n**[🎮 Interactive Playground](https://netascode.github.io/xmldot-playground/)**\n\nExperiment with XMLDOT in your browser without installing anything. The playground lets you:\n- Test path queries against sample or custom XML\n- Explore filters, wildcards, and modifiers\n- See results in real-time\n- Learn the syntax interactively\n\nPerfect for learning or prototyping queries before using in code.\n\n## Get a value\n\nGet searches XML for the specified path. A path is in dot syntax, such as \"book.title\" or \"book.@id\". When the value is found it's returned immediately.\n\n```go\npackage main\n\nimport \"github.com/netascode/xmldot\"\n\nconst xml = `\n\u003ccatalog\u003e\n    \u003cbook id=\"1\"\u003e\n        \u003ctitle\u003eThe Go Programming Language\u003c/title\u003e\n        \u003cauthor\u003eAlan Donovan\u003c/author\u003e\n        \u003cprice\u003e44.99\u003c/price\u003e\n    \u003c/book\u003e\n\u003c/catalog\u003e`\n\nfunc main() {\n    title := xmldot.Get(xml, \"catalog.book.title\")\n    println(title.String())\n}\n```\n\nThis will print:\n\n```\nThe Go Programming Language\n```\n\n## Fluent API (v0.2.0+)\n\nThe fluent API enables method chaining on Result objects for cleaner, more readable code:\n\n```go\n// Basic fluent chaining\nroot := xmldot.Get(xml, \"root\")\nname := root.Get(\"user.name\").String()\nage := root.Get(\"user.age\").Int()\n\n// Deep chaining\nfullPath := xmldot.Get(xml, \"root\").\n    Get(\"company\").\n    Get(\"department\").\n    Get(\"team.member\").\n    Get(\"name\").\n    String()\n\n// Batch queries\nuser := xmldot.Get(xml, \"root.user\")\nresults := user.GetMany(\"name\", \"age\", \"email\")\nname := results[0].String()\nage := results[1].Int()\nemail := results[2].String()\n\n// Case-insensitive queries\nopts := \u0026xmldot.Options{CaseSensitive: false}\nname := root.GetWithOptions(\"USER.NAME\", opts).String()\n```\n\n**Performance**: Fluent chaining adds ~280% overhead for 3-level chains compared to full paths. For performance-critical code, use direct paths:\n\n```go\n// Fast (recommended for hot paths)\nname := xmldot.Get(xml, \"root.user.name\")\n\n// Readable (recommended for business logic)\nuser := xmldot.Get(xml, \"root.user\")\nname := user.Get(\"name\")\n```\n\n**Array Handling**: Field extraction on arrays requires explicit `#.field` syntax:\n\n```go\nitems := xmldot.Get(xml, \"catalog.items\")\n// Extract all prices\nprices := items.Get(\"item.#.price\")  // Array of all prices\n```\n\n## Set a value\n\nSet modifies an XML value for the specified path. A path is in dot syntax, such as \"book.title\" or \"book.@id\".\n\n```go\npackage main\n\nimport \"github.com/netascode/xmldot\"\n\nconst xml = `\n\u003ccatalog\u003e\n    \u003cbook id=\"1\"\u003e\n        \u003ctitle\u003eThe Go Programming Language\u003c/title\u003e\n        \u003cprice\u003e44.99\u003c/price\u003e\n    \u003c/book\u003e\n\u003c/catalog\u003e`\n\nfunc main() {\n    value, _ := xmldot.Set(xml, \"catalog.book.price\", 39.99)\n    println(value)\n}\n```\n\nThis will print:\n\n```xml\n\u003ccatalog\u003e\u003cbook id=\"1\"\u003e\u003ctitle\u003eThe Go Programming Language\u003c/title\u003e\u003cprice\u003e39.99\u003c/price\u003e\u003c/book\u003e\u003c/catalog\u003e\n```\n\n### Creating Elements with Attributes (v0.3.0+)\n\nStarting from v0.3.0, Set automatically creates missing parent elements when setting attributes. This makes it easy to add attributes to elements that don't yet exist:\n\n```go\nxml := `\u003croot\u003e\u003c/root\u003e`\n\n// Automatically creates \u003cuser\u003e element with id attribute\nresult, _ := xmldot.Set(xml, \"root.user.@id\", \"123\")\n// Result: \u003croot\u003e\u003cuser id=\"123\"\u003e\u003c/user\u003e\u003c/root\u003e\n\n// Works with deep paths too\nresult, _ = xmldot.Set(xml, \"root.company.department.@name\", \"Engineering\")\n// Result: \u003croot\u003e\u003ccompany\u003e\u003cdepartment name=\"Engineering\"\u003e\u003c/department\u003e\u003c/company\u003e\u003c/root\u003e\n```\n\nBefore v0.3.0, setting an attribute on a non-existent element would return an error. Now the element is automatically created.\n\n## Path Syntax\n\nA path is a series of keys separated by a dot. The dot character can be escaped with `\\`.\n\n```xml\n\u003ccatalog\u003e\n    \u003cbook id=\"1\"\u003e\n        \u003ctitle\u003eThe Go Programming Language\u003c/title\u003e\n        \u003cauthor\u003eAlan Donovan\u003c/author\u003e\n        \u003cprice\u003e44.99\u003c/price\u003e\n        \u003ctags\u003e\n            \u003ctag\u003eprogramming\u003c/tag\u003e\n            \u003ctag\u003ego\u003c/tag\u003e\n        \u003c/tags\u003e\n    \u003c/book\u003e\n    \u003cbook id=\"2\"\u003e\n        \u003ctitle\u003eLearning Go\u003c/title\u003e\n        \u003cauthor\u003eJon Bodner\u003c/author\u003e\n        \u003cprice\u003e39.99\u003c/price\u003e\n    \u003c/book\u003e\n\u003c/catalog\u003e\n```\n\n```\ncatalog.book.title           \u003e\u003e \"The Go Programming Language\"\ncatalog.book.@id             \u003e\u003e \"1\"\ncatalog.book.price           \u003e\u003e \"44.99\"\ncatalog.book.1.title         \u003e\u003e \"Learning Go\"\ncatalog.book.#               \u003e\u003e 2\ncatalog.book.tags.tag.0      \u003e\u003e \"programming\"\ncatalog.book.title.%         \u003e\u003e \"The Go Programming Language\"\n```\n\n### Arrays\n\nArray elements are accessed by index:\n\n```\ncatalog.book.0.title         \u003e\u003e \"The Go Programming Language\" (first book)\ncatalog.book.1.title         \u003e\u003e \"Learning Go\" (second book)\ncatalog.book.#               \u003e\u003e 2 (count of books)\ncatalog.book.tags.tag.#      \u003e\u003e 2 (count of tags)\n```\n\n### Attributes\n\nAttributes are accessed with the `@` prefix:\n\n```\ncatalog.book.@id             \u003e\u003e \"1\"\ncatalog.book.0.@id           \u003e\u003e \"1\"\ncatalog.book.1.@id           \u003e\u003e \"2\"\n```\n\n### Text Content\n\nText content (ignoring child elements) uses the `%` operator:\n\n```\ncatalog.book.title.%         \u003e\u003e \"The Go Programming Language\"\n```\n\n## Wildcards\n\nSingle-level wildcards `*` match any element at that level. Recursive wildcards `**` match elements at any depth:\n\n```xml\n\u003ccatalog\u003e\n    \u003cbook id=\"1\"\u003e\n        \u003ctitle\u003eThe Go Programming Language\u003c/title\u003e\n        \u003cprice\u003e44.99\u003c/price\u003e\n    \u003c/book\u003e\n    \u003cbook id=\"2\"\u003e\n        \u003ctitle\u003eLearning Go\u003c/title\u003e\n        \u003cprice\u003e39.99\u003c/price\u003e\n    \u003c/book\u003e\n\u003c/catalog\u003e\n```\n\n```\ncatalog.*.title              \u003e\u003e [\"The Go Programming Language\", \"Learning Go\"]\ncatalog.book.*.%             \u003e\u003e [\"The Go Programming Language\", \"Alan Donovan\", \"44.99\", ...]\ncatalog.**.price             \u003e\u003e [\"44.99\", \"39.99\"] (all prices at any depth)\n```\n\n## Filters\n\nYou can filter elements using GJSON-style query syntax. Supports `==`, `!=`, `\u003c`, `\u003e`, `\u003c=`, `\u003e=`, `%`, `!%` operators:\n\n```xml\n\u003ccatalog\u003e\n    \u003cbook status=\"active\"\u003e\n        \u003ctitle\u003eThe Go Programming Language\u003c/title\u003e\n        \u003cprice\u003e44.99\u003c/price\u003e\n    \u003c/book\u003e\n    \u003cbook status=\"active\"\u003e\n        \u003ctitle\u003eLearning Go\u003c/title\u003e\n        \u003cprice\u003e39.99\u003c/price\u003e\n    \u003c/book\u003e\n    \u003cbook status=\"discontinued\"\u003e\n        \u003ctitle\u003eOld Book\u003c/title\u003e\n        \u003cprice\u003e19.99\u003c/price\u003e\n    \u003c/book\u003e\n\u003c/catalog\u003e\n```\n\n```\ncatalog.book.#(price\u003e40).title               \u003e\u003e \"The Go Programming Language\"\ncatalog.book.#(@status==active)#.title       \u003e\u003e [\"The Go...\", \"Learning Go\"]\ncatalog.book.#(price\u003c30).#(@status==active)  \u003e\u003e [] (no matches)\ncatalog.book.#(title%\"*Go*\")#.title          \u003e\u003e [\"The Go...\", \"Learning Go\"] (pattern match)\n```\n\n## Modifiers\n\nModifiers transform query results using the `|` operator:\n\n```\ncatalog.book.title|@reverse                  \u003e\u003e [\"Learning Go\", \"The Go...\"]\ncatalog.book.price|@sort                     \u003e\u003e [\"39.99\", \"44.99\"]\ncatalog.book.title|@first                    \u003e\u003e \"The Go Programming Language\"\ncatalog.book.title|@last                     \u003e\u003e \"Learning Go\"\ncatalog.book|@pretty                         \u003e\u003e formatted XML\n```\n\n### Built-in modifiers\n\n- `@reverse`: Reverse array order\n- `@sort`: Sort array elements\n- `@first`: Get first element\n- `@last`: Get last element\n- `@keys`: Get element names\n- `@values`: Get element values\n- `@flatten`: Flatten nested arrays\n- `@pretty`: Format XML with indentation\n- `@ugly`: Remove all whitespace\n- `@raw`: Get raw XML without parsing\n\n### Custom modifiers\n\nYou can add your own modifiers:\n\n```go\nxmldot.AddModifier(\"uppercase\", func(xml, arg string) string {\n    return strings.ToUpper(xml)\n})\n\nresult := xmldot.Get(xml, \"catalog.book.title|@uppercase\")\n// \"THE GO PROGRAMMING LANGUAGE\"\n```\n\n## Working with Arrays\n\nThe `Result.Array()` function returns an array of values. The `ForEach` function allows iteration:\n\n```go\nresult := xmldot.Get(xml, \"catalog.book.title\")\nfor _, title := range result.Array() {\n    println(title.String())\n}\n```\n\nOr use `ForEach`:\n\n```go\nxmldot.Get(xml, \"catalog.book\").ForEach(func(_, book xmldot.Result) bool {\n    println(book.Get(\"title\").String())\n    return true // keep iterating\n})\n```\n\n## Result Type\n\nXMLDOT returns a `Result` type that holds the value and provides methods to access it:\n\n```go\nresult.Type           // String, Number, True, False, Null, or XML\nresult.Str            // the string value\nresult.Num            // the float64 number\nresult.Raw            // the raw xml\nresult.Index          // index in original xml\n\nresult.String() string\nresult.Bool() bool\nresult.Int() int64\nresult.Uint() uint64\nresult.Float() float64\nresult.Array() []Result\nresult.Map() map[string]Result\nresult.Exists() bool\nresult.Get(path string) Result\nresult.ForEach(iterator func(key, value Result) bool)\n```\n\n## Namespaces\n\nBasic namespace prefix matching is supported:\n\n```xml\n\u003croot xmlns:ns=\"http://example.com\"\u003e\n    \u003cns:item\u003evalue\u003c/ns:item\u003e\n\u003c/root\u003e\n```\n\n```\nroot.ns:item                 \u003e\u003e \"value\"\n```\n\n**Note**: Only prefix matching is supported. Namespace URIs are not resolved. For full namespace support, use `encoding/xml`.\n\n## Validation\n\nValidate XML before processing:\n\n```go\nif !xmldot.Valid(xml) {\n    return errors.New(\"invalid xml\")\n}\n\n// Or get detailed errors\nif err := xmldot.ValidateWithError(xml); err != nil {\n    fmt.Printf(\"Error at line %d, column %d: %s\\n\",\n        err.Line, err.Column, err.Message)\n}\n```\n\n## Multiple Paths\n\nGet multiple paths efficiently:\n\n```go\nresults := xmldot.GetMany(xml, \"catalog.book.0.title\", \"catalog.book.0.price\")\nprintln(results[0].String())  // title\nprintln(results[1].Float())   // price\n```\n\nSet multiple paths:\n\n```go\npaths := []string{\"catalog.book.0.price\", \"catalog.book.1.price\"}\nvalues := []interface{}{39.99, 34.99}\nresult, _ := xmldot.SetMany(xml, paths, values)\n```\n\nDelete multiple paths:\n\n```go\nresult, _ := xmldot.DeleteMany(xml, \"catalog.book.0.tags\", \"catalog.book.1.tags\")\n```\n\n## Working with Bytes\n\nIf your XML is in a `[]byte` slice, use `GetBytes`:\n\n```go\nvar xml []byte = ...\nresult := xmldot.GetBytes(xml, \"catalog.book.title\")\n```\n\n## Design Philosophy\n\n**Zero External Dependencies**: XMLDOT uses only Go standard library for portability and security. All functionality including pattern matching uses internal implementations with built-in security protections.\n\n## Concurrency\n\nAll read operations are thread-safe and can be used concurrently without synchronization:\n\n```go\n// Safe: concurrent reads\nvar wg sync.WaitGroup\nfor i := 0; i \u003c 100; i++ {\n    wg.Add(1)\n    go func(id int) {\n        defer wg.Done()\n        result := xmldot.Get(xml, fmt.Sprintf(\"users.user.%d.name\", id))\n        process(result)\n    }(i)\n}\nwg.Wait()\n```\n\nWrite operations require external synchronization:\n\n```go\nvar mu sync.Mutex\ncurrentXML := \"\u003croot\u003e\u003c/root\u003e\"\n\nfunc updateXML(path string, value interface{}) {\n    mu.Lock()\n    defer mu.Unlock()\n    result, _ := xmldot.Set(currentXML, path, value)\n    currentXML = result\n}\n```\n\nSee the [Concurrency Guide](docs/concurrency.md) for patterns and best practices.\n\n## Documentation\n\n### Guides\n\n- [Path Syntax Reference](docs/path-syntax.md) - Complete path expression guide\n- [Error Handling Guide](docs/error-handling.md) - Error types and patterns\n- [Performance Guide](docs/performance.md) - Optimization techniques\n- [Concurrency Guide](docs/concurrency.md) - Thread-safety patterns\n- [Security Guide](docs/security.md) - Security features and limits\n- [Migration Guide](docs/migration.md) - Moving from other libraries\n\n### Examples\n\n- [Basic Get Queries](examples/basic-get/) - Simple element access\n- [Basic Set Operations](examples/basic-set/) - Modify XML documents\n- [Array Manipulation](examples/arrays/) - Working with arrays\n- [Query Filters](examples/filters/) - Filter elements by conditions\n- [Result Modifiers](examples/modifiers/) - Transform query results\n- [Custom Modifiers](examples/custom-modifiers/) - Build custom transformations\n- [Namespace Support](examples/namespaces/) - Work with XML namespaces\n- [Performance](examples/performance/) - Optimize for speed\n\n### Real-World Examples\n\n- [RSS Parser](examples/real-world/rss-parser/) - Parse RSS/Atom feeds\n- [Config Files](examples/real-world/config-files/) - Manage XML config files\n- [SOAP Client](examples/real-world/soap-client/) - Build SOAP clients\n\n### API Documentation\n\nFull API reference available at [GoDoc](https://godoc.org/github.com/netascode/xmldot).\n\n## Contributing\n\nWe welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Acknowledgments\n\nInspired by the excellent [gjson](https://github.com/tidwall/gjson) and [sjson](https://github.com/tidwall/sjson) libraries for JSON.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetascode%2Fxmldot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnetascode%2Fxmldot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetascode%2Fxmldot/lists"}