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/book selects book children of the root element.
  • // is shorthand for /descendant-or-self::node()/, so //book means 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

AxisDirectionAbbreviationUse it for
childDown the treenone (default)The normal traversal step
descendantDown, any depthnoneFinding something anywhere below
descendant-or-selfDown plus current//The shorthand behind //
parentOne level up..Climbing out of the current element
ancestorAll levels upnoneLocating the enclosing section
following-siblingForward, same levelnoneThe next row or item
attributeInto the tag@Attribute values
selfCurrent 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

TestSelects
bookElements 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; echo

Because 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.

Predicates and functions Namespaces

Last refreshed 2026-09-18.