Data Formats2026-06-04

How to Convert XML to JSON (with Examples)

XML and JSON model data differently, so conversion isn't 1:1. Here's how attributes, repeated elements, and text nodes map — plus code and a free converter.

xmljsonconvertparsingdata-interchange

How to Convert XML to JSON (with Examples)

Plenty of legacy APIs, SOAP services, RSS feeds, and enterprise systems still emit XML. Modern frontends and APIs want JSON. Converting between them sounds trivial, but unlike JSON ↔ YAML, XML and JSON don't model data the same way — and that mismatch is where conversions get interesting.

This guide explains the structural differences, shows how the tricky cases map, and gives you code plus a browser tool.

Why It Isn't 1:1

JSON has exactly six types: object, array, string, number, boolean, null. XML has only elements, attributes, and text — and no native concept of arrays or numbers. So any converter has to make decisions:

  • Where do XML attributes go in a JSON object that has no attribute concept?
  • How do you tell a single repeated element from an array?
  • What happens to text mixed with child elements?

Different converters answer these differently, which is why two XML-to-JSON tools can produce different JSON from the same input. Understanding the common conventions lets you predict the output.

The Standard Conventions

Most converters (and the one on this site) follow these rules:

Attributes get a prefix. An attribute like id="42" becomes a key prefixed with @:

<user id="42">Alice</user>
{ "user": { "@id": "42", "#text": "Alice" } }

Text content becomes #text when an element has both attributes and text (as above). When an element has only text, it usually collapses to a plain string:

<name>Alice</name>
{ "name": "Alice" }

Repeated elements become an array:

<users>
  <user>Alice</user>
  <user>Bob</user>
</users>
{ "users": { "user": ["Alice", "Bob"] } }

A Fuller Example

XML input:

<order id="1001" status="shipped">
  <customer>Acme Corp</customer>
  <items>
    <item sku="A1">Widget</item>
    <item sku="B2">Gadget</item>
  </items>
</order>

Converts to:

{
  "order": {
    "@id": "1001",
    "@status": "shipped",
    "customer": "Acme Corp",
    "items": {
      "item": [
        { "@sku": "A1", "#text": "Widget" },
        { "@sku": "B2", "#text": "Gadget" }
      ]
    }
  }
}

Paste your own XML into the XML to JSON Converter to see this mapping applied instantly — it parses the XML, preserves attributes and nested structure, and pretty-prints the JSON. Going the other way, the JSON to XML Converter reverses the process.

Converting in Code

JavaScript (browser) — the built-in DOMParser plus a small recursive walk:

function xmlToJson(node) {
  const obj = {};
  // attributes
  if (node.attributes) {
    for (const attr of node.attributes) obj["@" + attr.name] = attr.value;
  }
  // children
  for (const child of node.children) {
    const childJson = xmlToJson(child);
    if (obj[child.nodeName]) {
      if (!Array.isArray(obj[child.nodeName])) obj[child.nodeName] = [obj[child.nodeName]];
      obj[child.nodeName].push(childJson);
    } else {
      obj[child.nodeName] = childJson;
    }
  }
  if (!node.children.length) return node.textContent;
  return obj;
}

const doc = new DOMParser().parseFromString(xmlString, "application/xml");
const json = xmlToJson(doc.documentElement);

Python (the xmltodict library handles the conventions for you):

import xmltodict, json
data = xmltodict.parse(xml_string)   # attributes become @-prefixed keys
print(json.dumps(data, indent=2))

The Hard Cases

The single-vs-array ambiguity. When an element appears exactly once, a converter can't know whether it's "always a list that happens to have one item" or "a single value." <items><item>x</item></items> produces "item": "x" (a string), but with two items it's an array. Code that consumes the JSON must handle both — or you force arrays with a schema/force_list option.

Mixed content. XML allows text and elements interleaved: <p>Hello <b>world</b></p>. JSON has no clean representation; converters typically split it into #text fragments, which loses ordering. If you're converting documents (not data), expect lossy results.

Namespaces. Prefixes like <soap:Envelope> carry into JSON keys as literal soap:Envelope, which is valid but awkward. Strip or remap namespaces if your consumer can't handle the colon.

Everything is a string. XML has no number or boolean type, so <count>42</count> becomes "count": "42" — a string. If you need real numbers, post-process or apply a schema after conversion.

Validate First

Malformed XML — an unclosed tag, an unescaped &, a missing root element — will fail to parse. Run questionable input through the XML Formatter first; it pretty-prints valid XML and surfaces structural errors, so you fix the source before converting.

Quick Reference

  • XML → JSON isn't 1:1: attributes, repeated elements, and mixed content all need conventions.
  • Common rules: attributes → @-prefixed keys, text → #text or a bare string, repeats → arrays.
  • Convert instantly with XML to JSON / JSON to XML, or use DOMParser (JS) / xmltodict (Python).
  • Watch for the single-vs-array ambiguity, mixed content, namespaces, and the fact that all XML values arrive as strings.
  • Validate malformed XML with the XML Formatter before converting.