XML Syntax Checker

Paste a document, get the exact line and column where the parser stopped, and a count of what it managed to read before stopping. Everything runs on your machine.

Source

Report

Not checked

Nothing checked yet. Press Check syntax and the parser result lands here.

A pass means well-formed. It does not mean the document matches a DTD or an XSD. The difference is explained below.

An XML parser is unforgiving in a way HTML parsers are not. A browser will happily render a page with an unclosed <div>. An XML parser reading the same mistake stops dead and returns nothing usable. That strictness is the point of the format, and it is also why a single stray character in a 4,000 line SOAP response takes an afternoon to find.

This page runs your document through the same DOMParser your browser uses for XHTML and feeds back what it says. When the parse fails you get the message, the line, and the column. When it succeeds you get a structural summary you can sanity check against what you expected the file to contain.

Well-formed and valid are two different checks

These words get used interchangeably in bug reports and they mean different things in the XML spec.

Well-formed

Grammar only. One root element, every open tag closed, tags nested rather than overlapped, attribute values quoted, reserved characters escaped, names following the naming rules.

This page checks this

Valid

Conformance to a declared grammar: a DTD, an XSD schema, or a RELAX NG file. Are the right elements present, in the right order, with the right data types, inside the right parents.

This page does not check this

A document is often well-formed and wrong. <order><quantity>banana</quantity></order> parses without complaint. If the schema says quantity is xs:integer, the receiving system rejects it anyway. When an API returns a schema error rather than a parse error, this tool has already told you everything it knows.

Five failures behind most parser errors

Each block below is a real broken document. Load one into the editor to see how the parser reports it, then fix it in place.

1. A bare ampersand in text

Most common by a wide margin

An ampersand starts an entity reference. Written on its own, the parser reads forward looking for a name and a semicolon, finds a space instead, and gives up. Company names and query strings copied out of a database trigger this constantly.

<vendor><name>Marks & Spencer</name></vendor>

Fix: write &amp; for a literal ampersand, or wrap the text in <![CDATA[ ... ]]> when the string is full of markup characters. The other four that need escaping in text or attributes are <, >, ", and '.

2. Tag names differing by case

Hand-edited files

XML is case sensitive from top to bottom. <Book> and <book> are unrelated elements, so a closing tag with different capitalisation reads as a mismatch. People coming from HTML hit this on their first day.

<catalog><Book>Clean Code</book></catalog>

Fix: match the case exactly. Pick one convention for the whole file and stay with it.

3. Two root elements

Concatenated files and log dumps

An XML document has exactly one outermost element. Appending records to a file or joining two responses produces a second root, and the parser reports trouble at the start of the second one even though the file looked fine up to there.

<record id="1"><value>12</value></record><record id="2"><value>34</value></record>

Fix: wrap both in a container element such as <records>. If the source is an append-only stream, read it record by record rather than parsing the whole file as one document.

4. An element name starting with a digit

Generated from spreadsheets

Names start with a letter or an underscore. Anything generated from spreadsheet column headers or database fields called 2024_total produces names the parser refuses. A name also cannot contain a space, and cannot start with the letters xml in any casing.

<report><2024_total>98000</2024_total></report>

Fix: prefix it, as in <y2024_total>, or move the number into an attribute: <total year="2024">. The attribute version is usually the better data model anyway.

5. An undeclared namespace prefix

SOAP and RSS payloads

A prefix such as soap: means nothing on its own. It has to be bound with an xmlns:soap declaration on that element or an ancestor. Copying an inner fragment out of a larger SOAP envelope leaves the prefix behind and the binding upstream.

<soap:Body><getPriceResponse><price>34.50</price></getPriceResponse></soap:Body>

Fix: carry the declaration down with the fragment: <soap:Body xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">. The URI is an identifier, not an address, so nothing is fetched from it.

The reported line is where the parser gave up, not where you slipped

This trips up people more than the errors themselves. A parser reads forward and reports trouble at the first character it cannot reconcile with what it has already seen. With an unclosed <item> on line 40, the mismatch surfaces on line 300 at the closing </order>, because that is the first tag the parser can prove is wrong.

So read the reported line as a ceiling. Your mistake is on that line or above it. Two habits narrow the gap fast: indent the document first, because a mis-nested tag becomes visible as a step in the indentation, and cut the file in half and check each part to bisect toward the break.

The wording of the message depends on the browser engine, not on this page. Chrome and Edge report Opening and ending tag mismatch. Firefox says mismatched tag. Safari phrases it differently again. Same document, three sentences. Compare the line numbers rather than the prose when you look up an error.

What the numbers in the report mean

Where this checker stops

Being honest about the ceiling saves you from trusting a green badge too far.

Once the document parses

Fixing syntax is step one. To read a large valid file, the XML Pretty Print tool gives a collapsible tree. To pull the tree apart node by node, use the XML Parser.

Moving the data elsewhere usually means a conversion: XML to JSON for a JavaScript client, and the XML Minifier when payload size on the wire is what you are cutting.

Your document never leaves the browser. Parsing, counting, and formatting all run in local JavaScript, so no request carries the content to Toolexe or anywhere else.

XML syntax questions

What this checker reports, and what it deliberately leaves alone.

My XML passes here but the API still rejects it. Why?

This page checks well-formedness, meaning grammar. The API is checking validity against a schema: required elements, ordering, and data types. A document with the word banana inside an integer field is well-formed and still rejected. Read the API error for the element name it names, then compare that element against the published schema.

The error points at line 300 but that line looks fine.

The parser reports the first place it can prove something is wrong, which is usually after the actual mistake. An unclosed tag near the top surfaces at the closing tag near the bottom. Treat the reported line as the upper bound, indent the file, and work upward from there.

Does it validate against a DTD or XSD?

No. A DOCTYPE declaration is read as syntax and its rules are never applied, and no external DTD or schema file is fetched. For schema conformance you need a validating parser such as xmllint with the --schema flag, or the validator built into your XML editor.

Why does my SOAP fragment fail on a namespace prefix?

Prefixes are bound by an xmlns declaration on the element or one of its ancestors. Copying an inner fragment out of a full envelope leaves the prefix without its binding. Add the xmlns declaration to the outermost element of your fragment and it parses.

Is the file uploaded anywhere?

No. The DOMParser call, the element counting, and the indentation all run in your browser. Nothing is transmitted, which also means nothing is stored, so keep your own copy before clearing the editor.

What size of document does this handle?

Files up to a few hundred kilobytes are comfortable. Past a megabyte or two the code editor starts to lag on scrolling and typing well before the parser itself is under pressure. For anything larger, xmllint --noout on the command line reports the same first error without loading the file into a browser tab.