1. Home
  2. Blog
  3. How to Use XPath to Find Data in XML (with Examples)
XML Toolkit

How to Use XPath to Find Data in XML (with Examples)

Published 30 October 2026 · 7 min read

XPath is a small language for pointing at parts of an XML document, a bit like a file path points at a file on your computer. Instead of reading a whole file, you write //book/title and get every book title. It’s used in XSLT, in test tools like Selenium, in data imports, in configuration files and in almost every programming language that reads XML.

This guide walks through the XPath you’ll actually use, with real results, using the free XPath Tester. Every example below runs on the tester’s own Sample, so you can follow along.

The sample XML

A small shop with two books:

<shop name="Corner Books">
  <book id="bk101" lang="en">
    <title>XML &amp; JSON for Everyone</title>
    <author>Ada Lovelace</author>
    <price currency="EUR">29.95</price>
    <inStock>true</inStock>
    <tag>data</tag>
    <tag>web</tag>
  </book>
  <book id="bk102" lang="de">
    <title>Daten für alle</title>
    <author>Alan Turing</author>
    <price currency="EUR">24.50</price>
    <inStock>false</inStock>
    <tag>data</tag>
    <discount/>
  </book>
</shop>

How to test an XPath expression

  1. Open the XPath Tester. Click Sample to load the shop above, or paste your own XML or open a file.
  2. Type an expression into XPath expression. The line under it says ✓ Valid XPath expression as soon as it’s complete. The Try: buttons fill in ready-made examples.
  3. Press Enter or click Run XPath. You see how many nodes match, each with its type (element, attribute, text…) and its line; click the line number to jump to it in the XML.

The building blocks

  • / goes one level down from where you are; at the start it means “from the top of the document”.
  • // searches at any depth. //title finds titles wherever they are.
  • @ means an attribute: @id is the id attribute.
  • [ ] filters: only keep the nodes for which the condition is true.
  • * matches any element, . is the current node and .. its parent.

Selecting data

  • //book/title: every book’s title element → 2 matches: “XML & JSON for Everyone” and “Daten für alle”
  • //title/text(): only the text inside the titles → the same two texts, without the tags
  • //book/@id: the id attribute of every book → bk101 and bk102
  • /shop/@name: the name attribute of the top element → Corner Books
  • //price/@currency: the currency of every price → EUR and EUR

Filtering with conditions

  • //book[@lang='en']/title: titles of books whose lang attribute is “en” → XML & JSON for Everyone
  • //book[price > 25]/title: titles of books that cost more than 25 → XML & JSON for Everyone
  • //book[tag='web']/author: authors of books with a “web” tag → Ada Lovelace
  • //book[inStock='true']/title: books in stock → XML & JSON for Everyone
  • //book[discount]/@id: books that have a discount element at all → bk102
  • //title[contains(., 'JSON')]: titles that contain the word JSON → XML & JSON for Everyone
  • //book[1]/author: the author of the first book → Ada Lovelace
  • //book[last()]/title: the title of the last book → Daten für alle
  • //*[not(node())]: empty elements, which are often mistakes → <discount/>

Conditions can be combined with and and or, for example //book[@lang='en' and price > 25].

Counting and adding up

XPath can also return a single value instead of nodes:

  • count(//book): how many books there are → 2
  • sum(//price): the total of all prices → 54.45
  • boolean(//book[price > 100]): is there any book over 100? → false

Two mistakes almost everyone makes

1. The default namespace trap

Many real files, such as RSS and Atom feeds, sitemaps, Office files and SOAP messages, start with a default namespace:

<feed xmlns="http://www.w3.org/2005/Atom">
  <entry><title>Hello</title></entry>
</feed>

Here //entry/title finds nothing, because every element belongs to that namespace and a plain name doesn’t match it. Match by local name instead: //*[local-name()='entry']/*[local-name()='title']. The XPath Tester spots this situation and tells you.

2. Functions from newer XPath versions

Browsers, Selenium and most libraries use XPath 1.0. Functions from XPath 2.0 and later, such as lower-case(), matches() or ends-with(), don’t exist there. To ignore upper and lower case in XPath 1.0, use translate(), and to check how a value ends, compare substring().

Smaller gotchas

  • Positions start at 1, not 0: //book[1] is the first book.
  • Text comparisons are exact, including upper and lower case and spaces: [tag='Web'] doesn’t match “web”.
  • Write quotes inside quotes the other way round: //book[title="Daten für alle"] or [title='…'].

More XML tools

Is my XML uploaded?

No. The XPath runs in your browser, so your XML never leaves your device. Our server only records that one test happened, for the daily limit.

Frequently asked questions

Which XPath version does the tester use?

XPath 1.0, the version built into browsers and used by Selenium and most libraries, so an expression that works here works there too.

Can I test XPath for a web page (HTML)?

This tester needs well-formed XML, which most web pages aren’t. For a live page, open your browser’s developer tools and use the console: in Chrome and Edge, $x("//h1") runs an XPath on the page.

Why does my expression return nothing?

Check for a default namespace first, then for upper/lower case and extra spaces in text comparisons. Start with a short path such as //book and add one step at a time.