How XML elements, attributes and text map to JSON
XML and JSON both nest data, but XML has things JSON does not: attributes, text mixed in with tags, and no difference between one item and a list of one. The converter follows fixed rules, so the result is predictable.
- Elements become keys. The document element is the single key at the top, so
<team>becomes{"team": {...}}. - Attributes become keys that start with @ and come before the child elements.
<member id="1" role="design">gives"@id": 1and"@role": "design". - Text next to attributes is kept under
#text.<price currency="EUR">12.50</price>becomes{"price": {"@currency": "EUR", "#text": 12.5}}. - Empty elements such as
<zip/>become null when all types are detected, and an empty string otherwise. - Comments, processing instructions, the XML declaration and the DOCTYPE are dropped. CDATA sections become ordinary text.
Character references are decoded, so & becomes & and é becomes é. Text is trimmed of spaces and line breaks at both ends. Blank lines before the first tag, also in front of the <?xml ?> line, are allowed, and element names such as constructor or toString are kept as they are. A document needs one root element: a second element after the first, even a self-closing one such as <b/>, is reported with its line and column.
The one item list problem, and what else XML cannot say
A JSON list is explicit. XML has no list type: a list is the same tag written several times. So <skill>Figma</skill><skill>Illustration</skill> becomes "skill": ["Figma", "Illustration"], but a member with a single <skill> gives "skill": "TypeScript", a plain string. Code that expects a list will break on the single case, so check with Array.isArray or wrap the value in a list yourself before looping.
Two more things are not kept. The converter cannot warn about them, because the XML is perfectly valid:
- Order between different tags.
<a>1</a><b>2</b><a>3</a>becomes"a": [1, 3], "b": 2, because all theaelements are gathered under one key. - Text mixed with tags. In
<p>Hello <b>bold</b> world</p>the loose text is merged into one#textvalue, with the pieces trimmed and joined, givingHelloworld. XML that is really a document, such as XHTML, does not fit a data format like JSON.
Numbers, true and false, and attribute names
XML stores only text, so the converter has to decide which values are numbers. It looks at each value on its own, and only clean numbers are converted: digits with an optional minus sign and decimal point, no leading zeros and at most 15 digits.
12.50becomes 12.5, andversion="1.0"becomes 1. Set Values to Keep as text if you need1.0exactly as written.007,+1 555 0100,1e3and a 20 digit ID stay text.trueandfalsebecome booleans, and an empty element and the exact wordsnullandNULLbecome null, but only with Detect all types. To keep the word null as text, choose Detect numbers or Keep as text.
If an attribute and a child element share a name, as in <item id="1"><id>child</id></item>, plain attribute names would collide. The attribute then keeps its @ and a warning says so.
Namespaces, SOAP messages and feeds
Names with a prefix, such as soap:Body or xhtml:link, keep the prefix by default, and the xmlns declarations show up as keys like "@xmlns:soap". That keeps the namespace information but makes the keys awkward to use. Turn on Remove namespace prefixes under More options to get Body and link and to drop the declarations. If two names differ only by their prefix, they end up under the same key, so check the result when a document mixes namespaces.
RSS and Atom feeds convert with their structure intact: rss, then channel, then a list of item objects. If you want one row per item for a spreadsheet, use XML to CSV instead.