JSON to XML Converter

Convert JSON to XML for SOAP endpoints, enterprise systems and config formats that never moved to JSON. Keys become tags, arrays become repeated elements, and keys that start with an underscore become attributes. The converter does not add a root element, so wrap the JSON in one top-level key such as catalog to get a document that parses.

Input JSON
XML Output

1 JSON to XML example

Input JSON

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
    "root": {
        "person": [
            {
                "id": "1",
                "name": "John Doe",
                "email": "john@example.com",
                "active": "true"
            },
            {
                "id": "2",
                "name": "Jane Smith",
                "email": "jane@example.com",
                "active": "false"
            }
        ]
    }
}

XML Output

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<root>
    <person>
        <id>1</id>
        <name>John Doe</name>
        <email>john@example.com</email>
        <active>true</active>
    </person>
    <person>
        <id>2</id>
        <name>Jane Smith</name>
        <email>jane@example.com</email>
        <active>false</active>
    </person>
</root>

2 Where XML is still the answer

SOAP services

Any service described by a WSDL expects an XML envelope, whatever format the rest of your stack uses.

Enterprise and government feeds

Tax filing formats, banking messages such as ISO 20022 and older B2B integrations are specified in XML.

Tooling that expects tags

XSLT, XPath and XSD validation work on XML, and some pipelines have no JSON step to replace them.

How to use the JSON to XML tool

  1. Get JSON into the left editor by pasting, loading a file with Upload JSON, or fetching it with Load URL. Dummy Data loads a sample.
  2. The XML on the right updates as you type, indented two spaces. Every key becomes an element, every array item becomes a repeated element with the same name, and a key that starts with an underscore becomes an attribute.
  3. Give the JSON exactly one top-level key, for example {"catalog": {...}}. The converter does not add a root element, so this key becomes the root.
  4. Parse errors appear next to the editor label with a line number. Fix the line and the XML refreshes.
  5. Click Copy XML and paste the result into your file. Add an <?xml version="1.0"?> declaration at the top if the consumer requires one.

How to convert JSON to XML in JavaScript, PHP and Python

JavaScript (Node.js)

const raw = '{"user":{"id":1,"name":"Ada & Co","roles":["admin","dev"],"active":true}}';

const esc = (s) => String(s).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");

function toXml(value, name, depth = 0) {
  const pad = "  ".repeat(depth);
  if (Array.isArray(value)) return value.map((v) => toXml(v, name, depth)).join("");
  if (value !== null && typeof value === "object") {
    const inner = Object.entries(value).map(([k, v]) => toXml(v, k, depth + 1)).join("");
    return pad + "<" + name + ">\n" + inner + pad + "</" + name + ">\n";
  }
  return pad + "<" + name + ">" + esc(value ?? "") + "</" + name + ">\n";
}

const data = JSON.parse(raw);
console.log('<?xml version="1.0" encoding="UTF-8"?>\n' + toXml(data, "root"));

Good enough for element-only documents. Once you need attributes, namespaces or CDATA, switch to xmlbuilder2 or the XMLBuilder class in fast-xml-parser.

PHP (SimpleXML)

<?php
$raw = '{"user":{"id":1,"name":"Ada & Co","roles":["admin","dev"],"active":true}}';
$data = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);

function addNode(SimpleXMLElement $parent, string $name, mixed $value): void {
    if (is_array($value) && array_is_list($value)) {
        foreach ($value as $item) addNode($parent, $name, $item);
    } elseif (is_array($value)) {
        $child = $parent->addChild($name);
        foreach ($value as $k => $v) addNode($child, $k, $v);
    } else {
        // Assign through [0] so & < > are escaped; addChild($name, $value) drops "&"
        $child = $parent->addChild($name);
        $child[0] = is_bool($value) ? var_export($value, true) : (string) $value;
    }
}

$xml = new SimpleXMLElement('<root/>');
foreach ($data as $k => $v) addNode($xml, $k, $v);

$dom = dom_import_simplexml($xml)->ownerDocument;
$dom->formatOutput = true;
echo $dom->saveXML();

array_is_list() needs PHP 8.1. Assigning through $child[0] escapes & and < correctly; addChild($name, $value) does not escape &.

Python (ElementTree)

import json
import xml.etree.ElementTree as ET

raw = '{"user":{"id":1,"name":"Ada & Co","roles":["admin","dev"],"active":true}}'

def add(parent, name, value):
    if isinstance(value, list):
        for item in value:
            add(parent, name, item)
    elif isinstance(value, dict):
        node = ET.SubElement(parent, name)
        for k, v in value.items():
            add(node, k, v)
    else:
        node = ET.SubElement(parent, name)
        node.text = "" if value is None else json.dumps(value) if isinstance(value, bool) else str(value)

root = ET.Element("root")
for k, v in json.loads(raw).items():
    add(root, k, v)

ET.indent(root, space="  ")  # Python 3.9+
print(ET.tostring(root, encoding="unicode", xml_declaration=True))

ET.indent() needs Python 3.9. For keys that should become attributes, pass attrib={...} to ET.SubElement.

Common errors and how to fix them

XML parse error: junk after document element
The output has more than one top-level element because the JSON had several top-level keys or was an array. Wrap the JSON in one key so the XML has a single root.
Element names cannot start with a digit or contain spaces
JSON keys such as "2024" or "first name" are not valid XML names, and this tool copies them as they are. Rename them, or emit them as <item name="first name"> attributes instead of element names.
Unescaped & or < breaks the document
Text content must escape & as &amp; and < as &lt;. Use your XML library's text setter rather than string concatenation, or escape manually before writing.
A single-item array becomes one element and the reader expects a list
XML cannot say "this is a list of one". Wrap repeated items in a container element such as <roles><role/></roles>, or tell the reader which names are always lists.

Good to know

There is no standard mapping from JSON to XML, only conventions. This tool runs on x2js: keys become elements, arrays become repeated siblings, scalars become text nodes, and a leading underscore marks an attribute. Badgerfish uses an @ prefix instead, and other libraries have their own rules. Find out what the receiving system expects before you commit to one.

XML cares about element order, and JSON objects officially do not. If the consumer validates against an XSD that uses xs:sequence, put the keys in the JSON in the order the schema wants before you convert.

Specifications and references

This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.

Frequently Asked Questions

Does it support attributes?

Yes, through a naming convention. A key that starts with an underscore becomes an attribute of its parent element, so "_id": 5 turns into id='5'. Every other key becomes a child element.

How are arrays converted?

Each item in an array becomes a repeated element named after the array's key. An array under "items" produces several <items> elements, with no wrapper element around them.

What happens to keys that are not valid XML names?

They are copied as they are. A key such as "first name" or "2024" produces a tag that no XML parser accepts, so rename those keys in the JSON before converting.

Is a root element added?

No. The converter writes one element per top-level key, so JSON with two top-level keys, or a top-level array, produces XML without a single root, and that does not parse. Wrap the data in one key, for example {"catalog": ...}, to get one root element.

Are special characters escaped?

Yes. &, <, >, double quotes and apostrophes are escaped in element text and attribute values, so the content cannot break the markup.

Related

XML to JSON converts in the other direction. For configuration rather than messages, JSON to YAML is usually the better target.

More Data Converters

Browse all data converters

Copied to clipboard!