XML to JSON: The Mapping Rules and What Gets Lost
There is no standard XML-to-JSON mapping. The converter uses a common one, and this page states it so you can predict the output.
The rules
| XML | JSON |
|---|---|
| Element with only text | A string: <n>Dune</n> becomes "n": "Dune" |
| Attribute | A key prefixed with @: <b id="1"/> becomes {"@id": "1"} |
| Element with attributes and text | Text goes in #text |
| Empty element | null |
| Repeated sibling elements | An array, in document order |
| Root element | The single top-level key |
All values are strings. XML has no number or boolean type, so <qty>2</qty> becomes "2". Converting types is your decision, because only you know whether 007 is a number.
The single-versus-array trap
One <item> becomes an object; two become an array. Code that reads doc.order.item.length works on orders with two items and breaks on orders with one. Handle it at the consumer: wrap a value in an array if it is not one.
What a conversion cannot keep
- Order of mixed content. In
<p>one <b>two</b> three</p>, the text pieces are joined into one#text, so where<b>sat is lost. - Comments and processing instructions. They are dropped.
- Namespace meaning. Prefixes stay in key names (
soap:Body) andxmlnsdeclarations appear as@xmlns:soapattributes, but nothing resolves them. - Element versus attribute.
<a b="1"/>and<a><b>1</b></a>differ in XML and differ in the output (@bversusb), so a consumer that accepts both forms must handle both. - Whitespace. Text is trimmed, so a value that was only significant whitespace becomes
null.
Not well-formed input
The converter refuses to produce JSON for a malformed document and reports the line and column instead of emitting a partial result. See well-formed versus valid.