XML Viewer

A vendor sends a 3 MB product feed. Somewhere six levels down sits the one price field your import needs. Open the file here, fold the tree to the level you care about, search for the tag, then copy its XPath into your parser code.

Load sample
Paste XML, open a file, or press a Load sample button.Elements 0Attributes 0Depth 0Size 0 B

Open the file, then find your way in

Raw XML hides its shape. Indentation helps for a screen or two, then the closing tags blur together. This viewer parses the document in your browser and shows each element as one row you fold open or shut. A 20,000 line export turns into a short list of top-level elements you open one at a time.

A run through the Sitemap sample shows the whole loop in under a minute:

  1. Press Sitemap in the Load sample row. The Tree tab opens with urlset and its three url entries unfolded.
  2. Type lastmod in the find box. The counter reads 1 / 3 and the first match is selected.
  3. Press Enter to step to the second match. Folded branches open on their own when a match sits inside them.
  4. Read the right panel. The XPath for the selected row sits at the top. Press Copy XPath, or C with the tree focused.

The same loop works on a real file. Press Open file or drop the file onto the Source panel. Feeds, SVG, KML, Maven pom.xml, .NET .csproj and WSDL all qualify, since each one is plain XML underneath. Files are decoded with the encoding named in their XML declaration, so a legacy export marked ISO-8859-1 or windows-1252 keeps its accented names intact. UTF-16 files are picked up from their byte order mark.

Reading a row

Every row is one node. The markup stays in its XML form so you never have to translate an icon back into syntax.

On screenMeaning
<url>4 childrenAn element with child nodes, folded. Click the arrow or press → to open it. The count covers elements, comments, CDATA and text runs.
<loc>https://toolexe.com/xml/viewer</loc>An element holding only text, printed on one line with no arrow. Long values get cut at 120 characters in the row. The right panel shows the full text.
<image:image>A prefixed name, kept exactly as written in the file.
<trk:Event seq="1" at="..." city="...">+2 attrThe row shows the first three attributes. The rest are counted, and the right panel lists every one.
"Shipped from"Text in quotes sits beside child elements. This is mixed content, common in DocBook, XHTML fragments and Office XML.
<!-- ... -->, <![CDATA[ ... ]]>, <?xml-stylesheet ... ?>Comments, CDATA sections and processing instructions each get their own color, so a CDATA block never passes for plain text.
Show 500 moreAn element with more than 500 children. Rows render in batches of 500 so a sitemap with 40,000 URLs opens without freezing the tab.

Whitespace between tags is hidden. Those text nodes exist in the parsed document, and XPath counts them, yet in data files they hold nothing but line breaks and indentation.

Copied XPath, and why some paths say local-name()

The right panel prints an absolute path from the root to the selected row. Positions appear only where siblings share a name, so /rss/channel/item[2]/title points at the second item and no other.

Default namespaces change the output. The sitemap sample declares xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" on urlset. In XPath 1.0 a bare name such as url matches only elements in no namespace, so /urlset/url returns an empty result against this file. People lose an afternoon to this one. The viewer writes those steps in a form every XPath 1.0 engine accepts:

/*[local-name()='urlset'/'+\'\'+'*'url'/'+\'\'+'*'loc']

Prefixed names stay as written. /soap:Envelope/soap:Body works once your code binds the soap prefix, which lxml in Python, DOMXPath::registerNamespace() in PHP and a NamespaceContext in Java all require before evaluation. When you own the evaluation code, binding a prefix to the default namespace gives shorter paths than local-name(), and runs faster on big documents.

Paste either form into the XPath Tester to confirm what it selects before it goes into code.

Keyboard map

Click once inside the tree, then keep your hands on the keys.

KeyAction
↑↓Move between visible rows
→Open a folded element, or step into its first child
←Fold an open element, or step up to its parent
Enter or SpaceToggle the selected element
HomeEndFirst or last visible row
/Jump to the find box from anywhere on the page
EnterShift+EnterNext or previous match, inside the find box
EscClear the search and return to the tree
CCopy the XPath of the selected row

When a broken file comes in

A tree needs a well formed document, so a single bad tag stops the build. Load the Broken document sample to see what happens next. The status bar turns red, the Source tab stays open, and a code frame prints the failing line with a caret under the column the browser parser reported. Jump to line moves the cursor there in the text box. Fix the tag and the tree rebuilds after a short pause.

Read the reported line with some suspicion. For a mismatched tag, the parser complains where the wrong closing tag sits, while the real mistake is often an opening tag several lines higher that never got closed. The sample shows exactly that: the error lands on </lines>, and the missing </line> belongs one row above.

Viewer, parser or pretty print

Nothing leaves your tab. Files are read by the browser, parsed with its built-in DOMParser, and dropped when you close the page. No DTD is fetched and no external entity is resolved, so a payload holding customer records stays on your machine.

Where the viewer stops

XML viewer questions

What people ask after the first real file goes in.

I pasted XML and the tree did not open. Why?

Pasting switches to the Tree tab only when the document parses. When it fails, the status bar turns red and the Source tab shows the line and column where the browser parser stopped, with a caret under the spot. Fix that tag and the tree builds on its own.

Why does a copied XPath use local-name() instead of the tag name?

The element sits in a default namespace, declared with a plain xmlns attribute. XPath 1.0 matches a bare name only against elements in no namespace, so the short path returns nothing. The local-name() form works in any XPath 1.0 engine with no prefix setup. Prefixed elements such as soap:Body keep their prefix, and your code binds it before evaluating.

Which file types open?

Anything well formed: RSS and Atom feeds, sitemaps, SVG, KML and GPX tracks, Android layouts, Maven pom.xml, .NET project and resource files, WSDL, XSD and XSLT. The file picker filters on common extensions. Dropping a file onto the Source panel skips the filter.

Is my file uploaded anywhere?

No. Reading, parsing, searching and copying all run in JavaScript inside your tab, and nothing is stored between visits. Close the tab and the document is gone.

Some text from my file is missing in the tree. Where did it go?

Whitespace-only text between tags is hidden, since in data files it holds only indentation. Text inside an element with no child elements shows on the same row as the tag. Text sitting beside child elements appears as its own quoted row.

How large a file is too large?

The hard limit is 10 MB. Browsing stays smooth well past that size thanks to batched rendering, yet typing into the Source tab gets sluggish above 2 MB because every pause triggers a full re-parse. For large files, open them, read them, and do the editing elsewhere.