XML Formatter & Validator
Paste XML or open an .xml file and get clean, indented XML as you type. Every error is shown with its line and column and a plain-English hint. Minify XML to one line, convert it to JSON, or test an XPath query. Everything runs in your browser.
XPath tester
Run an XPath 1.0 expression on the XML above. Prefixes declared in the document work as they are; use x: for the default namespace.
What the formatter does
Before
<?xml version="1.0"?><order id="A-1042"><customer><name>Ana Silva</name><email>[email protected]</email></customer><items><item sku="KB-01" qty="1">Keyboard</item><item sku="MS-07" qty="2"/></items><note>Leave at the <b>back</b> door</note></order>
After
<?xml version="1.0"?>
<order id="A-1042">
<customer>
<name>Ana Silva</name>
<email>[email protected]</email>
</customer>
<items>
<item sku="KB-01" qty="1">Keyboard</item>
<item sku="MS-07" qty="2"/>
</items>
<note>Leave at the <b>back</b> door</note>
</order>
- It checks first. Your browser's XML parser reads the document. If it is not well-formed, you get the line, the column, the place marked with
^and a hint, instead of a half-formatted result. - One element per line, indented by its depth. Elements that hold only text, like
<name>Ana Silva</name>, stay on one line. - Mixed content stays as it is. In
<note>Leave at the <b>back</b> door</note>the spaces are part of the text, so the formatter does not add line breaks there. The same is true for any element withxml:space="preserve". - Nothing else changes: text, attribute values and their quotes,
<![CDATA[ ]]>sections, entities like&, comments, the XML declaration and the DOCTYPE are kept exactly. - Minify removes the white space between elements (and comments, if you tick "Remove comments"), so the XML fits on one line for a request body, a test fixture or a database field.
Common XML errors and how to fix them
The page explains every error in plain English. The message itself comes from your browser's parser, so the words differ a little: Chrome and Edge say "Unexpected closing tag", Safari says "Opening and ending tag mismatch", Firefox says "mismatched tag". These are the problems behind most of them.
| Problem | Typical message | Fix |
|---|---|---|
A tag is closed in the wrong order, or the closing tag has a typo. Names are case-sensitive: <Item> is not closed by </item>. | Unexpected closing tag: item != Item | Close the inner element first: <a><b></b></a>. |
A bare & in text or in a URL inside an attribute. | Unexpected token inside entity / EntityRef: expecting ';' | Write &: ?a=1&b=2. |
An HTML entity such as . XML only knows & < > " '. | Unexpected entity: nbsp / Entity 'nbsp' not defined | Use the number:  , or the character itself. |
A < in text (for example a < b), or a name that starts with a digit. | Qualified name is invalid / StartTag: invalid element name | Write <, or put the text in <![CDATA[ ... ]]>. |
An attribute without quotes (id=7) or without a value. | Unexpected token: 7 / AttValue: " or ' expected | Quote every value: id="7". |
| More than one root element, or text after the root. | Unexpected characters outside the root element / Extra content at the end of the document | Wrap everything in one element. |
Spaces, an empty line or a second declaration before <?xml ... ?>. | Invalid processing instruction: <?xml / XML declaration allowed only at the start | Make the declaration the very first characters of the file. |
A prefix such as soap: is used, but no xmlns:soap="..." declares it. | Element soap:Body prefix is unbound / Namespace prefix soap is not defined | Add the declaration on the element or on the root. |
| The text ends before every element is closed, often because a copy was cut off. | Unexpected end of stream / Premature end of data | Add the missing closing tags. |
XPath cheat sheet
| Expression | Selects |
|---|---|
/catalog/book | book elements that are direct children of the root catalog |
//book | every book element, at any depth |
//book[1] | the first book of each parent (positions start at 1) |
//book[last()] | the last book of each parent |
//book/@id | the id attribute of every book |
//book[@lang='en'] | books whose lang attribute is en |
//book[price > 30] | books with a price child above 30 |
//title/text() | the text inside every title |
//book[contains(title, 'XML')] | books whose title contains "XML" |
//*[local-name()='item'] | item elements in any namespace |
count(//book), sum(//price) | a number instead of nodes |
//title/.. | the parent of every title |
Browsers support XPath 1.0. Functions from XPath 2.0 and 3.1, such as matches() or lower-case(), are not available here; for case-insensitive matching use translate().
How XML becomes JSON
XML
<book id="bk101"> <title>XML Guide</title> <tag>xml</tag> <tag>reference</tag> <price currency="USD">44.95</price> </book>
JSON
{
"book": {
"@id": "bk101",
"title": "XML Guide",
"tag": ["xml", "reference"],
"price": {
"@currency": "USD",
"#text": "44.95"
}
}
}
Attributes get an @ in front, so they never clash with child elements of the same name. Repeated elements become an array, but a single element does not, so check for both if your data can have one or many. Comments and processing instructions are left out. Need the other direction or another format? See JSON Formatter, YAML to JSON and CSV to JSON.
Format XML in your editor and on the command line
| Tool | How |
|---|---|
| VS Code | Install an XML extension (for example "XML" by Red Hat), then Shift+Alt+F |
| IntelliJ IDEA and other JetBrains IDEs | Ctrl+Alt+L (Reformat Code) |
| Notepad++ | Plugin "XML Tools", then Ctrl+Alt+Shift+B (Pretty print) |
| Eclipse | Ctrl+Shift+F |
| xmllint (Linux, macOS) | xmllint --format in.xml > out.xml (check only: xmllint --noout in.xml) |
| Python | python -c "import sys,xml.dom.minidom as m;print(m.parse(sys.argv[1]).toprettyxml())" in.xml |
| PowerShell | ([xml](Get-Content in.xml -Raw)).Save("out.xml") |
| xmlstarlet | xmlstarlet fo in.xml, and XPath: xmlstarlet sel -t -v "//book/title" in.xml |
Frequently asked questions
How do I format XML?
Paste the XML in the first box, or open or drop an .xml file. The page checks it and shows the formatted XML at once in the second box: every element on its own line, indented by its depth. Choose 2 spaces, 4 spaces or tabs, then copy the result or download it as an .xml file.
What is the difference between well-formed and valid XML?
Well-formed XML follows the basic syntax rules: one root element, every tag closed in the right order, attribute values in quotes, and & and < written as & and < in text. Every XML parser needs this. Valid XML is well-formed and also matches a schema (an XSD or a DTD) that says which elements and attributes are allowed. This page checks that XML is well-formed. It does not check it against a schema.
Why do I get "Entity 'nbsp' not defined"?
, ©, — and similar names come from HTML. XML only knows five named entities: & < > " and '. Write the character itself (XML files are usually UTF-8) or its number instead:   for a non-breaking space, © for the copyright sign and — for a long dash.
Does formatting change my XML?
Only the white space between elements changes. Text, attribute values, CDATA sections, entities such as & and comments stay exactly as they are. Elements that mix text and child elements (like <p>Hello <b>world</b></p>) and elements with xml:space="preserve" are kept on one line, because the spaces inside them can be part of the content.
How is XML converted to JSON?
Each element becomes a key. Attributes become keys that start with @, for example "@id". When an element has both attributes and text, the text goes into "#text". Elements with the same name under one parent become an array. An element with only text becomes a plain string. By default all values stay strings; tick "Numbers and true/false as values" to turn 42 and true into JSON numbers and booleans.
Why does my XPath find nothing?
The most common reason is a default namespace: if the root element has xmlns="...", every element is in that namespace and //item finds nothing. On this page you can use the prefix x: for the default namespace (//x:item), or match the local name: //*[local-name()='item']. Other prefixes declared in the document, such as soap: or atom:, work as they are.
Is my XML uploaded?
No. The XML is parsed by your browser's own XML parser and formatted with JavaScript on this page. Nothing is sent to a server, so you can safely format configuration files, SOAP messages or data exports that contain private data. Only your settings, such as the indent, are kept in this browser for your next visit.