JSON ↔ XML Converter
Convert JSON to XML or XML to JSON with a single click. Handles nested objects, arrays, attributes, and text nodes. Runs entirely in your browser.
Input
How it works
- JSON → XML: objects become elements, arrays repeat the element, scalars become text; attributes are not used (clean 1:1 mapping).
- XML → JSON: elements become objects, repeated element names become arrays, text-only elements become strings, and attributes appear under
@attrkeys. - Output is indented for readability and valid in both directions for the data shapes shown here.
About JSON ↔ XML Converter
JSON and XML both describe hierarchical data, but with very different conventions: JSON has objects, arrays, and a compact syntax, while XML has elements, attributes, text nodes, and namespaces. Converting between them is common when integrating JSON-first APIs with XML-based systems — SOAP web services, legacy enterprise middleware, RSS/Atom feeds, or configuration formats like Maven POM files.
No mapping is perfectly lossless in both directions: JSON has no notion of attributes, so this tool uses plain elements on the way out and puts XML attributes under @-prefixed keys on the way in; repeating XML elements collapse into arrays. Whitespace-only text nodes are dropped. For exotic documents (mixed content, namespaces, CDATA) review the output — but for typical API payloads the round trip is clean. Everything runs locally in your browser.
Why the two structures do not line up
JSON has objects, arrays and scalars. XML has elements, attributes, text and namespaces. There is no array in XML, so an array has to be expressed as repetition: the same element name appearing as several siblings, which is what this converter emits for `{"items": [...]}` — one `<items>` per element, at the same indent level. There is also no attribute concept in JSON, so on the way out nothing becomes an attribute; the mapping stays element-only in that direction.
The reverse direction has more room, and it uses the two conventions real tools settle on: an attribute becomes a key prefixed with `@`, and a name that appears more than once becomes an array. Both are conventions, not parts of XML — the parser accepts any key — so a document that already contains keys starting with `@` will collide with them on the way in.
Reading XML back, and the one asymmetry to watch
Parsing uses the browser's own `DOMParser` in `text/xml` mode, so malformed input surfaces as a parser error rather than a silent misread. An element with no element children collapses to its trimmed text, or to `null` when that text is empty. Text and CDATA nodes are both read as node types 3 and 4 and concatenated before trimming, so a CDATA section becomes an ordinary string with no record that it was one. The root element's name becomes the single top-level key of the resulting object.
The asymmetry is the array rule. A name that appears exactly once stays a scalar, and only the second occurrence promotes the value to an array — so `<items><item>a</item></items>` comes back as a scalar rather than a one-element list, and a document whose item count is data-dependent produces a shape that changes with the data. Whitespace-only text between child elements is dropped by the trim, which is what keeps pretty-printed XML from producing noise keys.
Name sanitising, and the collisions it creates
Element names are filtered against `[^a-zA-Z0-9._-]`, with anything else replaced by an underscore and an empty result becoming `item`. That keeps output well-formed for most inputs, but it is many-to-one, so `user name` and `user_name` both become `user_name` and their contents merge into one element on the way back. A key like `@type` becomes `_type`, losing the marker that would have made it an attribute. The filter also permits a leading digit, which XML does not, so a key of `1st` produces a document no strict parser accepts.
The genuine losses are worth stating plainly. `null`, `[]` and `{}` all serialise to the same empty element and all read back as `null`, so three distinct inputs are indistinguishable in the XML. Namespaces are not resolved — a prefixed name is read using its prefixed `nodeName`, so `soap:Envelope` becomes a literal key containing a colon, and `xmlns` declarations appear as ordinary attributes. Mixed content, where text and elements interleave, keeps the text only when there are no element children. For typical API payloads the round trip is clean; for documents relying on any of the above, check the output against the real consumer.
Frequently Asked Questions
How do I convert JSON to XML?
Can I customise the XML element names?
Is my data sent to a server?
Do I need an account or API key?
Can I use these tools offline?
All processing happens in your browser. No uploads, no tracking, no servers. Your API keys, configs, and private payloads stay private — 100% client-side.