antchfx/xpath is a dependency-free XPath engine for Go
A pure-Go basic XPath evaluator that queries any tree through the NodeNavigator interface, with no external dependencies.
What this is
antchfx/xpath is an XPath expression engine written entirely in Go. It does not parse XML or HTML itself; instead it walks whatever document you hand it through the NodeNavigator interface, which describes a cursor that can move around a tree: to children, parents, siblings and attributes, reporting each node's type, name and value.
That separation is the whole design. The package provides the XPath machinery — parsing expressions, evaluating predicates, resolving axes and functions — while companion packages provide XPath querying for real document formats:
htmlquery— an XPath query package for HTML documentsxmlquery— an XPath query package for XML documentsjsonquery— an XPath query package for JSON documents
Because the only contract is the NodeNavigator interface, you can also write your own navigator over any in-memory structure. The repository's doc_test.go does exactly that: it defines a small linked-list node type and a NodeNavigator implementation, then runs XPath expressions against it.
What it supports
The README is explicit about scope: the basic XPath patterns "cover 90% of the cases that most stylesheets will need." That includes element selection (node, *), attributes (@attr, @*), node kinds (text(), comment()), parent and child traversal (., .., /), predicates (a[expr], positional a[n]), descendant paths (//b, a//b) and the union operator (a|b).
The README documents the node axes, including child, descendant, attribute, following-sibling, preceding-sibling, following, preceding, ancestor, self, parent, and the descendant-or-self and ancestor-or-self variants.
Expressions evaluate to one of three types — number, boolean or string — plus a node set. Comparisons (=, !=, <, <=, >, >=), arithmetic (+, -, *, div, mod) and boolean logic (and, or) are supported.
The function table is broad but honest about gaps. Most of the listed functions are marked ✓: count(), position(), last(), contains(), starts-with(), string-length(), substring(), translate(), normalize-space(), sum() and others. A handful of XPath 2.0 additions appear too, like lower-case() and string-join(). Unsupported functions — document(), id(), key(), current(), choose() among them — are listed with a ✗ rather than silently half-implemented.
The public API
The surface is small. You compile an expression once, then reuse it:
expr, err := xpath.Compile("count(//book)")
if err != nil {
panic(err)
}
val := expr.Evaluate(root) // returns float64
Three constructors are exported from xpath.go:
Compile(expr string)— parses and builds the query tree, returning an error on invalid expressions.MustCompile(expr string)— same but panics-free; on failure it returns an expression backed by a no-op query that matches nothing.CompileWithNS(expr string, namespaces map[string]string)— compiles with a namespace prefix mapping.
A compiled *Expr offers two evaluation paths. Evaluate(root NodeNavigator) interface{} returns the raw result type: bool, float64, string, or a NodeIterator. Select(root NodeNavigator) *NodeIterator always returns an iterator you walk with MoveNext() and read with Current(), which is how node-set queries are meant to be consumed:
expr = xpath.MustCompile("//book")
iter := expr.Select(root)
for iter.MoveNext() {
fmt.Println(iter.Current().Value())
}
There is also a package-level Select(root, expr) convenience function that compiles and selects in one call; the docs mark it deprecated in favor of compiling once with Expr.Select().
How it works inside
The engine is split across files by responsibility. parse.go holds the tokenizer — an item type for every lexical element from / and @ through quoted strings, numbers and axes like child::. It builds a parse tree whose node types mirror XPath grammar constructs.
build.go turns that parse tree into executable query objects. The builder tracks properties such as PosFilter, HasPosition, and NonFlat.
query.go defines the core interfaces: query (with Select, Evaluate, Clone, ValueType, Properties) and the result-type constants. Queries are cloned for each NodeIterator, so a compiled expression can be reused to create separate iterators.
The package deliberately keeps zero external dependencies, which shows in two places. A small capacity-resetting loading cache in cache.go (defaultCap = 65536) memoizes compiled regexes; when the cap is hit it simply resets rather than implementing an LRU, a trade-off documented at length in the source comment as preferable to pulling in something like hashicorp/golang-lru. And the string builder used by func.go is selected by build tags: strings.Builder on Go 1.10 and later (func_go110.go), falling back to bytes.Buffer for older toolchains (func_pre_go110.go).
Getting started
The module declares go 1.14, so it works with modern toolchains, though the build-tag split shows its roots in supporting much older Go versions.
go get github.com/antchfx/xpath
Because xpath itself has no built-in document parser, you can use it through a companion package or directly with a custom NodeNavigator:
- For HTML:
github.com/antchfx/htmlquery - For XML:
github.com/antchfx/xmlquery - For JSON:
github.com/antchfx/jsonquery
Those packages are listed in the README as XPath query packages for HTML, XML, and JSON. If your data lives in a custom structure, implement NodeNavigator yourself — the interface is thirteen methods (MoveToChild, MoveToParent, MoveToNextAttribute, Copy, Value, and so on), and doc_test.go shows a complete working example over an in-memory tree.
Who it's for
This is a library, not an application. It suits Go developers who need XPath-style selection over structured data without the weight of a full XML stack or a browser engine, and who value having no transitive dependencies to audit. The companion packages cover HTML, XML, and JSON querying.
The trade-off is scope: this is basic XPath with a few XPath 2.0 functions, not the full modern spec. If you need document(), id(), or advanced functions like format-number(), check the README's function table first — those are explicitly out of range.
antchfx/xpath: 255 KB in 26 files, indexed Nov 13, 2026 after 0.00 hours of indexing. License: MIT. Source: https://github.com/antchfx/xpath.
Ask your agent to name it in its tool calls (the repo argument of query_graph, recall_project and read_project_source).
Written by AI models on the operator's own hardware, checked by a second model, from the repository's README and its code. Back to the shelf