Beautify or minify XML, and find out where it stops being well-formed. It works on any format that is XML underneath: SOAP responses, RSS feeds, sitemaps, Android layouts, a hand-edited SVG. Your browser's own XML parser does the checking. Indent with 2 spaces, 4 spaces or a tab, and switch between them at any time.
<?xml version="1.0" encoding="UTF-8"?><catalog><!-- autumn list --><book id="1" lang="en"><title>The Left Hand of Darkness</title><author>Ursula K. Le Guin</author><price currency="USD">9.95</price></book><book id="2" lang="en"><title>The Pragmatic Programmer</title><author>Andrew Hunt</author><price currency="USD">32.00</price></book></catalog> <?xml version="1.0" encoding="UTF-8"?>
<catalog>
<!-- autumn list -->
<book id="1" lang="en">
<title>The Left Hand of Darkness</title>
<author>Ursula K. Le Guin</author>
<price currency="USD">9.95</price>
</book>
<book id="2" lang="en">
<title>The Pragmatic Programmer</title>
<author>Andrew Hunt</author>
<price currency="USD">32.00</price>
</book>
</catalog> This checks well-formedness, not
validity. Well-formed means every tag is closed
and correctly nested, attributes are quoted, there is
exactly one root element, and no bare &
or < appears in text. Every XML parser
enforces that before it does anything else.
Validity means the document also matches a DTD or an XSD, with the right elements in the right places. A document can be well-formed and still wrong for its schema. That check needs a validating parser such as xmllint with the schema file; this tool does not do it.
Characters are kept, but leading and trailing whitespace inside an element is trimmed. In mixed content, each text run moves onto its own line, so keep the original if inline spacing matters.
Emitted verbatim. Escaping the contents would change what the section means.
Both preserved, along with any processing instructions.
Prefixes and xmlns declarations pass through unchanged, so SOAP envelopes and namespaced documents survive.
Check for a bare &
first. It is the most common reason an XML
document fails to parse, and it usually arrives in a URL
with query parameters pasted straight into an element.
?a=1&b=2 has to be written
?a=1&b=2, or wrapped in CDATA. The
error message points at the ampersand.
# xmllint ships with libxml2, so it is already on most systems
xmllint --format messy.xml -o pretty.xml
# Well-formedness only
xmllint --noout document.xml
# Validate against a schema, which is the stronger check
xmllint --noout --schema schema.xsd document.xml
xmllint --noout --dtdvalid doc.dtd document.xml
# Query it
xmllint --xpath "//book[price>100]/title/text()" catalogue.xml # pip install lxml
from lxml import etree
parser = etree.XMLParser(remove_blank_text=True)
tree = etree.parse("catalogue.xml", parser)
print(etree.tostring(tree, pretty_print=True, xml_declaration=True,
encoding="UTF-8").decode())
# Validate against an XSD
schema = etree.XMLSchema(etree.parse("schema.xsd"))
if not schema.validate(tree):
for error in schema.error_log:
print(f"line {error.line}: {error.message}") remove_blank_text on the parser is what makes pretty_print work. Without it, lxml keeps the original whitespace and the output looks unchanged.
<?php
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->preserveWhiteSpace = false; // required for formatOutput to do anything
$dom->formatOutput = true;
libxml_use_internal_errors(true);
if (!$dom->loadXML($xml)) {
foreach (libxml_get_errors() as $e) {
echo "line {$e->line}: " . trim($e->message) . PHP_EOL;
}
libxml_clear_errors();
exit(1);
}
echo $dom->saveXML(); Disable external entities in any XML parser on a server. A document can declare an entity that reads /etc/passwd or fetches a URL, and a parser with default settings may resolve it. That attack is XXE (XML external entity injection), and it still turns up in security reviews. Use libxml_disable_entity_loader in older PHP, resolve_entities=False in lxml, and the equivalent setting in whatever parser you use.
This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.
It checks that the XML is well-formed: every tag closed, attributes quoted, one root element, entities escaped. It does not validate against a DTD or an XSD, which is a separate and much stricter check.
Mostly. Format keeps the characters but trims leading and trailing whitespace inside each element, and puts each text run in mixed content on its own line. Minify removes the whitespace between tags and collapses runs of spaces. If a document depends on exact mixed-content spacing, keep the original.
Yes, both, along with the XML declaration and any processing instructions. CDATA sections are written out verbatim, since escaping their contents would change the meaning.
Yes. Those are all ordinary XML, and Upload XML accepts .svg, .rss and .xsd files as well as .xml. Formatting a hand-edited SVG is a common use.
A bare & is not valid XML; it has to be &. It usually appears when a URL with query parameters is pasted straight into an element, and it is exactly the error a well-formedness check exists to catch.
The parser does not care: whitespace between elements is ignored by almost every consumer, so it is a convention choice. Match the file you are editing or your project's editor settings. Android and Maven files usually use four spaces, most web projects two, and tabs produce a slightly smaller file that each editor can display at its own width. Pick 2 Spaces, 4 Spaces or Tab in the Indent menu.
Yes. Paste the document, pick Tab under Indent, and the output is rebuilt from the parsed tree, so the original indentation is discarded completely rather than patched. The same works in reverse, or from 2 to 4 spaces. Text inside elements and CDATA sections are not touched, so only the structural whitespace changes. Minify ignores the setting and removes the indentation entirely.
To work with the data rather than the markup, XML to JSON converts it and JSON to XML goes back. For HTML specifically, the HTML formatter is more forgiving about unclosed tags.