Testing XPath expressions against your XML
XPath is the query language for picking parts out of an XML document: elements by path, attributes by name, nodes that pass a condition, or a computed number such as a count or a sum. This tester runs your expression against the XML you paste and prints every match, one per line, or the single value an expression returns.
Evaluation uses the browser's native document.evaluate, which implements XPath 1.0. That's the version used in XSLT 1.0, in many test frameworks and in browser developer tools, so expressions you prove here will carry over to those.
A sample document and real results
<inventory>
<item id="A1" stock="12"><name>Keyboard</name><price>49.90</price></item>
<item id="B2" stock="0"><name>Mouse</name><price>19.50</price></item>
<item id="C3" stock="5"><name>Monitor</name><price>189.00</price></item>
</inventory>
Each expression below was run against it:
| Expression | Output |
|---|---|
//item/@id |
A1, B2, C3 (one per line) |
//item[@stock > 0]/name |
Keyboard, Monitor |
//item[price < 50]/name/text() |
Keyboard, Mouse |
//item[1]/name |
Keyboard |
(//item)[last()]/name |
Monitor |
count(//item) |
3 |
sum(//price) |
258.4 |
sum(//price) div count(//price) |
86.13333333333333 |
boolean(//item[@stock=0]) |
true |
concat(//item[1]/name, " costs ", //item[1]/price) |
Keyboard costs 49.90 |
string(//item[3]/@id) |
C3 |
//item[2] |
Mouse19.50 |
//missing |
No nodes matched that XPath expression. |
Comparisons like @stock > 0 and price < 50 convert text to numbers automatically, which is why they work on values stored as strings. XPath numbers are floating point, so averages print with all their digits; wrap them in round() if you only want whole numbers.
How output is shown
The tool asks for "any type" of result and prints it according to what comes back:
- A node-set (most path expressions): one line per node. Attributes print their value; elements and text nodes print their text content. An element with children prints all its descendant text run together, as in the
//item[2]row above. - A number, string or boolean (from
count(),concat(), a comparison, and so on): printed as a single value.
No match gives the message "No nodes matched that XPath expression." rather than empty output, so you can tell the difference between "matched an empty element" and "matched nothing".
Step by step
- Paste the XML document into the first box. It has to be well-formed; otherwise you'll see "Enter valid XML in the first field." The XML validator will show you the exact problem.
- Type the expression into the second box.
- Click Test.
- Refine. Start broad (
//item), then add steps and predicates until only what you want remains.
Namespaces: the usual reason for "no match"
Atom feeds, SOAP envelopes, SVG and most XML produced by enterprise systems declare a default namespace on the root element. Against <feed xmlns="http://www.w3.org/2005/Atom">...<title>Hello</title>...</feed>, the expression //title returns no match, while //*[local-name()="title"] returns "Hello".
This is correct XPath 1.0 behaviour, not a bug. An unprefixed name in an expression means "no namespace", and the tool doesn't let you bind prefixes, so local-name() is the way to match by name alone. For documents with several namespaces, add a namespace-uri() test to the same predicate to be precise.
Expressions that won't work here
- XPath 2.0 and 3.1 functions such as
lower-case(),matches(),tokenize()andstring-join()give an "Invalid XPath expression" error. In 1.0, case-insensitive matching is done withtranslate(). - Returning markup. You get text, not the XML of the matched element. Use the XML formatter if you want to look at a section's structure, or the JSON/XML tree viewer to browse it.
- Invalid syntax, such as an unclosed bracket in
//item[, is reported with the browser's message, which varies between Chrome and Firefox.
If your data is JSON rather than XML, the equivalent tool is the JSONPath tester.
Last updated