How XML elements map to JSON keys
Each XML element becomes a JSON key and its text content becomes the value. An element that holds only text collapses straight to a string, number, or boolean. The converter infers the native type when it is unambiguous — 30 becomes a number and true a boolean, while anything else stays a string.
<!-- XML -->
<person>
<name>Alice</name>
<age>30</age>
<active>true</active>
</person>// JSON
{
"name": "Alice",
"age": 30,
"active": true
}Repeated elements become arrays — and the single-item trap
When sibling elements share a tag name, they are grouped into a JSON array under that key. This is the core structural gap between XML and JSON: XML expresses "many" by repeating a tag, JSON expresses it with brackets. The trap is the single case — one <book> often yields a plain object, not a one-element array, so code that does data.book.map(...) breaks. Use a "force array" option for tags that can repeat.
<!-- XML -->
<bookstore>
<book><title>Learning XML</title><price>39.95</price></book>
<book><title>JSON at Work</title><price>49.99</price></book>
</bookstore>// JSON
{
"book": [
{ "title": "Learning XML", "price": 39.95 },
{ "title": "JSON at Work", "price": 49.99 }
]
}Attributes become prefixed keys
JSON has no native attributes, so converters fold them into the object using a convention — most commonly an @ prefix on the key name. An element that carries both an attribute and text can no longer be a bare string, so its text moves into a #text key alongside the attributes.
<!-- XML -->
<user id="42" active="true">
<name>Alice</name>
<price currency="USD">9.99</price>
</user>// JSON
{
"user": {
"@id": "42",
"@active": "true",
"name": "Alice",
"price": { "@currency": "USD", "#text": "9.99" }
}
}Empty elements, nesting, and namespaces
Self-closing tags and empty elements map to null. Nested elements become nested objects. XML namespaces are usually kept verbatim, so a soap: prefix lands right in the key name — valid JSON, but awkward to read in JavaScript unless you strip the prefix.
<!-- XML -->
<order xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<customer><name>Alice</name></customer>
<middleName/>
</soap:Body>
</order>// JSON
{
"soap:Body": {
"customer": { "name": "Alice" },
"middleName": null
}
}Convert XML to JSON in code
When you need conversion in a script or pipeline instead of the browser tool:
# Python — xmltodict, one call, preserves attributes as @-prefixed keys
import xmltodict, json
doc = xmltodict.parse(open("data.xml").read())
print(json.dumps(doc, indent=2))// Node.js — fast-xml-parser, with attribute + array control
import { XMLParser } from 'fast-xml-parser'
const parser = new XMLParser({ ignoreAttributes: false, isArray: (name) => name === 'book' })
console.log(JSON.stringify(parser.parse(xmlString), null, 2))// Browser — built-in DOMParser, no dependency
const doc = new DOMParser().parseFromString(xmlString, 'text/xml')
// then walk doc.documentElement recursively to build the objectCommon XML to JSON mistakes
- Assuming a repeatable tag is always an array — single occurrences silently become objects.
- Dropping attributes by using a converter that only reads element text.
- Letting type inference mangle codes like
007or ZIP codes into numbers. - Carrying noisy namespace prefixes (
soap:,xmlns:) straight into JSON keys.
For a step-by-step walkthrough with JavaScript and Python examples, see the XML to JSON tutorial. To go the other way, use JSON to XML.