XPath Selectors for XML Guide

May 28, 20266 min read

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.

ExpressionMeaning
/catalogRoot element catalog
/catalog/bookAll book children of catalog
//bookAll book elements anywhere in the document
/catalog/book/titleAll 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

XPathResult
/catalog/book[1]First book
/catalog/book[last()]Last book
/catalog/book[position() < 3]First two books

By Attribute

XPathResult
//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

XPathResult
//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.

AxisDirectionExample
childChildren (default)child::bookbook
parentParent nodeparent::*..
ancestorAll ancestors up to rootancestor::catalog
descendantAll descendants at any depthdescendant::title
following-siblingSubsequent siblingstitle/following-sibling::*
preceding-siblingPrevious siblingsprice/preceding-sibling::*
selfThe context node itselfself::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.

FunctionPurposeExample
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 whitespacenormalize-space(title)
number()Convert to number//book[number(price) > 30]
count()Count node setcount(//book)
concat()Join stringsconcat(title, ' by ', author)
name()Node namename(//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

TaskCSS SelectorXPath
Select by text contentNot possible//a[contains(., 'Login')]
Select parent from childNot possible//a[@href="/login"]/..
Select by partial attribute[attr*="val"][contains(@attr, 'val')]
Select previous siblingNot possiblepreceding-sibling::div[1]
Select nth-from-lastLimited supportdiv[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-sibling and parent enable 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.