Format and validate XML without changing the document: CDATA, xml:space="preserve" and mixed content all survive, with errors carrying a line, a caret and a next step, plus XPath queries, a tree view and JSON conversion that names what JSON cannot carry
Initializing in your browser…
Format, validate and minify JSON, JSON with comments and JSON5, without changing a single value: every number is written back as the document spelled it. Errors carry a line, a column and the offending line. JSONPath queries, tree view, schema checks and diff
Format YAML without rewriting it: comments, anchors, quoting, block scalars, multi-document streams and the exact spelling of every number all survive, with YAML 1.1 and 1.2 both offered because the same file means different things under each
Minify or beautify JavaScript, TypeScript, CSS, HTML, JSON, XML and SQL with a real lexer per language, so a comment inside a string is not deleted and a line break the code depends on is kept, with the byte saving measured
You indent a one-line document to read it. It has a CDATA section holding some code, and a paragraph with an element in the middle of a sentence.
XML
<root><code><![CDATA[ if (a < b) {} ]]></code><p>one <b>two</b> three</p></root>Formatted
<root>\n <code><![CDATA[ if (a < b) {} ]]></code>\n <p>one <b>two</b> three</p>\n</root>Both of those elements stay on one line, and that is the point: their content is text, and indenting their children would insert whitespace inside it. XML has no insignificant whitespace without a schema, so the only thing a formatter may add or remove is a text node that is whitespace and nothing else. The previous version re-indented the CDATA and changed its text. Checked against xmllint and Python's ElementTree, 15 of 15 corpus documents now come out unchanged and correctly indented, against 14 and 12.
Format, validate and query XML, with the rule that formatting changes the whitespace between elements and nothing else. XML has no notion of insignificant whitespace without a schema, so that is the only freedom a formatter has: **a text node that is whitespace and nothing else may be added or removed, and every other character stays.** That is measured rather than promised. Every document in the test corpus is formatted and then judged by two things outside this tool: `xmllint --noblanks --c14n`, which is libxml2, and Python's `xml.etree.ElementTree`. The version this replaces came out as the same document on 14 of 15 and was correctly indented on 12 of 15; this one manages 15 and 15.
The tool already used `DOMParser` for its tree view and its XPath queries, which is the right decision and has not changed: the browser's own parser is what will read your document everywhere else. Its formatter and its minifier ran over the raw text, and that is where the faults were.
The formatter inserted a line break at every `><` boundary and then indented each line by matching it against a pattern. On `<root><a><b>1</b></a></root>` it put `<a>` and `<b>` at the same level; on a five-level document it produced no indentation at all; and given `<code><![CDATA[ x ]]></code>` it re-indented the CDATA section, changing the text of `<code>` from ` x ` to a newline, six spaces, `x` and two more. Nothing inside a CDATA section is markup and nothing in it is free whitespace.
This version works from a token stream and follows one rule: **an element with any text content is written on one line, exactly as it was.** Indenting the children of such an element would insert whitespace inside its text. `xml:space="preserve"` extends the same protection to an element and everything under it, which is the document explicitly telling a processor to leave it alone (XML 1.0 section 2.10). Mixed content such as `one <b>two</b> three` keeps both of its spaces.
**Validation now says where and why.** A `parsererror` from `DOMParser` carries a sentence; the checker that runs alongside it carries a line, a column, the offending line with a caret under it, and a next step: which element is still open, that XML is case sensitive so `<Root>` is not closed by `</root>`, that an XML document has exactly one root, that XML has no bare attributes. The two readers are compared on every corpus document and agree on all 21, so nothing is being caught by one and missed by the other.
**Converting to JSON names what JSON cannot carry.** A comment and a processing instruction have no JSON equivalent, and the version this replaces dropped both without saying so. The mapping is stated rather than assumed, because there is no standard one: an element becomes an object, its attributes go under `@name`, its text under `#text`, and repeated children of the same name become an array.
The page also reports what the document holds: the namespace prefixes declared, whether there is a default namespace, which elements carry `xml:space="preserve"` and are therefore untouched, how many CDATA sections there are, and how deep the nesting goes.
Indent a one-line SOAP response or RSS feed to see its structure, without the formatter quietly rewriting anything inside a CDATA section.
Get a line, a column and a sentence naming which element is still open, rather than one message about the first thing that went wrong.
Query the document with the browser's own XPath engine and see every match, which is the fastest way to check a selector before putting it in code.
Only the whitespace between elements, which is the only freedom XML gives a formatter without a schema. That is checked against two things outside the tool: xmllint canonicalises both the original and the output, and Python's ElementTree compares the trees with whitespace-only text normalised away. All 15 corpus documents come out unchanged.
Because it has text in it. Putting its children on their own lines would insert whitespace inside that text, and in XML the whitespace inside a text node is content. An element whose children are all elements is indented normally.
It is honoured, for the element and everything under it, and the page names every element carrying it so you can see that its whitespace was left alone. The version this replaces ignored the attribute entirely.
Nothing. Every character in one is data, including the whitespace, so it is written back exactly as it was. The previous formatter re-indented it, which changed the text of the element containing it.
Because two readers are asked. The browser's own DOMParser is the authority on what a browser will do with your file, and a checker runs alongside it to say where and why: a line, a column, the offending line with a caret and a next step. They agree on every document in the test corpus.
Comments and processing instructions, because JSON has neither, and both are named on the page rather than dropped quietly. The mapping for everything else is stated: attributes under @name, text under #text, and repeated children of one name as an array.
Your text is processed locally in the browser. Nothing you paste or open is transmitted or logged.