Xmldot
High-performance Go library for querying and manipulating XML using GJSON-inspired path syntax. Zero dependencies, blazing fast, security-first design.
Install / Use
/learn @netascode/XmldotREADME
XMLDOT is a Go package that provides a fast and simple way to get and set values in XML documents. It has features such as dot notation paths, wildcards, filters, modifiers, and array operations.
Inspired by GJSON and SJSON for JSON.
Getting Started
Installing
To start using XMLDOT, install Go and run go get:
$ go get -u github.com/netascode/xmldot
This will retrieve the library.
Try It Online
Experiment with XMLDOT in your browser without installing anything. The playground lets you:
- Test path queries against sample or custom XML
- Explore filters, wildcards, and modifiers
- See results in real-time
- Learn the syntax interactively
Perfect for learning or prototyping queries before using in code.
Get a value
Get 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.
package main
import "github.com/netascode/xmldot"
const xml = `
<catalog>
<book id="1">
<title>The Go Programming Language</title>
<author>Alan Donovan</author>
<price>44.99</price>
</book>
</catalog>`
func main() {
title := xmldot.Get(xml, "catalog.book.title")
println(title.String())
}
This will print:
The Go Programming Language
Fluent API
The fluent API enables method chaining on Result objects for cleaner, more readable code:
// Basic fluent chaining
root := xmldot.Get(xml, "root")
name := root.Get("user.name").String()
age := root.Get("user.age").Int()
// Deep chaining
fullPath := xmldot.Get(xml, "root").
Get("company").
Get("department").
Get("team.member").
Get("name").
String()
// Batch queries
user := xmldot.Get(xml, "root.user")
results := user.GetMany("name", "age", "email")
name := results[0].String()
age := results[1].Int()
email := results[2].String()
// Case-insensitive queries
opts := &xmldot.Options{CaseSensitive: false}
name := root.GetWithOptions("USER.NAME", opts).String()
// Structure inspection with Map()
user := xmldot.Get(xml, "root.user")
m := user.Map()
name := m["name"].String()
age := m["age"].Int()
// Iterate over all child elements
for key, value := range m {
fmt.Printf("%s = %s\n", key, value.String())
}
// Map() with case-insensitive keys
m := user.MapWithOptions(&xmldot.Options{CaseSensitive: false})
Performance: Fluent chaining adds ~280% overhead for 3-level chains compared to full paths. For performance-critical code, use direct paths:
// Fast (recommended for hot paths)
name := xmldot.Get(xml, "root.user.name")
// Readable (recommended for business logic)
user := xmldot.Get(xml, "root.user")
name := user.Get("name")
Array Handling: Field extraction on arrays requires explicit #.field syntax:
items := xmldot.Get(xml, "catalog.items")
// Extract all prices
prices := items.Get("item.#.price") // Array of all prices
Set a value
Set modifies an XML value for the specified path. A path is in dot syntax, such as "book.title" or "book.@id".
package main
import "github.com/netascode/xmldot"
const xml = `
<catalog>
<book id="1">
<title>The Go Programming Language</title>
<price>44.99</price>
</book>
</catalog>`
func main() {
value, _ := xmldot.Set(xml, "catalog.book.price", 39.99)
println(value)
}
This will print:
<catalog><book id="1"><title>The Go Programming Language</title><price>39.99</price></book></catalog>
Creating Elements with Attributes
Set automatically creates missing parent elements when setting attributes. This makes it easy to add attributes to elements that don't yet exist:
xml := `<root></root>`
// Automatically creates <user> element with id attribute
result, _ := xmldot.Set(xml, "root.user.@id", "123")
// Result: <root><user id="123"></user></root>
// Works with deep paths too
result, _ = xmldot.Set(xml, "root.company.department.@name", "Engineering")
// Result: <root><company><department name="Engineering"></department></company></root>
Path Syntax
A path is a series of keys separated by a dot. The dot character can be escaped with \.
<catalog>
<book id="1">
<title>The Go Programming Language</title>
<author>Alan Donovan</author>
<price>44.99</price>
<tags>
<tag>programming</tag>
<tag>go</tag>
</tags>
</book>
<book id="2">
<title>Learning Go</title>
<author>Jon Bodner</author>
<price>39.99</price>
</book>
</catalog>
catalog.book.title >> "The Go Programming Language"
catalog.book.@id >> "1"
catalog.book.price >> "44.99"
catalog.book.1.title >> "Learning Go"
catalog.book.# >> 2
catalog.book.tags.tag.0 >> "programming"
catalog.book.title.% >> "The Go Programming Language"
Arrays
Array elements are accessed by index:
catalog.book.0.title >> "The Go Programming Language" (first book)
catalog.book.1.title >> "Learning Go" (second book)
catalog.book.# >> 2 (count of books)
catalog.book.tags.tag.# >> 2 (count of tags)
Append new elements using index -1 with Set() or SetRaw():
xml := `<catalog><book><title>Book 1</title></book></catalog>`
// Append a new book using SetRaw for XML content
result, _ := xmldot.SetRaw(xml, "catalog.book.-1", "<title>Book 2</title>")
count := xmldot.Get(result, "catalog.book.#")
// count.Int() → 2
// Works with empty arrays too
xml2 := `<catalog></catalog>`
result2, _ := xmldot.SetRaw(xml2, "catalog.book.-1", "<title>First Book</title>")
// Result: <catalog><book><title>First Book</title></book></catalog>
Attributes
Attributes are accessed with the @ prefix:
catalog.book.@id >> "1"
catalog.book.0.@id >> "1"
catalog.book.1.@id >> "2"
Text Content
Text content (ignoring child elements) uses the % operator:
catalog.book.title.% >> "The Go Programming Language"
Wildcards
Single-level wildcards * match any element at that level. Recursive wildcards ** match elements at any depth:
<catalog>
<book id="1">
<title>The Go Programming Language</title>
<price>44.99</price>
</book>
<book id="2">
<title>Learning Go</title>
<price>39.99</price>
</book>
</catalog>
catalog.*.title >> ["The Go Programming Language", "Learning Go"]
catalog.book.*.% >> ["The Go Programming Language", "Alan Donovan", "44.99", ...]
catalog.**.price >> ["44.99", "39.99"] (all prices at any depth)
Filters
You can filter elements using GJSON-style query syntax. Supports ==, !=, <, >, <=, >=, %, !% operators:
<catalog>
<book status="active">
<title>The Go Programming Language</title>
<price>44.99</price>
</book>
<book status="active">
<title>Learning Go</title>
<price>39.99</price>
</book>
<book status="discontinued">
<title>Old Book</title>
<price>19.99</price>
</book>
</catalog>
catalog.book.#(price>40).title >> "The Go Programming Language"
catalog.book.#(@status==active)#.title >> ["The Go...", "Learning Go"]
catalog.book.#(price<30).#(@status==active) >> [] (no matches)
catalog.book.#(title%"*Go*")#.title >> ["The Go...", "Learning Go"] (pattern match)
Modifiers
Modifiers transform query results using the | operator:
catalog.book.title|@reverse >> ["Learning Go", "The Go..."]
catalog.book.price|@sort >> ["39.99", "44.99"]
catalog.book.title|@first >> "The Go Programming Language"
catalog.book.title|@last >> "Learning Go"
catalog.book|@pretty >> formatted XML
Built-in modifiers
@reverse: Reverse array order@sort: Sort array elements@first: Get first element@last: Get last element@keys: Get element names@values: Get element values@flatten: Flatten nested arrays@pretty: Format XML with indentation@ugly: Remove all whitespace@raw: Get raw XML without parsing
Custom modifiers
You can add your own modifiers:
xmldot.AddModifier("uppercase", func(xml, arg string) string {
return strings.ToUpper(xml)
})
result := xmldot.Get(xml, "c
Related Skills
xurl
352.0kA CLI tool for making authenticated requests to the X (Twitter) API. Use this skill when you need to post tweets, reply, quote, search, read posts, manage followers, send DMs, upload media, or interact with any X API v2 endpoint.
clearshot
Structured screenshot analysis for UI implementation and critique. Analyzes every UI screenshot with a 5×5 spatial grid, full element inventory, and design system extraction — facts and taste together, every time. Escalates to full implementation blueprint when building. Trigger on any digital interface image file (png, jpg, gif, webp — websites, apps, dashboards, mockups, wireframes) or commands like 'analyse this screenshot,' 'rebuild this,' 'match this design,' 'clone this.' Skip for non-UI images (photos, memes, charts) unless the user explicitly wants to build a UI from them. Does NOT trigger on HTML source code, CSS, SVGs, or any code pasted as text.
openpencil
2.1kThe world's first open-source AI-native vector design tool and the first to feature concurrent Agent Teams. Design-as-Code. Turn prompts into UI directly on the live canvas. A modern alternative to Pencil.
wanwu
4.3kChina Unicom's Yuanjing Wanwu Agent Platform is an enterprise-grade, multi-tenant AI agent development platform. It helps users build applications such as intelligent agents, workflows, and rag, and also supports model management. The platform features a developer-friendly license, and we welcome all developers to build upon the platform.
