This tool converts XML to JSON in your browser; nothing leaves your machine. For the reverse direction, see JSON to XML.
XML and JSON have different data models
XML is a markup language designed for documents; JSON is a data interchange format. They overlap but don’t map perfectly:
| XML feature | JSON equivalent |
|---|---|
| Element with text | String |
| Element with children | Object with key-per-child |
| Repeated elements | Array |
| Attributes | Object property (with prefix or in _attrs sub-object) |
| Mixed content (text + elements) | Awkward — needs convention |
| Namespaces | Encoded as part of element names |
| Comments | Discarded |
| Processing instructions | Discarded |
The conversion has to make decisions about each. There’s no canonical mapping.
A typical conversion
<user>
<name>Alice</name>
<age>30</age>
<tags>
<tag>vip</tag>
<tag>active</tag>
</tags>
</user>
→
{
"user": {
"name": "Alice",
"age": "30",
"tags": {
"tag": ["vip", "active"]
}
}
}
Notice:
- The outer element wraps everything (XML requires a single root).
- Numeric-looking values (
30) become strings — XML has no native types. - The
tagarray is detected because there are multiple<tag>elements. - A single
<tag>would have produced a string, not a 1-element array.
The “single element vs array” problem
The biggest XML-to-JSON conversion gotcha:
With one tag: With two tags:
<tags> <tags>
<tag>vip</tag> <tag>vip</tag>
</tags> <tag>active</tag>
</tags>
Becomes: Becomes:
"tags": { "tags": {
"tag": "vip" "tag": ["vip", "active"]
} }
The shape of the JSON depends on the count. Consumers have to handle “string or array” types, which is awkward.
Two solutions:
- Always wrap in array.
"tag": ["vip"]even when there’s one. Clean for consumers; bloats single-element cases. - Force a tag-list explicitly via schema. If the converter knows in advance which elements are repeatable, it can always emit an array for those.
The tool above does neither: one element becomes a value and two or more become an array, so check the type before you index into it.
Attributes
<user id="42" type="admin">
<name>Alice</name>
</user>
Attributes need a place in the JSON output. Conventions:
// Convention A: Prefix attributes with @ or $
{
"user": {
"@id": "42",
"@type": "admin",
"name": "Alice"
}
}
// Convention B: Group attributes in a sub-object
{
"user": {
"_attrs": { "id": "42", "type": "admin" },
"name": "Alice"
}
}
// Convention C: Mix attributes with elements (lossy if names collide)
{
"user": {
"id": "42",
"type": "admin",
"name": "Alice"
}
}
Convention A is the Badgerfish convention ($ prefix) and similar variants (@ prefix). Convention B is more verbose but never collides with element names. Convention C is simplest but loses the attribute-vs-element distinction.
The tool above uses Convention B with the key @attributes, and puts an element’s own text under #text when it also has attributes: <user id="42">Alice</user> becomes {"@attributes": {"id": "42"}, "#text": "Alice"}. Attribute values stay strings. The root element’s own name isn’t kept — the output is its content.
Mixed content
XML allows text and elements to interleave:
<p>Some <em>italic</em> text and <strong>bold</strong>.</p>
JSON has no clean way to represent this. Conventions:
// As an array of mixed values
{
"p": ["Some ", { "em": "italic" }, " text and ", { "strong": "bold" }, "."]
}
// As text with placeholders (lossy)
{
"p": "Some italic text and bold."
}
Mixed content is the hardest part of XML-to-JSON conversion. If your XML has it, the converter’s choice matters. The tool above is lossy here: child elements are grouped by name and the loose text is joined into one #text value, so the interleaving order is lost. Keep mixed-content documents (XHTML, DocBook) as XML.
Namespaces
<root xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:title>Example</dc:title>
<dc:creator>Alice</dc:creator>
</root>
In JSON, namespace prefixes typically become part of the key:
{
"root": {
"dc:title": "Example",
"dc:creator": "Alice"
}
}
The namespace declaration itself (xmlns:dc="...") becomes an attribute, which by Convention A is prefixed:
{
"root": {
"@xmlns:dc": "http://purl.org/dc/elements/1.1/",
"dc:title": "Example",
"dc:creator": "Alice"
}
}
Round-trip considerations
XML → JSON → XML usually does not produce the original XML. Lost in conversion:
- Attribute order.
- Element ordering when objects deduplicate names (JSON object keys are unique; XML allows repeated children of the same name).
- Comments and processing instructions.
- Specific whitespace patterns.
- The distinction between
<elem/>and<elem></elem>(both render as the same JSON).
For lossless round-tripping, use a converter explicitly designed for it (Badgerfish, JsonML, or similar canonical mappings).
When XML-to-JSON is the right tool
- Reading legacy XML APIs from JavaScript. SOAP services, RSS feeds, OData responses — easier to manipulate as JSON than as DOM.
- Importing XML data into a JSON-based store. MongoDB, Elasticsearch, modern document stores expect JSON.
- Converting XML configs to JSON. Rare but happens during modernization.
When it isn’t
- XML where order matters. JSON object key order isn’t guaranteed by the spec. If a downstream consumer depends on element order, you need an array-of-objects representation.
- XML with rich schemas. XSD-validated XML loses its validation when converted; rebuilding equivalent constraints in JSON Schema is non-trivial.
- XHTML and HTML. Convert to a JSON-of-DOM representation instead.
Common pitfalls
- Single-element arrays missing.
<tags><tag>vip</tag></tags>becomes"tag": "vip"(a string), not"tag": ["vip"]. Consumers have to handle both. Use “always array” mode for predictability. - Attribute name collisions. An element with both an
idattribute and a child element namedidcollides under Convention C. Use Convention A or B. - Lost whitespace. Insignificant whitespace between elements is dropped. If your “XML” is really mixed content where whitespace matters, the conversion is lossy.
- Numeric coercion. Some converters auto-convert numeric-looking text to JSON numbers (
<age>30</age>→"age": 30). Some don’t. The result affects how consumers parse — leading-zero strings ("007") are particularly affected. - Namespace flattening. Some converters strip namespaces; some preserve. Check the converter’s behavior.
For the reverse direction, see JSON to XML. For other JSON conversions, JSON to YAML, JSON to CSV.