XPath Selectors for XML Guide
XPath is the query language for navigating XML and HTML documents. It provides a concise syntax for selecting nodes, filtering by conditions, and extracting values — capabilities that make it indispensable for XML processing, web scraping, test automation, and XSLT transformations. This guide covers the core XPath syntax with practical examples you can apply immediately.
Core Path Expressions
XPath uses path notation similar to filesystem paths, with / separating steps from the root and // selecting anywhere in the document.
| Expression | Meaning |
|---|---|
/catalog | Root element catalog |
/catalog/book | All book children of catalog |
//book | All book elements anywhere in the document |
/catalog/book/title | All title elements under book |
//book/title/text() | Text content of all book titles |
Example Document
<catalog>
<book id="1" category="programming">
<title>XML Basics</title>
<author>Jane Doe</author>
<price>29.99</price>
</book>
<book id="2" category="design">
<title>Design Patterns</title>
<author>John Smith</author>
<price>39.99</price>
</book>
<book id="3" category="programming">
<title>Advanced XPath</title>
<author>Jane Doe</author>
<price>34.99</price>
</book>
</catalog>
Predicates — Filtering Nodes
Predicates are enclosed in square brackets [] and filter nodes by position, attribute, or child content.
By Position
| XPath | Result |
|---|---|
/catalog/book[1] | First book |
/catalog/book[last()] | Last book |
/catalog/book[position() < 3] | First two books |
By Attribute
| XPath | Result |
|---|---|
//book[@id='2'] | Book with id="2" |
//book[@category='programming'] | All programming books |
//book[@id] | All books that have an id attribute |
By Child Content
| XPath | Result |
|---|---|
//book[author='Jane Doe'] | Books by Jane Doe |
//book[price > 30] | Books priced above 30 |
//book[contains(title, 'XML')] | Books with "XML" in title |
Axes — Navigating Relationships
Axes specify the direction of navigation relative to the context node.
| Axis | Direction | Example |
|---|---|---|
child | Children (default) | child::book ≡ book |
parent | Parent node | parent::* ≡ .. |
ancestor | All ancestors up to root | ancestor::catalog |
descendant | All descendants at any depth | descendant::title |
following-sibling | Subsequent siblings | title/following-sibling::* |
preceding-sibling | Previous siblings | price/preceding-sibling::* |
self | The context node itself | self::book ≡ . |
Practical Axis Examples
<!-- All titles after the first book's title in document order -->
/catalog/book[1]/title/following-sibling::*
<!-- Price of the book titled "XML Basics" -->
//book[title='XML Basics']/price
<!-- All books that share an author with the first book -->
//book[author = /catalog/book[1]/author]
Functions XPath Provides
XPath includes built-in functions for string manipulation, numeric operations, and boolean logic.
| Function | Purpose | Example |
|---|---|---|
text() | Select text nodes | //title/text() |
contains() | Substring check | //book[contains(title, 'XML')] |
starts-with() | Prefix check | //book[starts-with(@id, '1')] |
string-length() | Character count | //title[string-length() > 10] |
normalize-space() | Trim whitespace | normalize-space(title) |
number() | Convert to number | //book[number(price) > 30] |
count() | Count node set | count(//book) |
concat() | Join strings | concat(title, ' by ', author) |
name() | Node name | name(//book/*) |
XPath for HTML and Web Scraping
Modern browsers support XPath on HTML via document.evaluate(). This is particularly useful for web scraping and test automation when CSS selectors are insufficient.
// Select the first <h2> inside an element with class "article"
const result = document.evaluate(
'//div[@class="article"]//h2[1]',
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
);
const heading = result.singleNodeValue;
When XPath Beats CSS Selectors
| Task | CSS Selector | XPath |
|---|---|---|
| Select by text content | Not possible | //a[contains(., 'Login')] |
| Select parent from child | Not possible | //a[@href="/login"]/.. |
| Select by partial attribute | [attr*="val"] | [contains(@attr, 'val')] |
| Select previous sibling | Not possible | preceding-sibling::div[1] |
| Select nth-from-last | Limited support | div[last()-1] |
Namespaces and XPath
When querying XML that uses namespaces, you must register namespace prefixes — even if the source document uses a default namespace:
from lxml import etree
tree = etree.parse('catalog.xml')
ns = {'bk': 'http://example.com/book'}
# This works:
titles = tree.xpath('//bk:title', namespaces=ns)
# This returns nothing:
titles = tree.xpath('//title') # matches name in no namespace
Key Takeaways
/navigates from root;//selects anywhere in the document hierarchy.- Predicates in
[]filter by position, attribute values, or child element content. - Axes like
following-siblingandparentenable navigation CSS selectors cannot do. - Built-in functions handle string matching, numeric comparison, and node counting.
- For namespace-aware XML, always register prefixes and use them in your XPath expressions.
- XPath excels over CSS selectors for selecting by text content, parent traversal, and sibling navigation.
Try It Yourself
Working with XML and need to inspect document structure? Paste your XML into the XML Formatter to get clean, indented output that makes it easy to identify the correct XPath expressions for your queries.