Code Formatting

XML Formatter

Format, compress and pretty-print XML.

Input XML
Formatted result
Formatted result will appear here

What is XML Formatter?

XML (eXtensible Markup Language) is a markup language for structured data. The XML formatter beautifies XML code with proper indentation and validates syntax.

Features

  • Format: Beautify XML with indentation
  • Minify: Remove whitespace for compact output
  • Validate: Check XML syntax
  • Custom Indent: Configurable indentation

Use Cases

  • Configuration files (web.config, pom.xml)
  • API responses (SOAP, RSS)
  • Data interchange formats

XML Formatter re-serialises XML through a JavaScript object model: it parses the markup, then prints it again with one, two, or four spaces of indentation, next to a minified copy and a compression percentage. It suits reading SOAP envelopes, Maven POMs, and IIS or Tomcat config files that arrive as a single unbroken line.

A parse-and-rebuild pass, not a whitespace pass

The formatter never edits your text. fast-xml-parser reads the document into a plain JavaScript object, then XMLBuilder prints that object again with indentation, so anything the parser has no key for is already gone before printing starts. An XML comment disappears, a DOCTYPE declaration disappears, and an empty element written with a trailing slash returns as an open tag plus a close tag because suppressEmptyNode is set to false. A CDATA block is decoded to plain text and re-escaped, so an ampersand inside it comes out as an entity reference. The builder also appends one final newline. That is why a formatted file can differ from the original in content, not only in layout, and why a copy should be kept before overwriting a checked-in configuration.

Numeric-looking values are retyped on the way in

The parser runs with parseAttributeValue enabled and parseTrueNumberOnly disabled, so values are converted to JavaScript types before any printing happens. An XML declaration reading version="1.0" is emitted as version="1", an attribute id="007" becomes 7, qty="1.50" becomes 1.5, and text content like 0042 becomes 42. An attribute whose value is the string "true" turns into a boolean and is printed as a bare attribute name with no equals sign and no quotes, which is not well-formed XML at all. These rewrites are the most frequent surprise: strict readers reject version="1", and a leading-zero order id no longer matches what upstream sent.

Lenient parsing is not validation

The error banner appears only when the parser aborts, which in practice means structural truncation: an unclosed comment, an unclosed CDATA block, or an unclosed processing instruction. The message is the library string itself, for example Comment is not closed. Everything else is repaired in silence. A mismatched pair, with an inner element opened and an outer element closed, is auto-closed; a stray closing tag after the root is discarded; several top-level elements are printed one after another; text containing a bare < sign can even corrupt the element name in the rebuilt output. A clean result therefore means the parser coped, not that the document is valid: DTD and XSD constraints, namespace binding, and entity declarations are never examined.

Worked example

Attribute values retyped during one round trip

Input
<order id="007" count="3"><item sku="A-1" qty="1.50">2</item><!-- rush --></order>
Output
<order id="7" count="3">
  <item sku="A-1" qty="1.5">2</item>
</order>

Two values were rewritten and one node vanished: id lost its leading zeros because the value was parsed as a number, 1.50 collapsed to 1.5, and the comment before the closing tag was never placed in the rebuilt document. The trailing newline comes from the builder, which always ends its output with one.

Limits and pitfalls

  • Indentation is limited to one, two, or four spaces; there is no tab option and no line-width wrapping, so each child element sits on its own line regardless of depth or attribute count.
  • XML comments and DOCTYPE declarations do not appear in the output, so formatting a document that relies on them for entity definitions or build tooling changes it materially.
  • Attribute and text values that look numeric or boolean are retyped: a leading-zero identifier, a fixed two-decimal amount, or a literal true value will not survive a round trip.
  • A clean result is not a validity verdict: mismatched tags are auto-closed and extra top-level elements are accepted, while the banner fires only for unclosed comments, CDATA sections, or processing instructions.
  • The compression percentage divides minified output length by raw input length in JavaScript string units, so CJK text counts one per character regardless of its UTF-8 size, and input that is already minified yields no percentage at all.

Related tools

Which XML path to take: this pane, xmllint, or Prettier

