A JSON object with one key can still need an extra wrapper when that key holds an array. This is the small input I use to check that case:
{
"item": [1, 2]
}
The array contains two values. An XML document still needs one document element. The XML specification defines that requirement.
Two items, one document
For comparison, this deliberately broken document has two top-level elements:
<item>1</item>
<item>2</item>
Those elements could be placed inside a larger document, but this text alone cannot be parsed as a well-formed XML document.
The tested converter adds a wrapper:
<root>
<item>1</item>
<item>2</item>
</root>
The name root is a mapping choice. If a receiving API expects <items> or a namespace-qualified element, this output can parse successfully and still have the wrong shape for that API.
Here is a small check using Python's standard ElementTree parser:
import xml.etree.ElementTree as ET
array_xml = """<root>
<item>1</item>
<item>2</item>
</root>"""
root = ET.fromstring(array_xml)
assert root.tag == "root"
assert [child.tag for child in root] == ["item", "item"]
assert [child.text for child in root] == ["1", "2"]
print("array_root: passed")
The parser checks the document structure. The assertions check the wrapper, element names, values and order expected by this particular mapping.
Add a nested object and text that needs escaping
My second fixture is a synthetic order:
{
"order": {
"@id": "00123",
"customer": "Lee & Tom",
"note": "<review>",
"item": [
{ "sku": "A1" },
{ "sku": "B2" }
]
}
}
Here, the single non-array key order supplies the document element. This converter treats the @ prefix as an attribute convention. Its output is:
<order id="00123">
<customer>Lee & Tom</customer>
<note><review></note>
<item>
<sku>A1</sku>
</item>
<item>
<sku>B2</sku>
</item>
</order>
00123 stays a string in the source. The ampersand and angle brackets are escaped in the XML text, then decoded when a parser reads it:
order_xml = """<order id="00123">
<customer>Lee & Tom</customer>
<note><review></note>
<item>
<sku>A1</sku>
</item>
<item>
<sku>B2</sku>
</item>
</order>"""
order = ET.fromstring(order_xml)
assert order.tag == "order"
assert order.attrib == {"id": "00123"}
assert order.findtext("customer") == "Lee & Tom"
assert order.findtext("note") == "<review>"
assert [item.findtext("sku") for item in order.findall("item")] == ["A1", "B2"]
print("nested_order: passed")
Run the two Python blocks in order. The second uses the import from the first. Keep the XML escapes in the document; the parsed values show whether the text survived.
Agree on the mapping before sending the result
For an integration, I would check the receiving contract against three choices:
- The required document element, including any namespace.
- How arrays are represented: repeated elements or a collection wrapper.
- Which fields become attributes, child elements or text.
@id is a converter convention, not a rule defined by JSON. The receiving system's schema or API documentation should determine the required structure. The assertions above verify these fixtures; they do not validate an XSD or prove that another API will accept them.
Both examples were run against the live DataToolForge JSON to XML converter on 2026-10-07, UTC+08:00, in a remote Chrome browser. The two Python blocks were also executed with Python 3.12.14. The screenshots show the actual tool results, and all inputs are synthetic.
You can paste either fixture into the converter and compare the result with the checks above. If your XML API needs a different array shape, which element names and wrapper does it require?
Disclosure: DataToolForge is my project. AI assistance was used to draft, test and edit this article.


Top comments (0)