XML Tutorial · XPath, XSLT and XQuery · Lesson 13 of 28
XPath Axes and Functions
Axes such as ancestor and following-sibling, string and number functions, position(), and what XPath 2.0 and 3.1 add.
Axes
A step can move in any direction from the current node with an axis: axis::node-test[predicate].
| Axis | Direction |
|---|---|
child:: (default), attribute:: (@) |
down one level, attributes |
descendant::, descendant-or-self:: (//) |
everything below |
parent:: (..), ancestor:: |
up |
following-sibling::, preceding-sibling:: |
sideways, same parent |
following::, preceding:: |
after / before in document order |
self:: (.) |
the node itself |
Functions
- Strings:
concat(),contains(),starts-with(),substring(),substring-before(),string-length(),normalize-space(),translate()(XPath 1.0's way to change case). - Numbers:
sum(),count(),round(),floor(),ceiling(),number(). - Nodes:
position(),last(),name(),local-name(),namespace-uri(),not().
from lxml import etree
shop = etree.fromstring(b"""<shop>
<product sku="TEA-01" category="drinks"><name>Green tea</name><price>3.50</price><stock>40</stock></product>
<product sku="COF-02" category="drinks"><name>Coffee beans</name><price>9.90</price><stock>0</stock></product>
<product sku="MUG-07" category="kitchen"><name>Camel mug</name><price>12.00</price><stock>15</stock></product>
<product sku="PAN-03" category="kitchen"><name>Frying pan</name><price>29.00</price><stock>4</stock></product>
</shop>""")
q = shop.xpath
print(q("//name[.='Camel mug']/../@category")[0]) # parent, then attribute
print(q("//product[@sku='MUG-07']/following-sibling::product/@sku")) # siblings after
print(q("//price[. > 20]/ancestor::product/name/text()")) # up to the product
print(q("//product[contains(name, 'tea') or starts-with(@sku, 'COF')]/@sku"))
print(q("translate(string(//product[1]/name), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"))
print(q("concat(count(//product[stock > 0]), ' of ', count(//product), ' in stock')"))
print(q("//product[position() <= 2]/@sku"))
Output
kitchen ['PAN-03'] ['Frying pan'] ['TEA-01', 'COF-02'] GREEN TEA 3 of 4 in stock ['TEA-01', 'COF-02']
XPath 2.0 and 3.1
Later versions (supported by Saxon, not by libxml2, browsers or the JDK's built-in engine) add typed sequences,
if … then … else, for … return, regular expressions (matches(), replace()), dates, string-join(),
and in 3.1 maps, arrays and JSON. In Python you can use elementpath or saxonche for XPath 3.1; the
XQuery page shows the newer syntax.
Test yourself
Which axis selects elements that come after the current node and share its parent?
following-sibling::following::descendant::ancestor::
Show answer
Answer: following-sibling::
following:: includes everything later in the document; following-sibling:: only the same parent's children.