JSON to XML Converter
Turn JSON into well-formed XML: pick the root and array-item element names, map @keys back to attributes, and let the converter fix keys that aren't legal XML names.
JSON to XML Converter
Runs in your browser — nothing you enter is uploaded or stored.
Scratchpad auto-saved
How it works — in four simple steps
No signup and nothing to install — it all runs in your browser.
Add your JSON
Paste it into the left box, press Open file, or drag a .json file onto it. Sample loads a realistic example.
Set the options
Adjust the options above the boxes — the output updates instantly as you change them.
Check the result
Read the status line: it reports rows, keys and any value that couldn't be represented in XML.
Copy or download
Copy the XML or download it as a .xml file. Nothing was uploaded at any point.
Keys that start with @ become attributes and #text becomes the element's text — the same convention the XML to JSON converter uses, so round trips are lossless in shape.
Features
Your element names
Set the root element and the name used for each array item, and invalid characters are fixed for you so the XML stays well-formed.
Attributes kept, clearly marked
XML attributes become keys with an @ prefix (or _ / - / none), so they never collide with child elements of the same name.
Declaration on demand
Include or omit the <?xml version="1.0" encoding="UTF-8"?> line.
CDATA when you want it
Text containing < or & can be wrapped in CDATA sections instead of being escaped.
Private by design
Parsing and conversion run in your browser with JavaScript — your data is never uploaded, logged or stored.
About the JSON to XML Converter
Going from JSON to XML is mostly mechanical — every key becomes an element — but three things need a decision. XML must have exactly one root element, while JSON can be an array or an object with many keys. JSON arrays have no element name of their own. And JSON keys can be anything ("first name", "2024", "a/b") while XML names can't contain spaces or start with a digit.
The converter handles these the way most XML tooling expects. If your JSON is an object with a single top-level key, that key becomes the root; otherwise everything is wrapped in the root element you name (default <root>). An array under a key repeats that key's element once per entry — "tag": ["a","b"] gives two <tag> elements — and a bare top-level array uses the array-item name (default <item>). Keys that begin with the attribute prefix (@ by default) become attributes, and #text becomes the element's text, so XML you converted to JSON here converts back to the same shape.
Illegal characters in names are replaced with underscores and names starting with a digit get a leading underscore, so the output always parses. Text is escaped (&, <, >; quotes in attributes), or wrapped in CDATA if you prefer. null becomes an empty element and booleans and numbers are written as their JSON text.
Examples
A typical API payload: an order object with attributes marked by @, a nested customer and an array of line items.
{
"order": {
"@id": "A-1042",
"@currency": "EUR",
"placed": "2026-10-20T14:05:00Z",
"customer": { "name": "Ada Lovelace", "email": "ada@example.com" },
"line": [
{ "@sku": "TF-MUG", "qty": 2, "price": 12.5 },
{ "@sku": "TF-TEE", "qty": 1, "price": 19 }
],
"note": "Leave at the door & ring twice",
"gift": false
}
}<?xml version="1.0" encoding="UTF-8"?>
<order id="A-1042" currency="EUR">
<placed>2026-10-20T14:05:00Z</placed>
<customer>
<name>Ada Lovelace</name>
<email>ada@example.com</email>
</customer>
<line sku="TF-MUG">
<qty>2</qty>
<price>12.5</price>
</line>
<line sku="TF-TEE">
<qty>1</qty>
<price>19</price>
</line>
<note>Leave at the door & ring twice</note>
<gift>false</gift>
</order>This output was produced by the converter on this page with the default options — load it with the “Order” preset above and change any option to see the effect.
How JSON maps to XML
| In JSON | Becomes in XML |
|---|---|
{"title": "Dune"} | <title>Dune</title> |
Key starting with @: "@id": 7 | attribute id="7" on the parent |
"#text": "9.99" | the element's text content |
"tag": ["a", "b"] | <tag>a</tag><tag>b</tag> |
Top-level array [{…}, {…}] | <root><item>…</item>…</root> |
null | empty element <x/> |
Key "first name" or "2026" | <first_name>, <_2026> — always a legal XML name |
"a < b & c" | a < b & c (or CDATA) |
Things that trip people up
- Arrays of arrays. XML has no anonymous lists, so a nested array like
[[1,2],[3,4]]uses the item element for the inner lists. If the consumer expects specific names, rename the item element. - Key order. Elements are written in the order the keys appear in your JSON. XML Schemas with
xs:sequencecare about order; JSON parsers usually don't, so check the order if a schema validates the output. - Numbers lose their type. XML has no number type — 1988 and "1988" both become the text 1988. The receiving system decides the type, usually from an XSD.
- Reserved names. Names beginning with
xml(any case) are reserved by the XML spec. They still parse in practice, but avoid them for elements you define.
JSON vs XML at a glance
| Property | JSON | XML |
|---|---|---|
| Specification | RFC 8259 (2017) · ECMA-404 | XML 1.0 Fifth Edition (W3C, 2008) |
| File extension | .json | .xml |
| Media type | application/json | application/xml (RFC 7303) |
| Data types | string, number, boolean, null, object, array | text only (types come from a schema) |
| Comments | No | Yes <!-- --> |
| Nesting | Unlimited | Unlimited |
- JSON: Numbers are parsed as IEEE-754 doubles in JavaScript, so integers above 9,007,199,254,740,991 (2⁵³ − 1) lose precision.
- XML: A document has exactly one root element; element names can't start with a digit, and only five entities (& < > " ') are predefined.
Frequently asked questions
5 answersHow do I make a JSON key an XML attribute?
{"book": {"@isbn": "123", "title": "Dune"}} gives <book isbn="123"><title>Dune</title></book>. The prefix is configurable.