JSON to XML: Handling Attributes vs Elements Correctly

4 min read

JSON has one way to represent a key-value pair. XML has two — an attribute or a child element — and they're not interchangeable stylistically, they mean genuinely different things. Converting JSON to XML means making that choice explicit, since JSON has no native concept of "this should be an attribute."

The same data, two valid XML shapes

<!-- As an attribute -->
<user id="5">
  <name>Alice</name>
</user>

<!-- As a child element -->
<user>
  <id>5</id>
  <name>Alice</name>
</user>

Both are valid, well-formed XML describing the same underlying data. The convention that's emerged over time: attributes for metadata about an element (an ID, a type, a unit), child elements for the actual content or nested structure. Neither rule is enforced by XML itself — it's a stylistic convention different schemas apply differently.

Our convention: the @ prefix

Since JSON has no built-in way to say "make this an attribute," our JSON to XML converter uses a prefix convention: any key starting with @ becomes an XML attribute; every other key becomes a child element.

{
  "user": {
    "@id": "5",
    "name": "Alice",
    "role": "admin"
  }
}

converts to:

<user id="5">
  <name>Alice</name>
  <role>admin</role>
</user>

This isn't a universal standard — different JSON↔XML libraries use different conventions (some use a $ prefix, some nest attributes under a dedicated @attributes key) — but the @-prefix approach is common enough to be quickly recognizable, and it keeps the JSON shape flat rather than adding another level of nesting just to hold attribute data.

The single-root-element problem

XML requires exactly one root element per document. JSON has no such restriction — a JSON object can have any number of top-level keys, and a JSON array can be the top-level value entirely. When there's exactly one top-level key, it becomes the root tag directly; when there are multiple (or the top level is an array), everything gets wrapped in a synthetic <root> element, since there's no other way to satisfy XML's single-root rule.

Arrays: repeated sibling elements

XML has no native array type either — the convention is repeated sibling elements sharing the same tag name:

{ "tags": { "tag": ["frontend", "urgent"] } }
<tags>
  <tag>frontend</tag>
  <tag>urgent</tag>
</tags>

Converting that XML back to JSON (with our XML to JSON tool) recognizes the repeated <tag> siblings and reconstructs the array automatically — the two converters are designed as inverses of each other around this exact convention.

Deciding when to use @ in your own conversions

A reasonable default: if a field identifies or describes the element itself (an ID, a version number, a type discriminator) and you'd never need to nest further data under it, make it an attribute. If it's actual content, or might need child structure of its own later, make it an element. When in doubt, elements are the safer default — they can always hold more structure later, while an attribute can only ever hold a single text value.

Try JSON to XML now

Convert JSON into well-formed XML markup.

Open JSON to XML