XML Formatter & Validator

Format, minify and check XML, and point at the exact spot where it breaks.

402 / 500,000 characters

Formatted XML

<?xml version="1.0" encoding="UTF-8"?>
<!-- The pond log, newest first. -->
<pond xmlns:duck="https://quackyard.com/duck">
  <duck:entry duck:id="1" when="2026-09-01">
    <duck:name>Quackmore</duck:name>
    <note>Woke up <b>grumpy</b>, then had peas.</note>
  </duck:entry>
  <duck:entry duck:id="2" when="2026-09-02">
    <log><![CDATA[if (bread > 0) { eat(bread); }]]></log>
  </duck:entry>
</pond>

7 elements · 5 attributes · 402 → 402 characters

Runs in your browser. Nothing you enter is sent anywhere.

How to use it

Paste a document into the XML box. It’s parsed as you type, in your browser.

  1. Choose Format to break it into indented lines, then pick 2 spaces, 4 spaces or Tabs. Choose Minify to drop the whitespace between elements; the indent choices are hidden there.
  2. Press Copy next to Formatted XML or Minified XML. The line under the output counts elements and attributes and gives the size in characters before and after.

If the document isn’t well-formed, there’s no output. You get the first problem with its line and column, and under it that line with a caret below the column. Sample document and Broken document load examples.

Examples

An Atom feed on one line, with Format and 2 spaces:

<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title>Pond log</title><entry><id>urn:pond:1</id><link href="/log/1" rel='alternate'/><summary>Seven ducks &amp; one heron</summary></entry></feed>
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Pond log</title>
  <entry>
    <id>urn:pond:1</id>
    <link href="/log/1" rel="alternate"/>
    <summary>Seven ducks &amp; one heron</summary>
  </entry>
</feed>

The line reads 6 elements · 3 attributes · 227 → 253 characters. The xmlns declaration counts as an attribute, and rel='alternate' comes back in double quotes.

A config file with a comment, an empty element, mixed content and a CDATA section, with Minify:

<config>
  <!-- local only -->
  <db host="localhost" port="5432"></db>
  <greeting>Hello, <b>world</b>!</greeting>
  <script><![CDATA[if (a < b && c) go();]]></script>
</config>
<config><!-- local only --><db host="localhost" port="5432"/><greeting>Hello, <b>world</b>!</greeting><script><![CDATA[if (a < b && c) go();]]></script></config>

The comment stays. <db></db> becomes <db/>, which means the same in XML. The text in greeting and the CDATA are copied exactly.

The Broken document sample:

<pond>
  <entry>one</entry>
  <entry>two</entree>
</pond>
Line 3, column 13: </entree> does not match <entry>, which is still open.
  <entry>two</entree>
            ^

</Entry> would fail the same way: XML names are case-sensitive.

An HTML entity in XML:

<item>
  <price>9&nbsp;EUR</price>
</item>

The error is Line 2, column 11: unknown entity "&nbsp;" — only amp, lt, gt, apos, quot and numeric references are supported. Write &#160; instead.

Good to know

  • The rules are XML 1.0’s well-formedness constraints. One root element; matching, case-sensitive tags; quoted attribute values, each name once per element; < and & escaped in text and attributes; no ]]> in text, and no -- in a comment or ---> at its end; no control characters, even as references like &#0;. The <?xml ...?> declaration, if there is one, must be the very first characters, in lower case: not even a blank line may come before it. Hex references use a lower-case x: &#x41; works, &#X41; doesn’t.
  • Well-formed isn’t the same as valid. Nothing is checked against a DTD or an XML Schema (XSD). A DOCTYPE is kept as written but not read, so entities it declares are reported as unknown, and namespace prefixes aren’t checked against their xmlns declarations.
  • XML predefines only five entities: &amp;, &lt;, &gt;, &apos; and &quot;. HTML names like &nbsp;, &copy; or &eacute; need a numeric reference instead: &#160;, &#169;, &#233;.
  • Text is written back with minimal escaping. References are read and only what must be escaped is escaped again: &#169; comes out as © and &gt; as >, while &amp;, &lt; and the &gt; in ]]&gt; stay. &#9;, &#10; and &#13; stay references where a parser would change the literal character: a tab or line break in an attribute reads back as a space. Every attribute gets double quotes. CRLF line breaks come out as LF, as any XML parser reads them.
  • An element with any text is left on one line, as written. <note>Woke up <b>grumpy</b>, then had peas.</note> keeps every space inside it, because in mixed content whitespace is data. The same goes for an element holding CDATA.
  • Whitespace-only text between elements is treated as indentation. In <p><b>x</b> <i>y</i></p>, Minify drops the space between b and i, and Format turns it into a line break. Only space, tab and line breaks count: a non-breaking space (&#160;) is text and stays. To keep an element’s whitespace exactly, descendants included, give it xml:space="preserve", as XML 1.0 defines.
  • Comments, processing instructions, the XML declaration and the DOCTYPE are kept in both modes, in their original place.
  • Input is limited to 500,000 characters.

Questions

How do I check if XML is valid?

Paste it into the XML box: a formatted result means it’s well-formed, and an error points at the first problem. On the command line, xmllint --noout file.xml checks well-formedness and xmllint --noout --schema schema.xsd file.xml also validates against an XSD.

How do I pretty-print XML on the command line or in Python?

xmllint --format file.xml from libxml2 prints an indented copy. In Python 3.9 or later, xml.etree.ElementTree.indent(tree) indents a parsed tree in place before you write it; xml.dom.minidom.parseString(text).toprettyxml() works in older versions.

Why is &nbsp; an error in XML?

Because XML defines only &amp;, &lt;, &gt;, &apos; and &quot;; &nbsp; belongs to HTML. Use the numeric reference &#160;, type the non-breaking space itself in a UTF-8 file, or declare the entity in the document’s DTD for parsers that read it.

Is <tag/> the same as <tag></tag>?

Yes. XML treats an empty-element tag and a start tag immediately followed by its end tag as the same empty element. Format keeps whichever you wrote, and Minify writes the short form.