XPath Tester evaluates an XPath 1.0 expression against any well-formed XML you paste into your browser, then prints the natural result type — node-set, string, number, or Boolean — as visible text without inserting anything into the live page. The workflow runs entirely in the current tab: the XML is parsed with DOMParser into a detached document, the expression is handed to Document.evaluate, and matched nodes are serialized for inspection. Because the document lives in memory and not in the page DOM, you can paste an API response, an exported SOAP envelope, a saved RSS feed, or a fragment you copied from documentation and start querying it within seconds. There is no project to scaffold, no script to embed, and nothing uploaded to a server.

Why the Chrome Console $x() Helper Stops at the Live Page
Chrome DevTools exposes two quick ways to test an XPath expression: the Elements panel search box (Ctrl/Cmd+F inside Elements) and the $x("//div") helper in the console. Both of those mechanisms query the document that the browser is currently rendering. The moment your XML is not the rendered page — when you copied an API response into a text editor, exported a SOAP envelope from a tool, saved an RSS feed as a file, or pulled a fragment out of a static site generator — neither helper can help. There is no live document for the helper to query.
You can paste XML into the console as a string, but the console cannot parse it into a DOM for you. Pasting a long SOAP envelope into the console and re-running $x() only returns matches against the current page, not the envelope you just dumped. That is the gap XPath Tester fills. It builds a detached DOM from your XML in the browser, evaluates your expression against that DOM, and shows the result without ever touching the page.
Inside the Evaluation Pipeline
The tool performs four distinct steps, and the order matters. First, the XML you paste is parsed with DOMParser using the application/xml MIME type. If the parser returns a parsererror document, the tool treats it as a failure and refuses to evaluate any XPath — mismatched tags, unescaped ampersands, and other malformations short-circuit the run instead of producing a confusing empty result.
Second, the parsed document lives in memory as a detached DOM. It is not inserted into the page, so a matched element cannot execute scripts, load remote resources, or affect layout. Third, the XPath 1.0 expression you typed is passed to Document.evaluate with ANY_TYPE, which lets the browser report the expression's natural result rather than forcing it into a node list.
Fourth, the result is rendered as visible text. Node-set matches are listed one per numbered line. Attributes are shown with an explicit @-style representation. Text and comment nodes carry visible labels so a comment hit is not mistaken for empty text. None of that output becomes live markup; it is plain text inside the result panel.
Run an XPath Query in Four Steps
- Paste the XML fixture. Include any namespace declarations on the root element exactly the way your destination document uses them — for example, xmlns:b="urn:books" if you plan to select b:book later.
- Enter an XPath 1.0 expression. Keep it inside the 2,000-character limit and prefer a specific absolute path over a broad descendant search on large inputs.
- Run the evaluation. The browser parses the XML, builds the detached document, and calls Document.evaluate on it.
- Read the result panel. Note the result type (node-set, string, number, or Boolean), inspect each numbered match, then move the same expression into the runtime that will execute it in production.
For best results, keep a representative fixture and re-run after any change. The tool does not save history, so a stable paste buffer is on you. The XML Formatter is a useful companion if the XML you received is minified and hard to read before you paste it.
Reading the Output: What Each Result Type Looks Like
XPath expressions can return four distinct result types under the XPath 1.0 specification, and XPath Tester preserves the distinction rather than collapsing everything into a flat list. That distinction is what tells you whether the same expression will work in lxml, libxml2, or Java's javax.xml.xpath downstream.
| XPath construct | Natural result type | How XPath Tester displays it |
|---|---|---|
| //book | node-set | Numbered list of serialized element nodes with their children |
| string-length(title) | number | Scalar value such as 42 on its own line |
| count(//book) | number | Scalar value such as 7 on its own line |
| contains(title, 'XML') | Boolean | true or false on its own line |
| normalize-space(.//p) | string | The returned text on its own line, distinct from a one-node-set match |
Functions such as string(), count(), and boolean() always produce their scalar result, even when you might expect a node-set. An empty string and a zero-node-set are both valid results and are reported distinctly from parser errors and expression errors, which the tool prefixes with a stable label while keeping the underlying browser message available for diagnosis.
Namespaces and Prefixes: The Most Common Cause of Zero Matches
Under XPath 1.0, an unprefixed name such as book selects elements in no namespace. A root element declaring xmlns="urn:books" as the default namespace does not change that rule — the default is for element creation, not for XPath matching. If you paste the XML and write //book, the tool will return zero matches even though every book element is sitting right there in the parsed DOM.
The fix is to bind the namespace to a prefix on the root and use the prefix in the expression. If the root declares xmlns:b="urn:books", the expression //b:book will select the namespaced elements. The reserved xml prefix is mapped automatically, so xml:lang works without further setup. If the XML uses a default namespace and you cannot change it, your expression needs an //*[local-name()='book'] workaround — but a proper prefix is cleaner.
The same trap applies in production. Many server-side XPath libraries inherit the same XPath 1.0 rule, so an expression that returns zero matches in XPath Tester will return zero matches in your scraper unless the library is configured otherwise. A passing test in this tool is, by design, a meaningful check rather than a coincidence.
Limits, Errors, and What the Tool Refuses to Do
XPath Tester publishes explicit caps so you can plan around them rather than discovering them mid-debug. The XML source is limited to 500,000 characters, the expression to 2,000 characters, matched nodes to 500, and the displayed result text to 1,000,000 characters. Hitting the match limit is treated as a failure: the tool refuses to present a partial slice and asks for a narrower expression. That is by design — a silent truncation would be worse than an error.
The implementation follows the browser's XPath 1.0 interface, not XPath 2.0, 3.1, XQuery, XSLT, CSS selectors, or JSONPath. Sequences, maps, arrays, regular-expression functions, and typed values from later editions are out of scope. The tool does not fetch remote documents, follow links, execute scripts, mutate the source XML, insert matched markup into the page, or save a history of your queries. It also does not validate against an XSD or DTD — a match proves the XML is parseable and that the expression selects nodes, not that the document satisfies any business rule.
For sensitive XML, treat the input with the same screen-sharing and clipboard hygiene as any developer tool. The XML never leaves the tab, but anything you copy out of the result panel follows normal clipboard rules.
When the Same Expression Behaves Differently in Production
Passing in the tool is a useful filter, not a final verdict. Server libraries, browser XPath, and this tool all implement XPath 1.0 but differ on edge cases. The table below summarizes the cases that most often bite people after a clean run.
| Environment | XPath edition | Namespace policy | Typical mismatch with XPath Tester |
|---|---|---|---|
| XPath Tester (browser DOM) | 1.0 | Prefixes resolved from the document root plus the reserved xml prefix | Reference baseline |
| Browser $x() and Elements search | 1.0 | Prefixes from the live page; unprefixed names match the HTML namespace | Different document means different roots and different prefixes |
| Python lxml | 1.0 (with extensions) | Requires explicit namespaces dict at construction | Names declared on the root are not enough; the API expects them at call time |
| Java javax.xml.xpath | 1.0 | Resolver must be supplied for non-default prefixes | Resolver configuration, not just expression syntax |
| .NET XPathNavigator | 1.0 (XPath 2.0 in newer builds) | Namespace manager required | Edition drift can introduce functions XPath Tester rejects |
For reliable use, keep a representative fixture, declare prefixes explicitly, test positive and zero-match cases, and verify the same expression in the target runtime. The tool is the fastest way to confirm that the browser interprets your XPath the way you expect; it is not a substitute for running the expression where it will actually live. For deeper background on the underlying primitives, the MDN Document.evaluate reference documents the same browser interface XPath Tester calls.