JSON to XML Converter

Convert JSON to XML online free. Keeps long IDs and trailing zeros exact, escapes correctly, renames keys XML cannot use, and runs entirely in your browser.

Runs in your browserNothing uploadedFree · no signup
Write null as

Numbers are written exactly as you typed them, so a price of 1.50 and a 20-digit ID keep every character. Keys that are not legal XML names are renamed and the change is listed, and anything the mapping cannot carry across is reported rather than dropped quietly.

Frequently asked questions

How do I control which keys become attributes?
Any key starting with @ becomes an attribute on its element, so { "@id": "bk101", "title": "..." } gives <book id="bk101"><title>...</title></book>. You can switch the marker to _ or $, or turn attributes off entirely so that every key becomes an element. The key called #text becomes the element's own text, which is what lets an element carry both attributes and a value. This is the exact mirror of the XML to JSON converter, so output from one feeds straight back into the other.
What happens to my arrays?
An array becomes repeated sibling elements, which is the only thing XML has that behaves like a list: { "item": ["a", "b"] } becomes <item>a</item><item>b</item>. Two consequences follow and both are reported. An empty array produces nothing at all, so an empty list and a missing key look identical afterwards. And an array sitting directly inside another array has no key to take a name from, so its entries are written as <item> - a name this tool invents rather than one from your data. You can change that name.
Why did my key get renamed?
Because an XML element name is far narrower than a JSON key. A name cannot start with a digit and cannot contain a space or most punctuation, so "first name" has to be written <first_name> and "2024" has to become <_2024>. Every rename is listed. The case worth watching for is two sibling keys that end up with the same name - "first name" and "first_name" both give <first_name> - because read back that is a two-item array rather than two fields, so it is called out separately.
Will a long ID or a price like 1.50 survive?
Yes. The JSON is parsed with every number kept as the text you wrote, and that text is what gets written out, so 1.50 stays 1.50 and a 20-digit order ID keeps all twenty digits. A converter that runs your JSON through JSON.parse first cannot do this: it rounds anything past 2^53 to the nearest double and rewrites 1.50 as 1.5, which quietly damages IDs, version pins and money.
How is null handled?
XML has no null, so you choose. An empty tag is the default and the honest caveat is that it reads back as an empty string. xsi:nil="true" marks the element explicitly and adds the one namespace declaration it needs to the root element, which is the right choice if a schema or a typed reader is at the other end. Leave out removes those elements entirely, so the key is simply absent.
Is the output valid XML?
Yes, and that is not automatic. Ampersands and angle brackets are escaped, including every > - a literal one closing the sequence ]]> is a parse error, not a stylistic choice. Carriage returns are written as &#13; and tabs and newlines inside attribute values as &#9; and &#10;, because a parser turns the literal characters into line feeds and spaces before your code ever sees them. Characters XML 1.0 cannot hold at all, such as most control codes, are reported rather than written into a document that would not parse.
Is my JSON uploaded anywhere?
No. The JSON is parsed and converted entirely in your browser and nothing is sent to a server, so an API payload or a config file holding hostnames and keys never leaves your device.