How this XML to JSON converter maps your document
XML and JSON describe data differently. XML has elements, attributes, text nodes, namespaces and CDATA sections; JSON has only objects, arrays and a handful of value types. This XML to JSON converter uses a widely used convention to bridge the two, so the output is easy to consume in JavaScript, Python or any JSON-based tool, and the rules stay the same for every document you convert.
Example
<catalog xmlns:dc="http://purl.org/dc/elements/1.1/">
<book id="bk101" lang="en">
<title>XML Guide</title>
<price currency="USD">44.95</price>
<isbn>0123456789</isbn>
<inStock>true</inStock>
<dc:creator>Matthew</dc:creator>
<summary><![CDATA[Use <tags> & more]]></summary>
<empty/>
</book>
</catalog>
With the default options, the result is:
{
"catalog": {
"@xmlns:dc": "http://purl.org/dc/elements/1.1/",
"book": {
"@id": "bk101",
"@lang": "en",
"title": "XML Guide",
"price": {
"@currency": "USD",
"#text": 44.95
},
"isbn": "0123456789",
"inStock": true,
"dc:creator": "Matthew",
"summary": "Use <tags> & more",
"empty": ""
}
}
}
The mapping rules
| XML | JSON |
|---|---|
| Root element | a single top-level key, such as "catalog" |
Attribute id="bk101" | key with the prefix: "@id": "bk101", listed before child elements |
| Element with only text | a plain value: "title": "XML Guide" |
| Element with attributes and text | an object with the attributes plus "#text" |
| Repeated sibling elements | an array |
Empty element <empty/> | empty string "" |
| CDATA section | its text, unescaped |
| Namespace prefixes | kept in the key: "dc:creator" |
| XML declaration, comments, processing instructions | dropped |
Options explained
- Attribute prefix – the marker that distinguishes attributes from child elements.
@is the default; some libraries use_or$. Set it to match the code that will read the JSON. With an empty prefix, attributes look exactly like child elements, which reads nicely but can collide when an element has both an attribute and a child with the same name. - Detect numbers & booleans – converts text such as
44.95andtrueinto real JSON numbers and booleans. Values with leading zeros (0123456789) and hex-looking values stay strings so that IDs, ISBNs and zip codes are not damaged. Untick it to keep every value as a string, exactly as written in the XML. - Indent and Sort keys – control only the layout of the JSON.
The array problem, and how to handle it
XML does not say whether an element is "a list". The converter only knows an element repeats when it sees it more than once, so <sku>A</sku><sku>B</sku> becomes "sku": ["A", "B"], but a single <sku>A</sku> becomes the plain value "sku": "A". Code that reads the JSON should therefore accept both shapes, for example by wrapping non-array values in an array before looping. This is the most common source of bugs when consuming converted XML.
Other edge cases
- Mixed content such as
<p>Hello <b>world</b>!</p>loses word order: the text pieces are joined into#textandbbecomes a separate key. XML-based documents like XHTML are better processed with an XML library. - Whitespace around text values is trimmed.
- Entities such as
&amp;and&lt;are decoded to&and<. - Malformed XML, for example a missing closing tag, is rejected with the line and column of the problem rather than converted partially.
Related tools
To look at a document before converting it, open it in the XML viewer. The reverse conversion is JSON to XML, which understands the same @ and #text conventions, so data can make the round trip. If you need typed classes rather than JSON, try XML to TypeScript.
Privacy
The XML is parsed and converted in your browser and is not uploaded. Only Load URL, which fetches a remote file through our server, and Save & Share, which stores the content to create a link, send data to the server.
Convert XML to JSON in Python
Python parses XML with xml.etree.ElementTree but has no built-in XML to JSON function, so a short recursive helper does the mapping: attributes get an @ prefix, child elements become keys, and an element that holds only text becomes a string. Watch repeated tags: an element that occurs once becomes a single value and one that occurs several times becomes a list, so code that reads the JSON must handle both. All values stay strings; ElementTree does not guess numbers.
import json
import xml.etree.ElementTree as ET
def to_dict(el):
node = {"@" + name: value for name, value in el.attrib.items()}
for child in el:
node.setdefault(child.tag, []).append(to_dict(child))
for tag, items in node.items():
if isinstance(items, list) and len(items) == 1:
node[tag] = items[0] # a tag used once is not a list
text = (el.text or "").strip()
if node and text:
node["#text"] = text
return node or text # leaf element -> its text
xml = ('<catalog><book id="b1"><title>XML Guide</title></book>'
'<book id="b2"><title>Tea & Code</title></book></catalog>')
root = ET.fromstring(xml)
print(json.dumps({root.tag: to_dict(root)}, indent=2))
The converter above follows the same @ and #text convention, so you can paste the XML there to check your script's output.