XSLT Playground logo XSLT Playground
Powered by Saxon HE 12.5

XPath Tester Online

Evaluate XPath expressions against your own XML and see every match instantly. XPath 1.0, 2.0 and 3.1 on the real Saxon engine — completely free.

Open the XPath Tester →

What is XPath?

XPath is the expression language used to address parts of an XML document. It is the addressing layer underneath XSLT, XQuery, XML Schema and most XML tooling — every select and match attribute in a stylesheet is an XPath expression. An XPath expression navigates a document as a tree of nodes and returns a sequence of whatever it selects: elements, attributes, text nodes, or atomic values such as numbers and strings.

Most XPath bugs are not syntax errors — they are expressions that parse cleanly and quietly select the wrong nodes, or nothing at all. That is why evaluating an expression against a real document, on a real processor, is the fastest way to debug it. XSLT Playground evaluates your expression with Saxon HE 12.5, so what you see here is exactly what your production pipeline will do.

How to Test an XPath Expression Online

  1. Open the XPath tester template — it loads with a working stylesheet and sample XML already in place.
  2. Replace the sample XML in the Data Pipeline panel with your own document.
  3. Put the expression you want to evaluate in the expression variable.
  4. The result panel lists every matching node, numbered, with a total count at the top.
  5. If the count is 0, check namespaces first — an unprefixed name never matches a namespaced element.
The most common reason an expression returns nothing is namespaces. In XPath, //book matches only elements with no namespace. If your document declares xmlns="http://example.com/books", you must bind that URI to a prefix in the stylesheet and write //b:book, or use the wildcard form //*[local-name() = 'book'].

Common XPath Expressions

The expressions below are the ones that cover the overwhelming majority of real-world selection work. Each is written against the sample library document used in the live example further down.

