Chapter 53: XPath Axes
What are XPath Axes? (5-minute honest explanation)
Axes are the directions you can move in the XML tree.
Normally XPath only goes down (child):
/library/book/titleBut with axes you can also go:
- up (parent, ancestor)
- sideways (siblings)
- diagonally (following/preceding nodes)
- even stay where you are + go down (descendant-or-self)
Analogy everyone understands
Imagine the XML document is a family tree drawn on a big wall.
- /library/book = “go down to children”
- parent:: = “go up to mom/dad”
- following-sibling:: = “go right to brothers/sisters after you”
- ancestor:: = “go up to grandparents, great-grandparents…”
- descendant:: = “go down to all children, grandchildren…”
- .// = “stay here and look at all your descendants”
Very important fact
Most people only ever use 4–5 axes in real life:
- child:: (default – you almost never write it)
- descendant:: (written as //)
- parent:: (written as ..)
- following-sibling::
- preceding-sibling::
The others are rare — but very powerful when you need them.
Lesson 1 – The full list of XPath axes (with visuals)
Here is the complete list of all 13 axes.
We will mark the most useful ones with ★ and the rare/advanced ones with ⚠.
| Axis name | Shortcut | Direction / Scope | Example XPath | What it selects (from <price> node) | Use frequency |
|---|---|---|---|---|---|
| child | (default) | direct children | child::author or just author | direct <author> child | ★ Very high |
| descendant | // | all descendants (children + grandchildren…) | descendant::title or //title | all <title> anywhere below current node | ★ Very high |
| descendant-or-self | .// | current node + all descendants | .//price | current node + all prices below | ★ Very high |
| parent | .. | parent node | parent::book or .. | the <book> parent | ★ Very high |
| ancestor | ancestor:: | all ancestors (parent, grandparent…) | ancestor::library | the <library> ancestor | ★ High |
| ancestor-or-self | ancestor-or-self:: | current + all ancestors | ancestor-or-self::book | current node + all book ancestors | Medium |
| following-sibling | following-sibling:: | siblings after current node | following-sibling::author | <author> that comes after current node | ★ High |
| preceding-sibling | preceding-sibling:: | siblings before current node | preceding-sibling::title | <title> that comes before current node | ★ High |
| following | following:: | all nodes after current (not ancestors) | following::price | all <price> that appear after current node | Medium |
| preceding | preceding:: | all nodes before current (not ancestors) | preceding::title | all <title> that appear before current node | Medium |
| self | . | current node itself | self::book or . | the current node (if it is book) | ★ High |
| attribute | @ | attributes of current element | @id or attribute::id | id attribute of current element | ★ Very high |
| namespace | namespace:: | namespace declarations | namespace::xsl | Very rare – only in XSLT/XQuery | Almost never |
Lesson 2 – Visual tree + navigation examples
Let’s take this XML and number the nodes:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<library> ← 1 <book id="101"> ← 2 <title>Atomic Habits</title> ← 3 <author>James Clear</author> ← 4 <price currency="INR">499</price> ← 5 </book> <book id="102"> ← 6 <title>Rich Dad Poor Dad</title> ← 7 </book> </library> |
Now let’s stand on node 5 (<price>), and see where axes take us:
- child::* → nothing (price has no children)
- descendant::* → nothing
- parent::* → node 2 (<book id=”101″>)
- ancestor::* → node 2 + node 1 (<library>)
- following-sibling::* → nothing (price is last child)
- preceding-sibling::* → node 3 (<title>) + node 4 (<author>)
- following::* → node 6 (<book id=”102″>) + node 7 (<title> inside it)
- preceding::* → node 3 (<title>) + node 4 (<author>)
- self::* → node 5 itself
- attribute::* → currency=”INR”
Lesson 3 – Most useful axes in real life (with examples)
1. parent:: (go up one level) ★★★★★
//price/parent::book/@id→ id of every book that contains a price
//price/parent::*[1]→ the direct parent element of every price
2. ancestor:: (go up multiple levels) ★★★★
//price/ancestor::library/@owner→ “Alice” (owner attribute of <library>)
//price/ancestor::*[2]→ the grandparent of price (usually <library>)
3. following-sibling:: and preceding-sibling:: ★★★★★
Very common when order matters.
//title/following-sibling::author→ the <author> that comes after each <title>
//author/preceding-sibling::title→ the <title> that comes before each <author>
Real use case: “get the price that comes right after the title”
//title/following-sibling::price4. following:: and preceding:: (dangerous but powerful) ★★
These select everything after/before — not just siblings.
//title/following::price→ all prices that appear anywhere after this title → can jump across books!
Warning: following:: and preceding:: are very expensive in large documents — avoid when possible.
Lesson 4 – Try yourself exercises (do these!)
- Select all authors that come after a <title>
- Select the book that contains a price in USD
- Select the owner attribute of the library that contains a book from 2018
- Select the second price in the document
- Select all titles that are followed by an author
- Select the book that comes right after the first book
- Select the price that is the last child of its book
Lesson 5 – Real-world context (where axes are really used)
- Web scraping → //div[@class=”product”]//price/parent::div
- XSLT → <xsl:apply-templates select=”following-sibling::node()”/>
- SOAP / web services → //soap:Body//ns:Amount/parent::ns:Transaction
- Automated testing → //button[text()=”Submit”]/preceding-sibling::input
- e-Invoice / EDI → //cac:TaxTotal/cbc:TaxAmount/ancestor::Invoice/cbc:ID
- Browser DevTools → $x(“//input[@type=’text’]/following-sibling::button”)
Would you like to continue with one of these next?
- Very deep dive into following/preceding (when to use vs when to avoid)
- ancestor:: vs parent:: – real cases where ancestor saves you
- following-sibling:: vs following:: – huge performance difference
- XPath with namespaces (very common in SOAP, UBL, Android manifest…)
- XPath functions that work well with axes (position(), count(), last())
- Real-world examples — RSS feed, SOAP envelope, e-invoice, configuration file
Just tell me which direction feels most useful or interesting for you right now! 😊
