XML to JSON Converter
Paste XML and get JSON in the exact shape you want. Pick the attribute prefix, force arrays, parse numbers, go compact or pretty, then copy or download. Runs in your browser.
- Free, no account
- No watermark
- No usage limit
About the XML to JSON Converter
Most XML to JSON converters give you one fixed shape and that is it. You paste your XML, and if the attribute keys, the arrays, or the formatting are not what your code expects, you are stuck with it. This XML to JSON converter hands you the controls instead. Pick how attributes are named, force every element into an array so your .map() never blows up on a single item, turn number parsing on or off, and switch between pretty and compact. The JSON rebuilds live as you change anything. And it runs in your browser, so a SOAP response with real customer data, or an internal API payload, never leaves your machine, with no upload, no account, and no size cap.
XML and JSON describe data differently, so mapping one onto the other forces judgment calls: where an attribute goes, whether a repeated tag is a list or a coincidence, what happens to text next to a child element. A locked converter answers those for you and hopes you agree. When it guesses wrong, you are hand-editing the output. The right shape depends on the code that reads it, so you should be the one choosing.
How to use
- Get your XML in. Type or paste it into the box, drop an
.xmlfile onto it, or paste a copied file straight in. Any well-formed XML works, a single<note>, a big nested<catalog>, a SOAP envelope, an RSS feed. It needs exactly one root element and every tag closed. - Set the output shape. Use the Output shape panel to choose the attribute prefix, the text key, arrays, number parsing, and pretty versus compact. Every change re-renders the JSON instantly, so you adjust and watch.
- Read the JSON. It appears below, in the exact convention you picked. Scan it to confirm the arrays and attributes landed where your code wants them.
- Take it with you. Hit Copy JSON for the clipboard, or Download .json to save a file. Share copies a link that carries your exact settings, so a teammate opens the tool already configured the way you had it.
- Something broke? If the XML is malformed, a red message names the likely cause, an unclosed tag, a mismatched name, a stray
<or&. Fix that one thing and the JSON comes right back. Load sample shows a working example with attributes and repeated elements.
Choose the output shape
This is the part free converters skip. Your last settings are remembered for next time.
Attribute keys: pick the prefix or drop it
An XML element can carry attributes and text at once, like <price currency="USD">24.99</price>. JSON has no notion of an attribute, so a converter folds both into one object and marks which key came from an attribute. The default marks them with @, giving {"price": {"@currency": "USD", "#text": "24.99"}}, the same style fast-xml-parser and xml2js use. If your schema validator hates @ in keys, switch it to _ or $, or pick no prefix so attributes become plain keys. The Ignore attributes toggle drops them entirely when you only want the data.
Always use arrays: kill the list-that-isn't-a-list bug
This is the one that burns people, and it is worth turning on more than you would think. By default a repeated tag becomes an array and a single tag stays a plain value. So two <item> tags give "item": ["x", "y"], but a record with one gives "item": "x", a string. The same schema produces a different shape depending on the data. Your code does data.item.map(...), it works all week, then a one-item record shows up and .map throws because a string has no .map. Flip Always use arrays and every element comes back as an array, single or not. You get one shape every time, with no more [].concat(x) guards scattered through your code.
Parse numbers and true/false: honest by default, safe when on
Off by default, and that is deliberate. XML has no types, 36 and "36" are identical inside a tag, so guessing is where converters quietly wreck data. Plenty of them turn a ZIP code 02134 into the number 2134, or collapse a version 1.0 into 1. This tool refuses to guess unless you ask, and when you turn parsing on it only converts values that survive a round trip. A leading zero, a phone number, or 1.0 all stay strings. Clean integers, decimals, and true/false convert, everything risky stays text.
Compact or pretty
Pretty with two-space indentation is the default because it reads well. Bump it to four spaces if that matches your house style, or switch to Compact for a single minified line when the JSON is going into a payload, a data attribute, or anywhere size beats readability.
Where XML fights back
Two things about XML have no clean JSON translation. Mixed content is the first. XML lets text and elements interleave, like <p>Click <b>here</b> now</p>, and there is no JSON shape for "text, then an element, then more text, in order." This tool gathers an element's own text under the text key and lists its children as keys, but the exact interleaving is lost. With data-shaped XML like records, config, and feeds that never happens, and for documents with markup inside prose, JSON is not the right destination anyway.
The second is namespaces. JSON has none, so <soap:Body> becomes the key "soap:Body", colon and all. The information survives, you just access it as the literal string data["soap:Body"], not data.soap.Body. Most people trip on this the first time they hit a SOAP payload.
Real jobs this handles
- Consuming a SOAP or legacy XML API from JavaScript. The backend speaks XML, your frontend speaks JSON. Paste, shape it, wire it in. Turn on Always use arrays so a response with one record does not break the code that handles many.
- Turning an RSS or Atom feed into data. Feeds are XML with repeated
<item>elements, which is exactly the array case, and you get a clean JSON array to iterate. - Reading a config file. A
pom.xml, an Android manifest, aweb.config, when you just want the structure as JSON to understand it. - Building a test fixture. Convert a sample payload once, download the
.json, drop it into your tests.
For a one-off conversion in front of you, this is the fast path. If conversion happens on every request inside your app, a library like fast-xml-parser or xmltodict belongs in the code where you tune it per call, and a whole directory of files is a job for a scripted xq run. The browser tool wins on being instant and private for the single job, not on automation.
Frequently asked questions
How do I get JSON without the @ on attribute keys?
Open the Output shape panel and change Attribute keys. You can switch the prefix to _ or $, choose no prefix so attributes become plain keys, or check Ignore attributes to remove them completely. The default @ matches what popular parsers produce, but if a downstream validator or your own schema rejects the symbol, one dropdown fixes it and the output updates as you watch.
Can I make every element an array so my code stops breaking?
Yes, that is what the Always use arrays toggle is for. With it on, a single child and a repeated child both come back as arrays, so data.tag is always something you can iterate. It is the cleanest fix for the classic bug where a list of one silently becomes a scalar and your .map call throws. Leave it off if you prefer the compact default where lone elements stay plain values.
Will parsing numbers ever corrupt an ID or ZIP code?
No, that is the reason it stays off unless you ask. With Parse numbers and true/false on, a value is only converted if it survives a round trip back to the same text. A ZIP like 02134 would lose its leading zero, and a version like 1.0 would collapse to 1, so both stay strings. Only clean integers, decimals, and the words true and false become typed values.
Does the tool upload my XML anywhere?
No. The conversion happens in your browser with JavaScript, on your own machine, and the XML is never sent to a server, logged, or stored. Close the tab and it is gone. That is what makes it safe for internal API responses, SOAP bodies with real data, or anything you would not paste into a random site.
What happens with an element that has both text and attributes?
The text moves under a dedicated text key so it can sit next to the attributes in the same object. By default that key is #text, and you can switch it to _text or text in the panel. When an element has only text and no attributes or children, the text stays inline as a plain value with no wrapper, the text key only appears when the element genuinely holds both.
Why did my converted file not turn back into the original XML exactly?
A round trip through JSON is not guaranteed to be byte-identical, and that is expected. Comments, processing instructions, and the source whitespace are not part of the data, so they do not survive, and dropping attributes or flattening mixed content loses more. Convert to JSON when JSON is your destination. If you need the original XML back exactly, keep the XML as the source of truth.