XML Formatter
Pretty-print XML without corrupting mixed content, CDATA or comments — entirely on this device.
The formatter changes whitespace only — mixed content, CDATA and comments stay byte-identical.
Press ? for shortcuts
Do it offline:$ xmllint --format file.xml
How to use it
- Paste XML or drop a file — .xml, .svg, .plist, .wsdl and .rss all parse identically; beyond 2 MB an explicit button states the size first.
- Pick 2-space, 4-space or tab indentation and an attribute-wrap policy, or switch to the Minify tab for one machine-ready line.
- A malformed document produces a verbatim diagnostic — line, column, code frame, caret — while the input pane keeps your bytes untouched.
- Copy the result, download it as a UTF-8 .xml file, or share the tool state as a link.
XML has a property JSON never had: whitespace inside an element can be data. Pretty-printers that re-indent everything quietly rewrite that data. This formatter re-emits your document with new whitespace only where content is element-only — mixed content, CDATA sections and comments come back byte-identical — and the work happens on this device, so nothing you paste is transmitted anywhere.
Examples
<order id="9001" status="shipped" priority="2" channel="web" market="eu"><item sku="KB-42" qty="1"/></order><order id="9001"
status="shipped"
priority="2"
channel="web"
market="eu">
<item sku="KB-42" qty="1"/>
</order>Five attributes cross the beyond-4 threshold: the first stays on the tag line, the rest wrap one per line, one indent unit deep. The two-attribute item element stays inline.
<p>Hello <b>world</b>!</p><p>Hello <b>world</b>!</p>Output equals input, byte for byte. The space after Hello is character data — re-indenting would move it — so the span is emitted verbatim and a chip reports “1 mixed-content region kept byte-identical”.
<query><![CDATA[SELECT * FROM users WHERE age < 30 AND bio LIKE "%<b>%"]]></query><query><![CDATA[SELECT * FROM users WHERE age < 30 AND bio LIKE "%<b>%"]]></query>Inside a CDATA section the comparison operator and the angle brackets are plain characters, not markup — the element counts as mixed content and survives untouched.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
Element-only vs mixed content — the region law
Whitespace is rewritten only where it cannot be data: inside elements whose children are exclusively other elements, comments or processing instructions, and at document level. One significant character — or any CDATA section — marks a region mixed, and its whole span is reproduced from the source. xml:space="preserve" freezes its entire subtree, tags included; in this first version a descendant xml:space="default" does not switch formatting back on.
Why your DOCTYPE is never fetched
A DOCTYPE naming a SYSTEM or PUBLIC identifier is the classic XXE vector: resolving parsers can be tricked into reading local files or calling internal hosts. This engine has no network path — the DOCTYPE rides through as one verbatim token, entities are checked for spelling but never expanded, and a chip states “external DTD is never fetched — passed through verbatim”.
Encoding labels: rewritten when formatting, untouched when minifying
Formatted output is always UTF-8 text, so a declaration claiming encoding="ISO-8859-1" would lie about the file you download. Format mode rewrites the label to UTF-8 and a warning chip names the original; Minify changes no declaration bytes. A version="1.1" declaration is processed under XML 1.0 rules, with a notice.
Namespace prefixes are names, not decoration
A prefixed tag like soap:Envelope resolves against the xmlns:soap declaration in scope, and signed documents hash the prefixed bytes. Renaming prefixes is a semantic edit, so this page never performs one — prefixes and xmlns attributes come back exactly as pasted.
SVG, RSS, .plist, .wsdl — one grammar, honest limits
Any well-formed XML dialect formats the same way here, and an SVG with inline text benefits directly from the mixed-content rule. A dedicated SVG Optimizer is a separate planned tool — this page only ever moves whitespace — and validating against an XSD or running XSLT is not offered today.
Common errors
Closing tag '</config>' at line 1, column 16 — '<item>' opened at line 1, column 9 is still open; did you forget '</item>'?- XML nesting is strictly last-opened, first-closed, and the diagnostic pairs both positions so you can see which level broke. Pastes from HTML — where some tags close implicitly — are the usual culprit.
Bare '&' at line 1, column 9 — probable cause: a literal ampersand; write '&' (entities look like '&name;', ' ' or '😀').- An ampersand always begins an entity reference; query strings pasted into attributes are the everyday source. Spell the character & and the document parses.
Unterminated comment at line 1, column 4 — probable cause: missing '-->'.- Everything after <!-- was consumed while scanning for the closing marker, so the position points at where the comment began. XML also forbids a double hyphen inside a comment body.
This tool formats up to 50MB; beyond that, try the CLI: xmllint --format file.xml- Refusing the whole input beats formatting a slice — a truncated document is a different document. xmllint ships with macOS and most Linux distributions.
FAQ
Can formatting change what my XML actually says?
Not on this page. Re-indentation happens only between elements, where whitespace has no meaning; the moment text or CDATA appears in a region, that region is reproduced byte-for-byte. The build re-executes every printed example through the engine.
How does the Minify tab differ from a dedicated minifier?
Minify here removes whitespace-only text between elements and stops: mixed content, CDATA, comments, processing instructions, the DOCTYPE and the declaration keep their bytes. An aggressive comment-stripping minifier is a different contract.
Is pasting XML with a DOCTYPE or entities safe here?
Yes. Nothing is fetched and nothing is expanded — the engine has no network capability, entity references only pass a syntax check, and external identifiers are surfaced in a chip, never resolved.
Is an XML beautifier different from an XML formatter?
They are the same tool under different names — beautifier and pretty-printer stress the indentation, formatter the whole rewrite. The property worth comparing is what a tool refuses to change.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Format or minify now — mandatory past 2 MB.
- ⌘/Ctrl + S
- Download the output as a UTF-8 .xml file.
- ⌘/Ctrl + C
- Copy the entire output when nothing is selected.
- ⌘/Ctrl + Shift + C
- Force-copy the full output despite a selection.
- t
- Switch the theme (idle while typing in a pane).
- ? or ⌘/Ctrl + /
- List every binding in a help overlay.
- Esc
- Dismiss the topmost dialog — input stays.