JSON to XML: A Practical Conversion Guide
JSON to XML looks like it should be a clean one-to-one mapping. It isn't. XML and JSON disagree on some fundamental things - XML has no concept of an array, no native numbers or booleans, and a hard requirement for a single root element. Every converter has to make opinionated choices to bridge those gaps, and if you don't know what those choices are, you end up with XML that technically parses but doesn't match what the consuming system expects. Here is how the conversion actually works and where it bites.
The Core Mismatch: XML Has No Arrays
This is the single biggest source of confusion. In JSON, a list is a first-class type:
XML has no array type. The standard way to represent a list is to repeat the element:
Notice there is no wrapper telling you these three belong together as one collection. A consumer reading this XML can't tell the difference between "a list called tags" and "three separate tags fields that happen to share a name." This is why round-tripping is lossy: convert that XML back to JSON and a naive parser may give you a single string instead of an array when the list has exactly one item. Keep this in mind any time you generate XML that something else has to read back.
JSON to XML Type Mapping
XML stores everything as text. There is no number type, no boolean, no null. Here is how the common JSON types land:
| JSON | XML Result | Notes |
|---|---|---|
"hello" | | Text content |
42 | | Becomes a string; consumer must re-parse |
true | | No boolean type in XML |
null | or xsi:nil="true" | Empty element, or an explicit nil attribute |
[1, 2] | repeated elements | No array wrapper |
{ } | nested | Object becomes a child element |
"age": 30 becomes 30 , the type information is gone. Whoever reads the XML has to know that age should be coerced back to an integer. XML Schema (XSD) exists to carry that contract, but the raw document on its own tells you nothing.
Attributes vs Elements
JSON has one way to attach data to an object: a key. XML has two - child elements and attributes. So this JSON:
can map to either of these, and both are valid:
Plain JSON gives a converter no signal about which fields should be attributes, so most tools default to elements-for-everything. That is the safe choice and the one you usually want. If you need specific fields as attributes, the common convention is a prefix like @ in the source JSON - { "@id": "bk-101" } becomes id="bk-101". Decide this up front based on whatever XSD or API you are targeting, because retrofitting attributes later means touching every record.
The Root Element Problem
XML documents must have exactly one root element. JSON has no such rule - a valid JSON document can be an object, but it can also be a bare array or even a single value:
You cannot convert that array directly. There is no single top-level element to wrap it in, so the converter has to invent one, usually something generic like or :
If a specific system expects as the root, a generic will fail validation against its schema. Always confirm what root name the target expects rather than accepting the default.
A Full Example
Here is a realistic API response and a clean conversion:
The items array became two repeated blocks, paid and total lost their types, and note collapsed to a self-closing empty element. None of that is wrong, but every one of those is a decision the consumer needs to know about.
Special Characters and Encoding
XML reserves five characters that cannot appear raw in text content: <, >, &, ", and '. A converter has to escape them or the document won't parse. So a JSON value like "Jack & Jill must become:
If you are doing this by hand or with a quick string template, this is the step people forget, and it produces XML that throws a parse error the moment a customer name contains an ampersand. For anything beyond ASCII, declare the encoding in the prolog: . A good converter handles both automatically - paste your JSON into the JSON to XML converter and the escaping is done for you, entirely in the browser.
Round-Tripping Back to JSON
Because the conversion is lossy, round-tripping rarely gives you back the exact JSON you started with. Single-element arrays come back as scalars, numbers come back as strings, and the attribute-vs-element choice changes the shape. If you need to go the other direction, the XML to JSON converter makes the same kinds of structural decisions in reverse, and seeing both directions side by side is the fastest way to understand where the lossiness lives.
Before you convert anything, run the source through the JSON validator first. Malformed JSON produces XML that is subtly broken rather than loudly broken, and a five-second validation check saves you from chasing a parse error that started two steps upstream. Validate, then convert, then confirm the root element and array handling match what the receiving system actually expects.