Convert JSON to XML

Runs on your device · Your file never leaves your device.

Paste or drop JSON and get an XML document with a declaration on top and one element per key. A document with a single top-level key uses it as the root element; anything else goes inside <root>. A list becomes repeated elements named after its key — "items": [..] gives several <items> elements — and a top-level list becomes <item> elements under <root>.

Keys that start with @ become attributes and a "#text" key becomes the element’s text — the shape the XML to JSON tool writes, so a document converted there comes back here as the same XML. Every other value is text inside its element, null becomes an empty element, and the document is indented two spaces per level. Keys that XML does not allow as names — starting with a digit, containing spaces or symbols — are sanitised with underscores so the result always parses.

Text is escaped correctly (&, <, > and, in attributes, quotes and line breaks); control characters, which XML 1.0 cannot hold at all, are removed. The encoding is UTF-8, and you see the first 200 lines before downloading. Nothing is uploaded.

How to convert JSON to XML

  1. Drop a JSON file, or paste JSON into the box.
  2. Press Convert to XML.
  3. Check the preview and download the .xml.

Supported formats and limits

Input
JSON (.json) — a file or pasted text
Output
XML 1.0, UTF-8, declaration on top, pretty-printed
Root
The single top-level key, else <root>; a top-level list becomes <item> elements
Lists
Repeated elements named after the key
Where it runs
In your browser; nothing uploaded

Not for: Matching a specific XML schema (SOAP, RSS, an invoice standard) — the element names follow your JSON keys, not a schema.

How your keys become element names

A key that starts with @ becomes an attribute and a "#text" key becomes the element's text, so {"item": {"@id": 3, "#text": "A"}} gives <item id="3">A</item>. When the document has a single top-level key, that key is the root element; otherwise everything goes inside <root>.

A character that XML does not allow in a name becomes an underscore, and a name that starts with a character not allowed first, such as a digit, gets one in front: "1st place" becomes <_1st_place>. A colon is kept only when its prefix is declared higher up, as in "@xmlns:soap"; an undeclared "soap:Body" becomes <soap_Body>, because no namespace-aware parser would read it otherwise. Letters from any script are allowed, so a key such as "اسم" or "名前" stays as written.

What the values look like

Every value is written as text, and numbers exactly as the JSON has them: 1.0 stays 1.0 and 12345678901234567890 keeps every digit. null and an empty object both become an empty element such as <note/>, and an empty list writes nothing at all, so the XML cannot tell these three apart.

Control characters, codes below 32 other than tab, line feed and carriage return, cannot be written in XML 1.0 at all, not even as a number such as &#1;, so they are removed. A carriage return is written as &#13; so a parser keeps it. In attribute values, quotes, tabs and line breaks are also written as references, because a parser would otherwise turn them into spaces.

Lists of lists lose their grouping

Repeated elements can express only one level of list. "m": [[1, 2], [3]] becomes three <m> elements holding 1, 2 and 3, and the fact that 1 and 2 belonged together is gone. A top-level list behaves the same way: [1, [3, 4]] gives three <item> elements. If the grouping matters, wrap each inner list in an object first: [{"values": [1, 2]}, {"values": [3]}] gives two <item> elements, each holding its own <values>.

Going from XML to JSON and back

A document that went through /xml-to-json comes back as the same elements, attributes, namespace prefixes and text, with no extra wrapper around it. What the JSON never held does not come back: comments and the DOCTYPE, the position of text between child elements, and the order between elements of different names, which come back grouped by name. If type detection was on in /xml-to-json, a value such as TRUE comes back as true; switch detection off there for a word-for-word round trip.

Frequently asked questions

Are my files uploaded to a server?
No. This conversion runs inside your browser using your own device’s processing power, and the file is not uploaded. Once a tool has been used once (video, text recognition and background removal download their engine from this site the first time), it keeps working when your connection drops.
How are lists represented?
As repeated elements. {"items": [1, 2]} becomes <items>1</items><items>2</items>. A list at the very top of the document becomes <item> elements inside <root>. An empty list produces no element at all.
What about keys with spaces or digits?
XML element names cannot start with a digit or contain spaces. Such keys are sanitised: "1st place" becomes _1st_place, "unit price" becomes unit_price. Everything else is kept as is.
Can I get attributes instead of child elements?
Yes: put @ in front of the key. {"item": {"@id": 3, "name": "A"}} gives <item id="3"><name>A</name></item>. It is the shape the XML to JSON tool writes, so the round trip gives back the same document.

Related tools

More in Spreadsheets & data

This page in other languages: العربية · Deutsch · Français · Español · Русский · Português · 中文 · हिन्दी · Türkçe · עברית · فارسی · اردو · Bahasa Indonesia · বাংলা