Turn a JSON file into XML a system will accept
Plenty of software still speaks XML only. Older accounting and inventory systems, product feeds, SOAP services and many settings files expect tags, and they reject a JSON file no matter how clean it is. If the data you have came out of an app or an API as JSON, converting JSON to XML is the quickest way to get it in.
The part that needs deciding is the mapping. JSON has lists and XML doesn't, JSON has no attributes and XML does, and an XML document needs one root element with a name. This page explains exactly how our converter makes those choices, so you know what the XML file will look like before you open it.
How to convert JSON to XML
- Upload your JSON file - Drag it into the box at the top of this page, or browse for it. You can add up to 5 files at once.
- Check the output - XML is already picked on this page, so there's nothing to change.
- Download your file - Save the .xml file when it's ready. It opens in any text editor or browser.
The conversion runs on our servers, not in your browser, so there's nothing to install and no account to make. Our security page explains what happens to your file after that.
How JSON becomes XML tags
The converter walks through your JSON and writes one tag for each key. The file starts with <?xml version="1.0" encoding="UTF-8"?> and is indented with two spaces, so it's easy to read. These are the rules it follows:
- The root element. XML needs one element that holds everything else. If your JSON is a record with a single key, and that key's value isn't a list, the key becomes the root, so
{"order": {"id": 7}}gives<order><id>7</id></order>. Any other shape is wrapped in<root>, and if the file is a list, each item becomes an<item>element. - Lists. XML has no list type, so the tag is repeated once per item.
"tags": ["a", "b"]becomes<tags>a</tags><tags>b</tags>. An empty list writes nothing at all. - Records inside records. A nested record becomes a nested element, so a city inside an address ends up as
<address><city>...</city></address>. - Empty values.
null, an empty string and an empty record all become a self-closing tag like<phone/>, so the key is still there for the system reading it. - Key names XML won't allow. A tag name can't contain a space and can't start with a digit. Characters that aren't allowed turn into an underscore, and a name with a bad first character gets one added in front:
user namebecomesuser_name, and1stbecomes_1st. - Special characters in text. The five characters that have a meaning in XML,
& < > ' ", are escaped, so a value likeTom & Jerrycan't be mistaken for markup. Control characters that XML can't hold are removed.
Getting attributes instead of child tags
By default every key becomes a child element. Many XML schemas want some values as attributes instead, like <product id="42">. To get that, start the key with @_, and use #text for the text that goes inside the element itself:
{
"product": {
"@_id": "42",
"name": "Lamp",
"price": {"@_currency": "EUR", "#text": "19.99"}
}
}
That gives this XML. The single key product also became the root, because its value is a record and not a list:
<?xml version="1.0" encoding="UTF-8"?>
<product id="42">
<name>Lamp</name>
<price currency="EUR">19.99</price>
</product>
We ran this example through our live converter on 13 November 2026, and the output above is what came back. This is the same convention the fast-xml-parser library uses, and our converter was built to match its output.
A real example from our tests
On 13 November 2026 we uploaded this small file to our live converter. It's a list of two records, with a nested address, a list of tags that is empty in the second record, and a ZIP code that starts with a zero:
[
{"id": 1, "name": "Ana", "address": {"city": "Lisbon"}, "tags": ["a", "b"], "zip": "01100"},
{"id": 2, "name": "Zoë", "address": {"city": "Zürich"}, "tags": [], "zip": "8001"}
]
About 13 seconds after we started the upload, it came back as this XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<item>
<id>1</id>
<name>Ana</name>
<address>
<city>Lisbon</city>
</address>
<tags>a</tags>
<tags>b</tags>
<zip>01100</zip>
</item>
<item>
<id>2</id>
<name>Zoë</name>
<address>
<city>Zürich</city>
</address>
<zip>8001</zip>
</item>
</root>
Because the file is a list, there was no key to use as the root, so the output is wrapped in <root> and each record is an <item>. The address became a nested element, the two tags became two <tags> elements, and the empty tags list in the second record wrote nothing. The ZIP code 01100 kept its zero, since XML text is never treated as a number, and the accents in Zoë and Zürich came through. You can download the JSON file we uploaded and the XML it produced to compare them yourself.
Before launch, we also ran larger files on our test server. A 19 MB file with 122,589 records converted to XML in about 11 seconds, and a file with Hindi, Japanese and Arabic city names kept every character.
Limits, and files that won't convert
- Each JSON file can be up to 20 MB. The upload box accepts bigger files, but the converter stops anything over 20 MB and asks you to split it.
- Data nested more than 64 levels deep is refused.
- JSON Lines, with one record on each line, isn't supported, because the file has to hold a single JSON value. The error reads
Invalid JSON: extra data at line 2. - The file must be UTF-8 text. UTF-16 and UTF-32 files with a BOM work too.
- NaN and Infinity aren't part of the JSON standard, so a file that uses them is refused.
If your JSON has a mistake, like a missing quote or a comma after the last item, the error message says what's wrong and which line it's on. Fix that line and upload the file again.
If what you need is a spreadsheet rather than tags, our JSON to CSV converter lays the same data out as rows and columns. To go the other way, XML to JSON turns an XML file back into JSON.