ExpressionWhat it selects
//bookEvery book element anywhere in the document.
/library/bookOnly book children of the root library element — faster and safer than //.
//book[@lang = 'en']Books whose lang attribute equals en — an attribute predicate.
//book/@yearThe year attribute nodes themselves, not the elements.
count(//book)The number of books, as a number rather than a node sequence.
//book[price > 40]Books whose price child compares numerically greater than 40.
//book[contains(author, 'Martin')]Books whose author string contains a substring.
//book[starts-with(title, 'Clean')]Books whose title begins with a given prefix.
//book[1]Every book that is first among its own siblings — see the note below.
(//book)[1]The first book in the whole document.
//book[last()]The last book among each set of siblings.
//book[@lang = 'es']/following-sibling::bookBooks that come after the Spanish one, using an axis.
//price/ancestor::bookWalks back up the tree from a price to its containing book.
//book[not(@lang)]Books with no lang attribute at all.
distinct-values(//book/@lang)The deduplicated set of languages (XPath 2.0 and later).

Predicates: the Positional Trap

A predicate in square brackets filters the node sequence produced by the step it is attached to — not the final result of the whole path. This distinction catches almost everyone at least once. Given a document where books are split across shelves:

<library>
  <shelf id="A"><book>A1</book><book>A2</book></shelf>
  <shelf id="B"><book>B1</book><book>B2</book></shelf>
</library>

The same rule explains why //book[last()] can return several nodes. When you mean "the Nth thing overall", parenthesise the path.

XPath Axes

An axis says which direction to travel from the current node. child:: is the default and is almost always written implicitly, but the others become essential once you need to move sideways or upwards.

child / descendant

child::book (usually just book) and descendant::book, abbreviated .//book, walk downwards.

parent / ancestor

parent::* (abbreviated ..) and ancestor::book walk back up towards the document node.

following-sibling / preceding-sibling

Move sideways among nodes sharing a parent — the basis of pattern-based grouping in XSLT 1.0.

attribute / self

attribute::lang is abbreviated @lang; self::book (abbreviated .) tests the current node itself.

Live XPath Example: Evaluate an Expression and List Every Match

This is the stylesheet behind the XPath tester template. It wraps your expression in a harness that reports the match count and copies out every selected node, so you can see exactly what the expression returned rather than guessing from a single value.

XML input:

<library>
  <book lang="en" year="2001">
    <title>Refactoring</title>
    <author>Martin Fowler</author>
    <price>38.50</price>
  </book>
  <book lang="es" year="2005">
    <title>El Quijote</title>
    <author>Cervantes</author>
    <price>12.00</price>
  </book>
  <book lang="en" year="2018">
    <title>Clean Architecture</title>
    <author>Robert C. Martin</author>
    <price>41.20</price>
  </book>
</library>

Stylesheet:

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <!-- Put the expression you want to test here. -->
  <xsl:variable name="expression" select="//book[@lang = 'en']"/>

  <xsl:template match="/">
    <matches count="{count($expression)}">
      <xsl:for-each select="$expression">
        <match position="{position()}">
          <xsl:copy-of select="."/>
        </match>
      </xsl:for-each>
    </matches>
  </xsl:template>
</xsl:stylesheet>

Output:

<matches count="2">
   <match position="1">
      <book lang="en" year="2001">
         <title>Refactoring</title>
         <author>Martin Fowler</author>
         <price>38.50</price>
      </book>
   </match>
   <match position="2">
      <book lang="en" year="2018">
         <title>Clean Architecture</title>
         <author>Robert C. Martin</author>
         <price>41.20</price>
      </book>
   </match>
</matches>

Evaluating Several Expressions at Once

When you are comparing candidate expressions it is quicker to evaluate them side by side. This stylesheet runs eight expressions against the same library document and labels each result.

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/">
    <results>
      <r expr="count(//book)">
        <xsl:value-of select="count(//book)"/>
      </r>
      <r expr="//book[@lang = 'en']/title">
        <xsl:value-of select="//book[@lang = 'en']/title" separator=", "/>
      </r>
      <r expr="//book[price &gt; 40]/title">
        <xsl:value-of select="//book[price > 40]/title" separator=", "/>
      </r>
      <r expr="//book[contains(author, 'Martin')]/title">
        <xsl:value-of select="//book[contains(author, 'Martin')]/title" separator=", "/>
      </r>
      <r expr="//book[1]/title">
        <xsl:value-of select="//book[1]/title"/>
      </r>
      <r expr="//book[last()]/@year">
        <xsl:value-of select="//book[last()]/@year"/>
      </r>
      <r expr="//book[@lang = 'es']/following-sibling::book/title">
        <xsl:value-of select="//book[@lang = 'es']/following-sibling::book/title" separator=", "/>
      </r>
      <r expr="//price[. &gt; 40]/ancestor::book/@year">
        <xsl:value-of select="//price[. > 40]/ancestor::book/@year"/>
      </r>
    </results>
  </xsl:template>
</xsl:stylesheet>

Output:

<results>
   <r expr="count(//book)">3</r>
   <r expr="//book[@lang = 'en']/title">Refactoring, Clean Architecture</r>
   <r expr="//book[price &gt; 40]/title">Clean Architecture</r>
   <r expr="//book[contains(author, 'Martin')]/title">Refactoring, Clean Architecture</r>
   <r expr="//book[1]/title">Refactoring</r>
   <r expr="//book[last()]/@year">2018</r>
   <r expr="//book[@lang = 'es']/following-sibling::book/title">Clean Architecture</r>
   <r expr="//price[. &gt; 40]/ancestor::book/@year">2018</r>
</results>

Note that //book[1]/title returns a single title here only because all three books share one parent. The separator attribute on xsl:value-of requires XSLT 2.0 or later.

XPath 1.0 vs 2.0 vs 3.1 — What Changed

In XSLT Playground the XPath version follows the XSLT version you select: XSLT 1.0 gives you XPath 1.0, XSLT 2.0 gives XPath 2.0, and XSLT 3.0 gives the full XPath 3.1 surface.

Frequently Asked Questions

How do I test an XPath expression online?
Open the XPath tester template, paste your XML into the input panel, and put your expression in the expression variable. The result panel lists every matching node with a total count.
Which XPath versions can I test?
XPath 1.0, 2.0, 3.0 and 3.1. The version follows the XSLT version you select, and Saxon HE 12.5 evaluates all of them — including maps, arrays and the arrow operator in XPath 3.1.
Why does //book[1] return more than one node?
A positional predicate applies to each step, not to the whole result. //book[1] selects every book that is first among its own siblings. To take the first node of the entire result, parenthesise the path: (//book)[1].
Can I test XPath axes online?
Yes. All thirteen axes work, including ancestor, descendant, following-sibling, preceding-sibling, parent, self and attribute. The expression runs inside a real Saxon transformation, so behaviour matches production.
Do browsers support XPath 2.0 or 3.1?
No. Browsers implement XPath 1.0 only, so matches(), tokenize(), distinct-values() and format-date() are unavailable there. XSLT Playground runs Saxon on the server, which is why it can evaluate XPath 2.0 and 3.1.
Is the online XPath tester free?
Yes — completely free, no installation and no account. You can also share a workspace with a single link.

XPath Function Reference

Every XPath function, documented with syntax and a runnable example: browse the complete XSLT & XPath function reference. The functions that show up most often inside predicates:

Learn More

Also Available

Need to turn that XML into JSON once you have selected it? Try the XML to JSON converter →

Testing a full stylesheet rather than a single expression? Use the XSLT 2.0 Online Tester or the XSLT 3.0 Online Tester.