XPath Axes

An axis defines the direction of navigation from the current node in an XPath expression. The default direction is downward — selecting children. But XPath supports 13 axes that let you navigate in every direction through the tree: up to ancestors, sideways to siblings, forward to following nodes, and backward to preceding ones.

Think of axes like compass directions on a map. You stand at a specific location (the context node) and the axis tells you which direction to look — north, south, east, west — to find the nodes you want.

The 13 XPath Axes

Axis NameDirection / Nodes Selected
childDirect children of the context node
parentThe single parent of the context node
selfThe context node itself
ancestorParent, grandparent, and all ancestors up to root
ancestor-or-selfThe context node plus all its ancestors
descendantAll children, grandchildren, and all below
descendant-or-selfThe context node plus all its descendants
following-siblingAll siblings that come after the context node
preceding-siblingAll siblings that come before the context node
followingAll nodes in the document after the context node's closing tag
precedingAll nodes in the document before the context node's opening tag
attributeAll attributes of the context node
namespaceAll namespace nodes of the context node

Axis Syntax

axis-name::node-test[predicate]

Working XML for Examples

<company>
  <department id="D1" name="Engineering">
    <team>Backend</team>
    <team>Frontend</team>
    <employee>
      <name>Ravi Kumar</name>
      <role>Developer</role>
    </employee>
  </department>
  <department id="D2" name="HR">
    <employee>
      <name>Sunita Rao</name>
      <role>Manager</role>
    </employee>
  </department>
</company>

Axis Navigation Diagram

                   ancestor
                      ↑
    preceding         |          following
    ←←←←←  [context node: employee]  →→→→→
                      |
                   descendant
                      ↓

    preceding-sibling ← [context: employee] → following-sibling
                     (same parent level)

child Axis

Selects direct children only. This is the default axis.

child::department        → same as: department
child::*                 → all child elements
child::text()            → all text node children
child::employee          → all employee children
/company/child::department  → both department elements

parent Axis

Selects the single parent node. Useful when you start at a deep node and need to go up one level.

/company/department/employee/parent::department
    → the department element that contains the employee

/company/department/team/parent::*
    → any parent element of team (the department)

ancestor Axis

Selects all ancestors — parent, grandparent, and above — up to and including the root.

/company/department/employee/name/ancestor::*
    → name, employee, department, company (all ancestors)

/company/department/employee/ancestor::department
    → the department ancestor of employee

/company/department/employee/ancestor::company
    → the company ancestor

descendant Axis

Selects all descendants at any depth below the context node.

/company/descendant::name
    → all name elements anywhere inside company

/company/department[1]/descendant::*
    → all elements inside the first department

/company/descendant::text()
    → all text content in the entire document

following-sibling and preceding-sibling Axes

Siblings share the same parent. These axes navigate sideways.

Assume context is the first <team> (Backend):

following-sibling::team
    → the Frontend team (comes after Backend)

following-sibling::employee
    → the employee element (comes after both teams)

preceding-sibling::*
    → all sibling elements before the current node

following and preceding Axes

These axes cover all nodes in document order after or before the context node — not just siblings, but nodes in completely different branches of the tree.

/company/department[1]/following::*
    → every element after the first department closes:
      department[D2], employee[Sunita], name, role

/company/department[2]/preceding::*
    → every element before the second department opens:
      department[D1], team[Backend], team[Frontend], employee[Ravi], name, role

attribute Axis

Selects the attributes of the context node. The @ shorthand is an abbreviation for attribute::.

/company/department/attribute::*        → all attributes of all departments
/company/department/attribute::id       → the id attribute
/company/department/attribute::name     → the name attribute

Abbreviated:
/company/department/@*
/company/department/@id

self Axis

Selects the context node itself. Useful in predicates to test the current node's own properties.

self::department     → the context node if it is a department, otherwise nothing
self::*              → the context node regardless of name
self::node()         → same as self::*

Use case in a predicate:
//department[self::*[@id='D1']]
    → department that is itself named with id D1

Axis Examples in XSLT

<!-- Get the parent department name when processing an employee -->
<xsl:template match="employee">
  <p>Department: <xsl:value-of select="parent::department/@name"/></p>
  <p>Employee: <xsl:value-of select="name"/></p>
</xsl:template>

<!-- Count all following siblings -->
<xsl:value-of select="count(following-sibling::employee)"/>

<!-- List all ancestor element names -->
<xsl:for-each select="ancestor::*">
  <p><xsl:value-of select="name()"/></p>
</xsl:for-each>

Key Points to Remember

  • Axes define the direction of navigation from the current context node.
  • child:: is the default axis — writing book is the same as child::book.
  • ancestor:: goes up the tree; descendant:: goes down.
  • following-sibling:: and preceding-sibling:: move sideways among shared-parent nodes.
  • following:: and preceding:: cover all nodes in document order before or after the context node.
  • attribute:: selects attributes — abbreviated as @.
  • self:: selects the context node itself — useful in predicates and filtering.

Leave a Comment

Your email address will not be published. Required fields are marked *