XML to JSON Converter

Convert XML to JSON, attributes and text nodes included. Attributes become keys with an underscore prefix (_id), and text that sits next to child elements goes under __text. Use it when a SOAP response or an RSS feed has to reach code that only reads JSON.

XML Input
JSON Output

1 XML to JSON example

XML Input

1
2
3
4
5
6
7
8
9
10
11
12
<root>
  <person>
    <id>1</id>
    <name>John Doe</name>
    <role>Admin</role>
  </person>
  <person>
    <id>2</id>
    <name>Jane Smith</name>
    <role>User</role>
  </person>
</root>

JSON Output

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
  "root": {
    "person": [
      {
        "id": "1",
        "name": "John Doe",
        "role": "Admin"
      },
      {
        "id": "2",
        "name": "Jane Smith",
        "role": "User"
      }
    ]
  }
}

2 Where XML to JSON comes up

Legacy responses

Normalize repeated elements before the JSON reaches a frontend. One <order> becomes an object and two become an array, so the same SOAP call can return two shapes.

Feeds

RSS and Atom are XML, while most code that consumes them today works with JSON.

Reading a config

A deeply nested XML config is easier to scan as JSON when you only want to see what is in it.

How to use the XML to JSON tool

  1. Paste XML into the left editor, or use Upload XML for a file. Load URL works for feeds and API responses, but only when the server allows cross-origin requests.
  2. The JSON on the right updates as you type. Attributes become keys with an underscore prefix; text that sits beside child elements goes under __text.
  3. Elements that repeat under the same parent become an array; a single occurrence becomes an object or a string.
  4. Malformed XML shows Invalid XML next to the editor label, without a position. The usual causes are an unclosed tag, an unquoted attribute and a bare & in text.
  5. Click Copy JSON and paste the result where you need it.

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

PHP (SimpleXML)

<?php
$xml = '<catalog>
  <book id="1" lang="en"><title>Dune</title><price>9.99</price></book>
  <book id="2"><title>Emma</title><price/></book>
</catalog>';

$obj = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
if ($obj === false) {
    die('Malformed XML');
}

echo json_encode($obj, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);

Attributes land under @attributes and an empty element becomes {} rather than "" or null. LIBXML_NOCDATA turns CDATA sections into plain strings.

Python (ElementTree)

import json
import xml.etree.ElementTree as ET

xml = """<catalog>
  <book id="1" lang="en"><title>Dune</title><price>9.99</price></book>
  <book id="2"><title>Emma</title><price/></book>
</catalog>"""

def to_dict(el):
    node = {"@" + k: v for k, v in el.attrib.items()}
    for child in el:
        value = to_dict(child)
        if child.tag in node:                       # repeated tag -> list
            if not isinstance(node[child.tag], list):
                node[child.tag] = [node[child.tag]]
            node[child.tag].append(value)
        else:
            node[child.tag] = value
    text = (el.text or "").strip()
    if text and not node:
        return text
    if text:
        node["#text"] = text
    return node or None

root = ET.fromstring(xml)
print(json.dumps({root.tag: to_dict(root)}, indent=2))

Standard library only. If you would rather not maintain this, xmltodict.parse(xml) from the xmltodict package does the same job and uses the same @ and #text keys.

JavaScript (fast-xml-parser)

// npm install fast-xml-parser
const { XMLParser } = require("fast-xml-parser");

const xml = '<catalog><book id="1"><title>Dune</title><price>9.99</price></book>' +
            '<book id="2"><title>Emma</title><price/></book></catalog>';

const parser = new XMLParser({
  ignoreAttributes: false,
  attributeNamePrefix: "@_",
  isArray: (name) => name === "book",   // always a list, even with one <book>
});

console.log(JSON.stringify(parser.parse(xml), null, 2));

Without the isArray option a parent with one child gives an object and a parent with two gives an array, which is the kind of bug that only appears with real data.

Common errors and how to fix them

A list with one item is an object, a list with two is an array
Every XML to JSON mapper has this problem, because XML cannot mark a single element as a list. Configure the parser with the names that are always lists, or normalize with Array.isArray() / isinstance(x, list) after parsing.
Numbers and booleans come out as strings
XML text has no type. Cast the fields you need after conversion, or enable a parser option such as parseTagValue in fast-xml-parser. Beware of values like 007 that should stay strings.
Error: xmlParseEntityRef: no name
A bare & in text, usually in a URL with query parameters. Replace it with &amp; or wrap the text in a CDATA section.
Namespaced keys such as soap:Body or media:content
Most libraries keep the prefix in the key, so you access it with bracket syntax, data["soap:Body"], or strip prefixes with a parser option such as removeNSPrefix. This tool's x2js output uses the local name (Body) and stores the prefix under __prefix.

Good to know

This tool runs on x2js, which puts attributes under underscore-prefixed keys (_id) and mixed text under __text. Every library picks its own scheme: SimpleXML uses @attributes, xmltodict uses @id and #text, fast-xml-parser defaults to @_id. Pick one and agree on it before the JSON goes anywhere else.

Comments, processing instructions and the DOCTYPE are dropped. JSON has nowhere to put them. If you need a lossless round trip, keep the XML as the source of truth and treat the JSON as a view of it.

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

How are XML attributes represented in JSON?

Attributes become keys with an underscore prefix, so <item id="5"> gives "_id": "5". When an element has attributes or child elements as well as text, the text goes under a __text key. Nothing in the element is lost.

What happens with repeated elements?

Elements that occur more than once under the same parent are collected into a JSON array. A single occurrence becomes a plain object or string.

Are namespaces supported?

Partly. Keys use the element's local name, so soap:Envelope becomes Envelope, and the prefix is kept in a __prefix field inside it. Namespace declarations such as xmlns:soap appear as attributes (_xmlns:soap).

Why do I get an error about malformed XML?

The input must be well-formed: every tag closed, attributes quoted and a single root element. The browser's XML parser rejects anything else, and the tool then shows Invalid XML without a position, so check for an unclosed tag or a bare & first.

Can I convert an RSS feed or SOAP response?

Yes. Paste the raw XML, or fetch it with Load URL when the server allows cross-origin requests. RSS, Atom, SOAP, SVG and sitemap files are all regular XML.

Related

JSON to XML converts in the other direction. Once you have JSON, the formatter tidies it, and JSON to YAML converts it again if the destination is a config file.

More Data Converters

Browse all data converters

Copied to clipboard!