SituationThis pane (fast-xml-parser, rebuilt in the tab)Real alternative
The document is prose with inline markup — SVG text, XHTML, DocBookText sitting beside an inline child does not stay on one line: <p>text <b>bold</b> tail</p> returns with <b> on its own line and the trailing run glued on as texttail, so the space between two words is gone. Element-only configuration is unaffected; running text is not.A tree-preserving printer leaves text nodes where they are and only indents element-only regions: xmllint --format keeps that whole paragraph on one line, and an XSLT indent such as xmlstarlet fo behaves the same. When the file is a document rather than data, this pane is the wrong pass.
A schema or DTD has to accept what comes outThe pane renders documents a validator would reject, and it retypes values on the way: text 1e3 prints as 1000, 0.0000001 prints as 1e-7, and an attribute written "true" prints as a bare attribute name. xs:decimal forbids the exponent form, so input that validated can leave invalid.Print with xmllint --format, which copies text nodes verbatim — 1e3 stays 1e3 — then decide the document is correct with xmllint --noout --schema gateway.xsd wsdl.xml. This pane is for reading; the validator is for verdicts.
Forty XML files must end up in one committed styleOne paste at a time, spaces only, at widths 1, 2 or 4 — the menu is ordered 2, 4, 1 and opens on 2. No tabs, no config file to commit, no glob: the style holds until the tab closes.Prettier with @prettier/plugin-xml and a committed .prettierrc — tabWidth, useTabs: true, xmlWhitespaceSensitivity — reformats a whole glob in one run and can be gated in CI. That is the option the next contributor inherits.
The XML lives on disk, or there are a hundred of themThere is no file input and no batch path: one document per visit, pasted into a textarea, with both panes rebuilt synchronously on every keystroke in the page thread.xmllint --format in.xml -o out.xml reads and writes files directly, and a for loop over *.xml covers a folder. When the source is already a file, piping it through a browser textarea adds a copying step and nothing else.
You want one field out of a 200-entry responseFormatting keeps every element, attribute and nesting level, so the field you are after is still a long scroll away; the pane has no search and no path lookup.The XML to JSON tool on this site turns the same string into an indexable object — feed.entry[3].title — at the cost of comments and an @_ prefix on attributes. Convert when the data is the point; format when the XML itself is the deliverable.
Nothing may be installed, and the payload may not leave the machineParsing and rebuilding both happen in the tab, so a customer envelope reaches no server and closing the tab leaves no copy. That privacy is the one reason to accept the rewriting above for a read-only look.Every command named here needs an install and writes the file somewhere — a repo, /tmp, a shell history. When an install and a disk copy are both forbidden, the pane is all that is left; read the output, and do not ship it.

One concrete scenario

A gateway WSDL pasted out of a log, and eleven declarations that grow

A payment gateway ships its WSDL as one line, and the copy in the ticket is eleven empty <xs:element/> declarations, four comments naming the on-call rotation, and a DOCTYPE. Paste it in at the default two spaces: the document unwraps to one element per line, and the eleven empty declarations come back as open and close pairs — thirteen characters each becoming twenty-five, so the output is 132 characters heavier before any indentation is counted. The DOCTYPE and the four comments never arrive. The compression readout can still show a positive percentage here, because what shrank was content, not whitespace. Read it in the pane, then run xmllint --noout --schema on the copy that goes back into the repo.

Frequently Asked Questions

XML or JSON — which should I use?
For new systems and web APIs, JSON (lighter, universally parsed). XML remains irreplaceable for document markup, SOAP enterprise interfaces, data exchange requiring namespaces and strict XSD validation, and publishing/legal industries. This site has converters between the two.
Does formatting preserve comments and CDATA?
Yes. Formatting only adjusts indentation and line breaks: comments , CDATA sections, and processing instructions are kept verbatim. Text inside CDATA is never re-indented, since that would change the content itself.
What does "XML declaration in wrong position" mean?
must be the very first thing in the document — no spaces, line breaks, or BOM before it. Files exported from other systems commonly have stray whitespace there; delete it and the error goes away.

Content reviewed: