Location paths and axes
The XPath data model, absolute and relative paths, the axes you will actually use, and node tests that select the right node type.
The data model behind a path
XPath addresses an XML document as a tree of nodes. An expression is evaluated against a context node, and the result is a node-set (XPath 2.0 and later may also return sequences of atomic values).
- The document node sits above the root element and is selected by
/at the start of a path. - There are seven node types: document, element, attribute, text, comment, processing instruction and namespace.
/alone is the root step;/catalog/bookselectsbookchildren of the root element.//is shorthand for/descendant-or-self::node()/, so//bookmeans any book at any depth.- A relative path starts with no slash and is evaluated from the current context node — the usual case inside an XSLT template.
<catalog>
<book id="bk-101"><title>Alpha</title><price>39.95</price></book>
<book id="bk-102"><title>Beta</title><price>12.00</price></book>
</catalog>Axes worth knowing
| Axis | Direction | Abbreviation | Use it for |
|---|---|---|---|
child | Down the tree | none (default) | The normal traversal step |
descendant | Down, any depth | none | Finding something anywhere below |
descendant-or-self | Down plus current | // | The shorthand behind // |
parent | One level up | .. | Climbing out of the current element |
ancestor | All levels up | none | Locating the enclosing section |
following-sibling | Forward, same level | none | The next row or item |
attribute | Into the tag | @ | Attribute values |
self | Current node | . | Keeping the current node in a step chain |
/catalog/book absolute: books that are children of the root
//book/title any title element anywhere
catalog/book/@id attribute axis, abbreviated with @
//book[1] first book child of each parent
(//book)[1] the first book in the document - note the brackets
//book/ancestor::catalog the catalog that encloses each book
//title/following-sibling::price the price that comes right after a title
//book[@id = 'bk-102']/title/text() the text node of a matching title
//comment() every comment node💡
Prefer explicit axes over deep
// expressions. A path that descends from a known element survives document changes; //price keeps working right up until a second price element appears somewhere else.Node tests and multiple results
| Test | Selects |
|---|---|
book | Elements named book |
* | Any element |
node() | Any node at all, including text and comments |
text() | Text nodes only |
@* | All attributes |
comment() | Comment nodes |
processing-instruction('xml-stylesheet') | A named processing instruction |
# try expressions from the command line before putting them in code
xmllint --xpath 'count(//book)' catalog.xml; echo
xmllint --xpath 'string(//book[1]/title)' catalog.xml; echo
xmllint --xpath '//book/@id' catalog.xml; echoBecause a node-set keeps document order, string() applied to several matches returns the first value. That is convenient for logging and dangerous for correctness — count the matches before trusting one.
FAQ
Why does <code>//book[1]</code> return several nodes?
The predicate is applied per parent, so it selects the first book child of each parent. Wrap the whole expression in parentheses —
(//book)[1] — to take the first match in the document.Does XPath select the document as text?
No. XPath returns nodes or atomic values; you then take
string(), text() or a serializer to get characters out.Related
Predicates and functions Namespaces
Last refreshed 2026-09-18.