XML Validator
Check XML well-formedness with the exact line, column and paired open-tag position of every error — entirely on this device.
The verdict appears here as you type — with the exact line, column and paired tag position when something's wrong.
Press ? for shortcuts
Do it offline:$ xmllint --noout file.xml
How to use it
- Paste XML or drop a file (.xml, .svg, .rss, .plist and friends) — up to 50 MB, worker-backed; from 2 MB the button names the size it will check.
- Read the verdict: a census and collapsible structure outline when well-formed, otherwise one exact error with a caret frame and a Jump to error button.
- Scan the advisory chips: undeclared prefixes, encoding mismatches and skipped DTDs are positioned warnings, never failures.
- Copy or download the plain-text report, or share the input as a link; past the 8 KB link budget the share becomes a state file.
XML errors come in pairs, so this validator reports both halves: a stray closing tag is matched to the element it actually closes and to the still-open tag it forgot, each with line and column. Well-formed documents get a census — root, elements, namespaces, size — plus a structure outline. Everything is checked on this device by a single strict pass; nothing is uploaded.
Examples
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://example.com/search?q=shoes&page=2</loc>
</url>
</urlset>Bare & at line 4, column 44 — write & unless starting an entity reference like < or  .Query strings break more sitemaps and feeds than anything else: every & between URL parameters must be &. The column lands on the exact ampersand, mid-URL.
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetPrice>
<Item>widget
</GetPrice>
</soap:Body>
</soap:Envelope>Mismatched closing tag </GetPrice> at line 5, column 5 — it closes <GetPrice> opened at line 3, but <Item> opened at line 4 is still open — did you forget </Item>?Three positions in one message — the wrong closer, the element it matches, the tag still waiting — plus the exact closing tag to add.
<order xmlns="https://example.com/ns/order" xmlns:pay="https://example.com/ns/pay">
<customer id="C-1041">Nia Devi</customer>
<items>
<item sku="A-7" qty="2">widget</item>
<item sku="B-3" qty="1">gasket</item>
</items>
<pay:total currency="EUR">41.90</pay:total>
</order>Well-formed · root <order> · 6 elements · 2 namespaces · 287 BThe census counts the document as written: six start tags, two declared namespace URIs and the size in bytes. Expand the outline and the order, items and item rows step inward three levels.
<config>
<db xsi:type="primary">main</db>
</config>namespace prefix 'xsi' on the attribute xsi:type at line 2, column 7 is not declared — well-formed, but namespace-aware parsers will reject it; add xmlns:xsi="…" on this element or an ancestorA missing xmlns:xsi declaration breaks namespace processing, not XML 1.0 well-formedness — so the verdict stays green and a warning carries the fix.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
External DTDs are never fetched
A SYSTEM or PUBLIC identifier produces a note — “external DTDs and entities are never fetched” — never a request; that one rule closes the XXE surface.
Entity bombs are budgeted, not expanded
A billion-laughs payload dies at accounting: past 1,048,576 expanded characters or 16 nesting levels comes the typed refusal “the document was rejected, not expanded”.
Encoding mismatches are named
Decoding follows the byte-order mark or the declaration (UTF-8, UTF-16, Latin-1); one the browser could not honor draws a warning that “characters and positions may be wrong”.
A leading byte-order mark is simply legal
U+FEFF at the start of a file passes with no diagnostic; the XML specification permits it.
XML 1.1 is checked as 1.0
A version="1.1" declaration is accepted, the document is “validated as XML 1.0”, and 1.1-only constructs such as control-character references still fail.
Whitespace-only gets a verdict; an empty pane waits
Blank space is a document with no root, refused gently: “Only whitespace at line 1, column 1 — probable cause: an XML document needs a root element; even <note/> is valid.”
50 MB cap, worker speed
Past 50 MB the refusal prints the exact figure; under it, a 30 MB export takes about a second in the worker.
Share links stop at 8 KB compressed
Bigger states download as a .json file instead; the file picker re-opens it with everything intact.
Common errors
Mismatched closing tag </headline> at line 2, column 22 — expected </title> for the <title> opened at line 2, column 3.- When the closer matches an ancestor instead, the wording flips to name the tag you forgot — fix the inner element first.
Unclosed element <playlist> at line 1, column 1 — the document ends before its closing tag; add </playlist>.- The position anchors the opener, not the last line, so the jump lands where the missing tag belongs.
Duplicate attribute id at line 1, column 15 — it already appears on this <user> tag at line 1, column 7; attribute names must be unique within a tag.- Repeating an attribute name in one tag is illegal however equal the values; both occurrences are positioned.
Second root element <row> at line 2, column 1 — an XML document has exactly one root element; <row> already closed at line 1.- Concatenated exports trip this constantly — wrap the records in one parent element or validate them singly.
Misplaced XML declaration at line 2, column 1 — <?xml …?> must be the very first thing in the document; remove the content before it.- Even a blank line ahead of <?xml is illegal — the declaration owns the first character. A byte-order mark is the one exception.
Unclosed comment at line 2, column 3 — the comment opened here never reaches -->.- Everything after the opener was swallowed as comment text — which is why the rest of the document seemed to vanish.
Invalid character U+0007 (BEL) at line 1, column 10 — control characters below U+0020 (except tab, LF and CR) are not allowed in text content.- XML 1.0 bans these codepoints outright, escaped or not; naming them matters because the character is invisible in editors.
Undeclared entity é at line 1, column 7 — only & < > ' " are predefined; declare it in the DTD or write the text out.- HTML's named entities are not XML's. Write the character, a numeric reference like é, or a DTD declaration.
Input is larger than the 50 MB limit for this tool. For bigger files use the CLI: xmllint --noout file.xml- A partial verdict would be worthless, so past the cap the page declines the whole document. The same check runs locally at any size.
FAQ
What is the difference between well-formed and valid XML?
Well-formed means the syntax itself holds — every tag closed in order, one root, attributes quoted and unique, entities known — and it is all this page judges. Valid means a well-formed document also obeys a grammar declared for it in a DTD or XSD schema. An XSD checker is a separate tool planned for this site; settle well-formedness first, because no schema processor accepts a document that fails here.
Why are external DTDs and entities never fetched?
Because a fetching parser can be steered: external entity declarations are the XXE technique — reading what a parser can reach, signaling remote servers. This page resolves nothing over the network; skipped declarations get a note, unverifiable references are tolerated and labeled.
Which XML versions and encodings are supported?
Documents are checked against XML 1.0 rules; a 1.1 declaration is accepted with a notice, and 1.1-only constructs still fail. Files decode as UTF-8 or UTF-16 by byte-order mark, follow their encoding declaration where the browser can honor it, and otherwise draw a warning naming both encodings.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Validate or re-validate — the explicit run required from 2 MB.
- ⌘/Ctrl + S
- Save the validation report as a .txt file.
- ⌘/Ctrl + C
- Copy the report while nothing is selected; selections copy natively.
- ⌘/Ctrl + Shift + C
- Copy the report even with a selection active.
- t
- Switch theme — inert while typing in a pane.
- ? or ⌘/Ctrl + /
- Show the shortcut overlay.
- Esc
- Close the open overlay or dialog.