How to test an XPath expression
- Paste the XML or open a file. The example is a UBL invoice.
- Type an expression and press Evaluate (or Enter), or click one of the expressions suggested under the field: they are written with the document's own element and attribute names.
- Each node found is listed with its path and line; click one to jump to it in the editor. Numbers, strings and booleans are shown as values.
Namespaces without the boilerplate
Most XPath testers fail on a document with a default namespace: //Invoice finds nothing, because the element is really {urn:oasis:names:specification:ubl:schema:xsd:Invoice-2}Invoice. Here, unprefixed names in your expression match the root element's namespace, and every prefix the document declares (cbc, cac, ram…) can be used as it is. The bindings in use are listed above the results.
XPath 3.1, not just 1.0
Expressions are evaluated by SaxonJS, which implements XPath 3.1: for and let expressions, if/then/else, regular expressions (matches(), replace()), dates and durations, string-join(), maps and arrays. XPath 1.0 expressions work as they are.
It is the same engine that runs the Schematron business rules in the validator, so an expression that works here works in an <assert test="…">. See the Schematron validator.
XPath cheat sheet
Every expression below runs against the example invoice (Load example above). Once your own document is in, the Cheat sheet for this document tab shows the same kinds of expression written with its element and attribute names, and the field completes names, functions and axes as you type.
Paths
- /
- The document node, above the root element.
- /Invoice
- The root element.
- /Invoice/*
- The elements directly under the root.
- /Invoice/cac:InvoiceLine
- Invoice lines, by their full path.
- //cbc:ID
- Every
cbc:ID, wherever it is. - //cac:InvoiceLine/cbc:ID
- The IDs that are children of an invoice line.
- //*
- Every element in the document.
- //cbc:IssueDate | //cbc:DueDate
- Both dates:
|joins two selections. - (//cbc:ID)[1]/..
- The parent of the first ID;
.is the current node.
Position
- (//cac:InvoiceLine)[1]
- The first invoice line in the document.
- //cac:Party/cac:PartyName[1]
- The first
cac:PartyNameof each party: without parentheses, the position counts among siblings. - (//cac:InvoiceLine)[last()]
- The last invoice line.
- (//cbc:ID)[position() <= 2]
- The first two IDs.
Conditions
- //cbc:InvoicedQuantity[@unitCode]
- Quantities that have a
unitCodeattribute. - //cbc:InvoicedQuantity[@unitCode = "HUR"]
- Quantities in hours.
- //cac:InvoiceLine[cbc:LineExtensionAmount > 600]
- Lines over 600: a comparison with a number compares numbers.
- //cac:InvoiceLine[not(cbc:Note)]
- Lines without a note.
- //cbc:Name[contains(., "Ltd")]
- Names that contain "Ltd".
- //cbc:Name[starts-with(., "North")]
- Names that start with "North".
- //cbc:ID[matches(., "^INV-\d{4}")]
- IDs matching a regular expression.
- //cac:InvoiceLine[cbc:ID = "1" and cbc:InvoicedQuantity > 5]
- Two conditions;
orworks the same way.
Values and functions
- //cbc:IssueDate/text()
- The text of an element.
- //@currencyID
- Every
currencyIDattribute. - string((//cbc:InvoicedQuantity)[1]/@unitCode)
- The first quantity's unit, as a string.
- count(//cac:InvoiceLine)
- How many lines there are.
- sum(//cac:InvoiceLine/cbc:LineExtensionAmount)
- The total of the lines;
avg(),min()andmax()work alike. - distinct-values(//@currencyID)
- Each currency once.
- string-join(//cac:PartyName/cbc:Name, ", ")
- Values joined into one string.
- name(/*) and local-name(/*)
- The root's name with and without its prefix;
namespace-uri(/*)gives its namespace. - lower-case(//cbc:DocumentCurrencyCode)
- Also
upper-case(),normalize-space(),substring(),replace(),tokenize(). - round(avg(//cac:InvoiceLine/cbc:LineExtensionAmount), 2)
- A number rounded to two decimals.
Axes
- //cbc:DueDate/preceding-sibling::*
- The elements before
cbc:DueDateunder the same parent;following-sibling::gives those after it. - //cbc:Name/ancestor::cac:Party
- The party a name belongs to.
- (//cac:InvoiceLine)[1]/descendant::*
- Everything inside the first line.
XPath 3.1
- //cac:InvoiceLine ! (cbc:LineExtensionAmount * 2)
- The simple map operator: a value per line.
- for $line in //cac:InvoiceLine return $line/cbc:ID || ": " || $line/cbc:LineExtensionAmount
- A loop, and
||to join strings. - let $total := sum(//cac:InvoiceLine/cbc:LineExtensionAmount) return $total = //cbc:LineExtensionAmount[parent::cac:LegalMonetaryTotal]
- A variable: do the lines add up to the total?
- if (count(//cac:InvoiceLine) > 1) then "several lines" else "one line"
- A condition.
- days-from-duration(xs:date(//cbc:DueDate) - xs:date(//cbc:IssueDate))
- Days between two dates.
- //cac:InvoiceLine => count()
- The arrow operator: the value on the left is the first argument.
The full lists are in the W3C recommendations: XML Path Language (XPath) 3.1 for the syntax, axes and operators, and XPath and XQuery Functions and Operators 3.1 for every function.
Questions
Is my XML uploaded?
No. The document is parsed and the expression evaluated in your browser, in a background worker.
Which XPath version is supported?
XPath 3.1, through SaxonJS. XPath 1.0 and 2.0 expressions work too.
Why does my expression find nothing?
Usually a namespace. Unprefixed names here match the root element's namespace; an element in another namespace needs the prefix the document uses for it.
How many results are shown?
The first 500, with the total count.
Other tools
- XML formatter: Pretty-print or minify XML, keeping text, CDATA and comments as written.
- XSD generator: Infer an XML Schema from sample documents, checked against them.
- XML from XSD: Generate a sample XML document from a schema, validated against it.
- XSLT transformer: Run XSLT 1.0, 2.0 or 3.0 on a document and see the result, the messages and the files it writes.
- XML diff: Compare two XML documents as trees: changed, added and removed elements, attributes and text.
- XML to JSON converter: Convert XML to JSON, with arrays where an element repeats or wherever its XSD allows.
- JSON to XML converter: Convert JSON to XML: @keys become attributes, arrays repeated elements.
- XML to CSV converter: Turn a repeating element into CSV rows: invoice lines, products, records.
- E-invoice viewer: Read an XRechnung, ZUGFeRD, Factur-X or Peppol invoice as a document, and print it.
- XML validator: check a document against XSD, DTD, RelaxNG or Schematron, up to 1 GB.