FormatterHQ

JSON to XML Converter

Turn JSON objects and arrays into well-formed XML. Choose the root and item element names, map @ keys to attributes and get escaped, indented output in your browser.

Input JSON
Output XML
Ready.

How to use the JSON to XML Converter

  1. Paste JSON into the input editor, drop or upload a .json file, use Load URL, or click Sample.
  2. Set the Root element and Array item element names, and the Attribute prefix if your keys use something other than @.
  3. Choose an Indent and whether to add the XML declaration, then click Convert to XML (with Auto update on, the output refreshes by itself).
  4. Use Copy or Download to save the XML.

JSON to XML with predictable element names

This JSON to XML converter is for the moment your data is in JSON but the receiving end speaks XML: a SOAP endpoint, a payment gateway, an import screen in an ERP, or a test fixture for an XML parser. Objects become elements, arrays become repeated elements, and a small naming convention lets you produce attributes and mixed content too.

JSON and XML do not map one to one. JSON has arrays and typed values; XML has attributes, element order and a single document root. The rules below explain every decision the converter makes, so the result is not a surprise.

Example: an object with attributes and a list

{
  "product": {
    "@sku": "TX-40",
    "name": "Desk lamp",
    "price": { "@currency": "USD", "#text": 39.9 },
    "colors": ["black", "white"],
    "2nd warranty": null
  }
}

Converted with the default options:

<?xml version="1.0" encoding="UTF-8"?>
<product sku="TX-40">
  <name>Desk lamp</name>
  <price currency="USD">39.9</price>
  <colors>black</colors>
  <colors>white</colors>
  <_2nd_warranty/>
</product>

Four rules are visible here. The single top-level key product became the document element, so no extra <root> wrapper was added. Keys starting with @ turned into attributes. The #text key supplied the text of <price>. And the list of colors was written as two sibling elements that share the key's name.

How JSON structures become XML

JSONXML result
Object key with a scalar valueChild element containing the value as text
Key starting with the attribute prefixAttribute on the parent element
#text keyText content of the parent element
Array under a keyOne element per entry, each named after the key
Array inside an arrayEntries wrapped in the Array item element name
Top-level arrayRoot element holding one item element per entry
null, empty string, empty objectSelf-closing element such as <note/>
Numbers and booleansPlain text: true, 39.9

When does the Root element setting apply? Whenever the JSON is not a single-key object: a top-level array, an object with several keys, a bare value, or a single key whose value is an array. For example, {"users": [ … ]} produces <root> with repeated <users> children, because XML allows only one document element and an array would otherwise create several.

Options

  • Root element – the wrapper name, root by default. Use the name the receiving schema expects, such as orders or Envelope.
  • Array item element – the name for entries of a top-level array and of nested arrays, item by default. Converting [1, 2] with root numbers and item n gives <numbers><n>1</n><n>2</n></numbers>.
  • Attribute prefix – which key prefix marks an attribute. Keep @ for data produced by the XML to JSON converter, or change it (for example to _) if your keys legitimately begin with @.
  • XML declaration – prepends <?xml version="1.0" encoding="UTF-8"?>. Untick it when the fragment will be pasted inside another document.
  • Indent – 2, 3 or 4 spaces, or a tab.

Names and characters that XML rejects

A JSON key can be any string, but an XML element name cannot contain spaces, cannot start with a digit and should not start with the letters "xml". Rather than emit a document that fails to parse, the converter rewrites such names: characters outside letters, digits, _ . : - become underscores, and an underscore is put in front of names that begin with a digit or with "xml". That is how 2nd warranty became _2nd_warranty. The same cleanup applies to the root and item names you type in the options.

Text values are escaped, so "a < b & c" is written as a &lt; b &amp; c. You never need to pre-escape anything in the JSON.

Common problems

  • The JSON does not parse. The status bar shows the reason and position, for example Trailing comma before '}' is not allowed (line 1, column 8). Fix it in the editor or run it through the JSON formatter first.
  • Element order matters to a schema. Elements follow the key order of your JSON objects, so reorder the keys in the input if an XSD requires a sequence.
  • Namespaces. Prefixed element names such as soap:Body are kept, because the colon is allowed. Namespace declarations work too: an "@xmlns:soap" key becomes an xmlns:soap="…" attribute on its element, and xml:lang is kept as written.

After converting, paste the result into the XML validator if you want a second check before sending it to another system.

Privacy

The conversion runs in your browser; the JSON is not uploaded. Our server is only contacted when you use Load URL (the file is fetched through it) or Save & Share (the input is stored to create the link).

Convert JSON to XML in Python

The standard library has no single function for this, but xml.etree.ElementTree reduces it to a short recursive helper: a dictionary becomes child elements, a list repeats the element once per item, and anything else becomes text. Build the tree instead of concatenating strings, because ElementTree escapes & and < for you. It does not check element names, though: a JSON key with a space, such as "bad key", is written as <bad key>, which is not well-formed XML, so clean the keys first.

import json
import xml.etree.ElementTree as ET

def fill(element, value):
    if isinstance(value, dict):
        for key, item in value.items():
            # a JSON array repeats the element once per item
            for one in item if isinstance(item, list) else [item]:
                fill(ET.SubElement(element, key), one)
    else:
        element.text = value if isinstance(value, str) else json.dumps(value)

data = json.loads('{"user": {"name": "Ann", "age": 30, "tags": ["a", "b"], "note": "R&D <lead>"}}')
root = ET.Element("user")
fill(root, data["user"])
ET.indent(root)
print(ET.tostring(root, encoding="unicode"))

The converter above replaces such characters with underscores, which makes it a handy reference for your script's output.

Frequently asked questions

How do I make an XML attribute from JSON?
Start the key with the attribute prefix, which is @ by default. {"book": {"@id": "7", "title": "Dune"}} becomes Dune. The prefix can be changed in the options.
Why is there no <root> element in my output?
If the JSON is an object with exactly one key and that key holds an object or a value, the key itself becomes the document element. The Root element setting is only used when a wrapper is needed, for example for arrays or objects with several keys.
How can I set both attributes and text on the same element?
Use a #text key next to the attribute keys: {"price": {"@currency": "EUR", "#text": 12}} produces 12.
Why were my element names changed?
XML names cannot contain spaces or most symbols and cannot start with a digit. The converter replaces invalid characters with underscores and adds a leading underscore where needed so the document stays well-formed.
Are JSON types preserved in XML?
XML text has no types, so numbers, booleans and strings are all written as text. A consumer that needs types must read them from a schema or convert the values itself.

Last updated October 3, 2026

Related tools