Free online XML to JSON converter
XML to JSON without guessing the shape
This XML to JSON converter is free, needs no account and runs in your browser: paste up to 5 MB of markup and the JSON appears beside it. Because no standard says how XML maps to JSON, the three decisions that change the output are yours — the attribute prefix, the key that holds text, and whether an element that appears once becomes an array — and the bar underneath names every element path where the two formats did not line up, including the paths that end up as an array in one record and a bare value in the next.
- 100% free
- No signup
- Up to 5 MB
- @ / @_ / $ prefixes
- Ambiguity report
The JSON appears here as you type.
Paste XML, open a file, or press Ctrl+V anywhere on this page.
One schema, two JSON shapes
These two fragments are valid against the same schema and differ only in how many tags the product carries. Converted with arrays created from repetition — the default in almost every library — they produce different types for the same path.
One child element
<product>
<tags>
<tag>coffee</tag>
</tags>
</product>becomes
{
"product": {
"tags": { "tag": "coffee" }
}
}Two child elements
<product>
<tags>
<tag>coffee</tag>
<tag>fair-trade</tag>
</tags>
</product>becomes
{
"product": {
"tags": { "tag": ["coffee", "fair-trade"] }
}
}tags.tag is a string in the first document and an array in the second, so tags.tag.length returns 6 in one case and 2 in the other. Switching the array policy to “Always an array” makes both documents produce ["coffee"] and ["coffee", "fair-trade"], at the cost of wrapping every other child in brackets too.
How to convert XML to JSON
Three steps: paste the markup, pick the conventions, check what the mapping could not carry.
Drop the document in
A .xml, .rss, .atom, .svg, .xsd or .plist up to 5 MB will do — paste it, drop it on the editor, or hit Ctrl+V — ⌘V under macOS — with nothing selected. A DOCTYPE at the top is stepped over and the XML declaration is read for its encoding; neither of them reaches the JSON, because JSON has nowhere to put a prolog.
Choose the three conventions that decide the shape
Set the attribute prefix — @id, @_id, $id, merged with the child names, or dropped entirely — then the key that holds text next to attributes (#text, _text, $t or value), then whether an element that appears once is a value or a one-item array. Namespace prefixes can stay in the key as dc:creator or be stripped down to creator.
Read the shape report before you copy
The bar underneath counts the elements read, the attributes mapped and the arrays created, and it names any path that is a list in one record and a single value in another — the case that breaks a consumer expecting one shape. Copy hands over the entire document even when the preview stops early, and Download writes it out beside the filename you opened.
Technical specifications
| Accepted input | Any well-formed XML 1.0 document: elements, attributes, text, CDATA, comments, processing instructions and a DOCTYPE, from .xml, .rss, .atom, .svg, .xsd, .xsl, .plist or .config |
|---|---|
| Attribute conventions | @name, @_name, $name, no prefix (merged with child names), or dropped — 5 options, applied to every attribute including xmlns declarations |
| Text-node key | #text, _text, $t or value, used only when an element has attributes or children as well as text |
| Array policy | Array only where an element repeats, or an array for every child element. The second is the only one with a stable shape across records and costs 47% more bytes — 4.10 MB against 6.00 MB on the same 20,000-record catalogue |
| Namespaces | Prefix kept in the key (dc:creator) or stripped (creator); the namespace URI survives only as the xmlns attribute value |
| Entities resolved | The five XML predefines — & < > " ' — plus &#NNN; and &#xHH;. An HTML-only entity such as is reported as an error with its line, because XML never defined it |
| Cannot be represented | Comments, processing instructions, the DTD, the order between text and sibling elements, and the difference between CDATA and escaped text — each is counted in the report |
| Speed, limits and cost | A 4.5 MB feed of 160,000 elements parses in 0.15 s and reaches finished JSON in 0.33 s, coming out roughly 47% larger than the markup. 5 MB and 500 levels of nesting are the ceilings; a mismatched end tag or unknown entity is reported with line, column and the source line. Free, no signup, run in this browser tab |
Frequently asked questions
How are XML attributes represented in JSON?
As ordinary object keys with a marker that keeps them apart from child elements — @id by default here, with @_id, $id, no prefix at all, or dropping them entirely as the alternatives. The marker exists because JSON has one kind of member and XML has two: without it, an attribute called price and a child element called price collide into one key and one of them is lost. This page counts those collisions and names the paths where they happen rather than silently keeping the last one.
Why did the same element become an array in one place and a plain value in another?
Because arrays in this mapping come from repetition, and a record with one child has nothing to repeat. A <tags> element holding two <tag> children produces an array; the next record with a single <tag> produces a string, and any code doing data.tags.tag.map() crashes on the second record. The document itself cannot resolve this — nothing in a well-formed XML file says an element is a list — so either switch to “Always an array”, or read the schema, where maxOccurs tells you what the author intended.
What happens to XML namespaces?
Prefixes are kept as part of the key by default, so <dc:creator> becomes "dc:creator", and the xmlns declarations arrive as ordinary attributes because that is what they are. Stripping prefixes gives you "creator", which is friendlier to consume and loses the only thing distinguishing two identically named elements from different vocabularies — an Atom feed mixing atom:title with a custom title is the usual casualty. The namespace URI itself has nowhere to go in either mode.
Does CDATA survive the conversion?
The text inside survives; the wrapper does not. <![CDATA[<b>hi</b>]]> and <b>hi</b> are two spellings of the same characters in XML, and both arrive as the JSON string "<b>hi</b>" — nothing marks which spelling the source used. That matters when you convert back, because a value that was hand-written as CDATA to keep it readable will return as an escaped string.
What happens to an element that contains both text and child elements?
The text is gathered into the text key and the children become members, which loses the order between them. <p>Call <b>now</b> before Friday</p> is a sentence in XML and becomes {"b": "now", "#text": "Call before Friday"} in JSON — the words survive, their positions around the <b> do not. Mixed content is counted in the report because prose-shaped XML is the one case where converting to JSON destroys meaning rather than reshaping it.
Why is my empty element null instead of an empty string?
Because <coupon/> and <coupon></coupon> are the same thing in XML and neither says whether the value is absent or blank. null is the reading most converters take and the one this page takes; if your producer means an empty string, it should be sending one explicitly. The count of empty elements appears in the report so you can see how many nulls came from this rule rather than from real data.
Is there an official XML to JSON standard?
No — there is no W3C or IETF specification for it, only conventions, which is why two converters disagree about your file. The named ones are Parker (drop attributes, keep the text), BadgerFish (attributes prefixed with @, text under $), JsonML (arrays that preserve document order) and the defaults in libraries like fast-xml-parser and xml-js. This page implements the widely used attribute-prefix convention with the choices exposed, because picking one silently is what makes converter output non-portable.
About mapping XML onto JSON
There is no canonical XML-to-JSON mapping, and there cannot be one, because the two formats disagree about what a document is. XML has attributes and elements, JSON has one kind of member. XML orders everything, including text sitting between two child elements; JSON orders array items and treats object members as unordered. XML has namespaces, comments, processing instructions and a schema language that says which elements repeat; JSON has none of that. Every converter therefore invents a convention, and the well-known ones — Parker, BadgerFish, JsonML and the defaults baked into fast-xml-parser and xml-js — disagree about the same file. That is the practical reason the choices are controls on this page rather than defaults in a docs page nobody reads.
The most expensive disagreement is about arrays. An XML schema knows that maxOccurs="unbounded" makes an element a list even when a particular document contains one of them; a converter reading the document alone cannot know that, so it infers the list from repetition and produces a different shape for every record. Whole classes of production bug come from this: an order with one line item deserialises into an object, the code iterates it as an array, and the failure only shows up for the customer who bought a single thing. If the JSON is going somewhere typed, take the stable shape and pay the extra brackets — or generate a contract for it with the JSON Schema generator once the shape is settled.
Conversion is also not reversible, which is worth knowing before you build a round trip on it. Comments, processing instructions and the DTD are gone; CDATA and escaped text become the same string; the order between text and elements in mixed content is lost; and an empty element arrives as null with no way to tell whether the author meant blank or absent. Going the other way through JSON to XML produces valid markup that is not the document you started with. When you only need to read the tree rather than reshape it, the XML viewer leaves all of that intact.
The markup never leaves this tab
The parser and the mapper are JavaScript running in this tab, so the markup you paste is never uploaded, logged or stored — a supplier feed with real customer names can be converted here without it leaving the machine, and the page keeps working with the network switched off.