SyntaxStudy
Sign Up
XML XPath Axes and Node Tests
XML Beginner 1 min read

XPath Axes and Node Tests

XPath defines thirteen axes that describe directions of travel through the document tree. The most commonly used are: child (direct children), parent (immediate parent), ancestor (all ancestors up to root), descendant (all descendants), ancestor-or-self, descendant-or-self, following-sibling (same parent, after), preceding-sibling (same parent, before), following (anything in document order after the context node's end tag), preceding, attribute, namespace, and self. Node tests follow the axis and narrow the selection. A name test like book selects elements with that local name. The wildcard * selects any element node. text() selects text nodes, comment() selects comment nodes, processing-instruction() selects PIs, and node() selects any node regardless of type. When working with namespaced documents you must either use a prefix registered in the evaluation context or use local-name() and namespace-uri() functions in a predicate. Predicates add conditional filtering to any step. A predicate is an expression in square brackets evaluated for each candidate node; if it results in a number it is treated as a position test (selecting the nth node), otherwise it is treated as a boolean. Multiple predicates can be chained — they are applied left to right — and predicates can themselves contain location paths, making XPath a surprisingly expressive query language for tree-structured data.
Example
<!--
    XPath Axis Examples
    (using the library document from the previous lesson)
-->

<!--
    CHILD AXIS (default):
    child::book          = book
    child::*             = * (all element children)
    child::text()        = text node children

    DESCENDANT AXIS:
    descendant::title    = all <title> at any depth
    //title              = abbreviated form

    PARENT AXIS:
    ..                   = abbreviated parent::node()
    parent::library      = parent if it is <library>

    ANCESTOR AXIS:
    ancestor::*          = all ancestor elements

    SIBLING AXES:
    following-sibling::book         = next <book> siblings
    preceding-sibling::book[1]      = the nearest preceding <book>

    ATTRIBUTE AXIS:
    @id                  = attribute::id
    @*                   = all attributes

    SELF AXIS:
    .                    = self::node()
    self::book           = true only if context node is <book>

    Combined step examples:
    /library/book/following-sibling::magazine   → m001
    //book[@id='b001']/following-sibling::*     → b002, m001
    //title/parent::book/@id                    → b001, b002
    //book[author='Robert C. Martin']/@category → non-fiction

    Namespace-aware:
    //*[local-name()='subject']             → dc:subject element
    //*[namespace-uri()='http://purl.org/dc/elements/1.1/']
                                            → dc:subject
-->