Quick answer: paste XML on the left and the JSON appears instantly. Elements become keys, attributes land under _attributes, text under _text, repeated elements become arrays. Flip the toggle and the same engine converts JSON back to XML. It's powered by xml-js 1.6.11 (36 KB, runs in this tab) — a 254-byte catalog XML comes out as 710 bytes of pretty JSON and converts back byte-for-byte.

Convert

XML input0 bytes
Drop an .xml or .json file, or click to open
Ad
JSON output0 bytes

Ready. Nothing you paste leaves this page.
Ad

How xml-js Maps XML to JSON

XML constructExampleJSON (compact mode)
Element<book>…</book>"book": { … }
Attribute<book id="bk101">"_attributes": {"id": "bk101"}
Text content<price>44.95</price>"price": {"_text": "44.95"}
Repeated elementstwo <book> siblings"book": [{…},{…}] (array)
Declaration<?xml version="1.0"?>"_declaration": {…}
Comment<!-- note -->"_comment": "note"
CDATA<![CDATA[raw]]>"_cdata": "raw"
Processing instruction<?php echo 1;?>"_instruction": {…}

Verbose mode keeps the document as an elements tree with type, name, and attributes fields on every node — closer to the DOM, handier for walking, heavier to read. Compact mode is what most APIs and fixtures want. The underscore key names are fixed on this page; if your downstream schema forbids them, rename the keys after converting.

How the Converter Works

The page runs xml-js 1.6.11 (MIT), the same engine widely used for config and fixture conversion, bundled to 36 KB with its sax parser and loaded from this site. Parsing happens in your tab: XML goes in through xml2js, JSON comes out through serialization; the reverse direction parses JSON first and rebuilds markup with json2xml. The active direction reruns on every keystroke, and errors surface as messages instead of silent empty output.

A worked example, measured

Take a 254-byte catalog with two books, each carrying an id attribute, an author, a title, and a priced element with a unit attribute:

That round-trip property is why this pairing is safe for round-tripping fixture data: convert, store as JSON, regenerate the XML when a legacy consumer needs it. It's also the honest answer on size — JSON repeats key names and wraps attributes and text, so element-heavy XML roughly triples in bytes going to pretty JSON. Attribute-heavy XML shrinks instead.

What converts, and what to watch

Credits and licenses

Conversion by xml-js 1.6.11 (MIT) with the sax 1.6.1 parser (BlueOak-1.0.0), bundled under /vendor/ with license texts. Nothing executes outside your browser tab.

Edge Cases, Tested

The mapping table above covers the happy path. Real files are messier, so here's what this page's engine actually does with the awkward bits. Each row was run through the same xml-js build the converter loads, in compact mode, then converted back to XML.

XML inputJSON output (compact)Back to XML
<a></a>{"a":{}}<a/>
<a> </a>{"a":{}}<a/> (whitespace-only text dropped)
<a> padded </a>{"a":{"_text":" padded "}}identical
<a id="7">text</a>{"a":{"_attributes":{"id":"7"},"_text":"text"}}identical
<ns:b xmlns:ns="urn:x">1</ns:b>{"ns:b":{"_attributes":{"xmlns:ns":"urn:x"},"_text":"1"}}identical
<a>&lt;tag&gt; &amp;</a>{"a":{"_text":"<tag> &"}}identical (re-escaped)
<a><![CDATA[<raw> & stuff]]></a>{"a":{"_cdata":"<raw> & stuff"}}identical
<a><b>1</b><c>x</c><b>2</b></a>{"a":{"b":[{"_text":"1"},{"_text":"2"}],"c":{"_text":"x"}}}<a><b>1</b><b>2</b><c>x</c></a> (reordered)
<p>Hello <b>world</b> again</p>{"p":{"_text":["Hello "," again"],"b":{"_text":"world"}}}<p>Hello again<b>world</b></p> (mixed content broken)
<a>&nbsp;</a>{"a":{}}<a/> (HTML entity silently dropped)

Two rows deserve a second look. The reordered siblings and the mangled paragraph both come from the compact format itself: a JSON object can only hold one "b" key, so every <b> gets pooled into one array and its position among other elements is lost. Switch Structure to verbose and both round-trip exactly, because verbose mode stores children as an ordered elements list. The &nbsp; row matters if you're converting XHTML or hand-written feeds. XML only knows five named entities, and anything else, like &nbsp; or &copy;, disappears without a warning. Use the numeric form (&#160;) if you need it kept.

Common pitfalls when going JSON to XML

Frequently Asked Questions

How do I convert XML to JSON online?

Paste your XML into the left pane or drop an .xml file on the page. The xml-js engine streams it through the sax parser and builds JSON as you type, all inside your browser tab. Attributes go under an _attributes key, text under _text, and repeated elements become arrays. Pick Compact or Verbose structure and an indent, then copy or download the result.

What gets lost when converting XML to JSON?

Less than you might expect: comments, CDATA sections, processing instructions, and the DOCTYPE are all kept as _comment, _cdata, _instruction, and _doctype keys. The XML declaration is dropped by default, but setting Ignore declaration to No keeps it as _declaration. What compact mode can't keep is the position of interleaved siblings, so mixed content like a paragraph with inline bold text gets split apart. Whitespace-only text nodes are also dropped. Verbose mode preserves ordering exactly.

Can the converter go back from JSON to XML?

Yes. Flip the toggle to JSON → XML and the same engine rebuilds the markup. With data-style XML the round trip is exact: the sample catalog converts to 710 bytes of JSON and back to the same XML byte for byte, as long as you use the same indentation both ways. Keep the Structure setting the same as the JSON you paste, or the output will be empty or full of odd tags.

Why is one element an object but two elements an array?

That's how compact mode works. A single <book> becomes "book": {…}, and as soon as a second <book> sibling appears, it becomes "book": [{…},{…}]. Code that reads data.catalog.book[0] will break on a file with only one book. Either normalize to an array in your own code, or use verbose mode, where children are always an elements array.

Are numbers and booleans converted to JSON types?

No. Every text value and attribute stays a string, so <price>44.95</price> becomes {"_text":"44.95"} and <flag>true</flag> becomes {"_text":"true"}. XML has no types without a schema, and guessing can do damage, like turning a ZIP code of 02134 into 2134. Parse the values you need in your own code.

Why do I get "Converting circular structure to JSON"?

That message almost always means an element was never closed, such as <a><b>1</b> with no </a>. The parser leaves the open element half-built, and the JSON step then trips over it. Other mistakes get clearer errors: a mismatched close tag reports Unexpected close tag, and an unquoted attribute reports Unquoted attribute value. Check the last few tags of the document first.