XML to JSON & JSON to XML Converter
XML to JSON with attributes, repeated tags, namespaces, 5 spacing options and root unwrap; JSON to XML with attributes, CDATA, comments and your own root.
Your browser asks that address directly — the file does not pass through this site.
Compact on: <name>Ada</name> becomes "name": "Ada". Off: every element is an object, so it becomes "name": { "#text": "Ada" }. Attributes always go under "@attributes".
Turn XML into JSON in your browser
Paste any well-formed XML and the JSON appears as you type — there is no Convert button to press. Each element becomes a JSON key named after its tag, and a namespace prefix stays part of that name, so <x:note> is written as "x:note". Element attributes are grouped under an @attributes object, text content is kept under a #text key, and when the same tag repeats inside a parent it is turned into an array so no value is lost. The order of differently named siblings is not kept, because JSON holds one key per name: <a/><b/><a/> comes out as both a elements, then the b. Entities such as & come back as the character they stand for, and a CDATA block keeps its raw text.
Compact mode and safe parsing
Compact mode, on by default, collapses text-only elements — an element with no attributes and no children — straight to their string value, which produces the tidy JSON most APIs expect. Turn it off and that same element is written as an object with a #text key, which keeps the structure explicit. The XML is parsed with the browser built-in DOMParser, so if a tag is unbalanced or the document is malformed you are given the line and the column of the problem, in the language of the page, instead of silent, wrong output. Attributes and nested elements are carried over, and an XML declaration is read but not written into the JSON. Mixed content keeps its text, joined into one #text and trimmed at the ends, but not its place among the child elements; comments and processing instructions are dropped.
How the JSON is written
JSON spacing offers five settings: two, four or eight spaces, one tab per level, or minified onto a single line. Root wrapper decides how much of the top to keep — the whole document under its root element's name, the root element's own value, or one level further down, which is the shape a list document is usually wanted in: <rows><row>a</row><row>b</row></rows> becomes ["a","b"]. That last step is refused, never guessed, when the level below the root holds anything other than exactly one key — the keys it found are named back to you instead of one of them being quietly thrown away.
Files and web addresses
Open an .xml, .svg, .rss, .atom, .xsd, .xsl, .plist or .txt file of up to 5 MB — a larger one is refused with both sizes rather than truncated — and the download is named after it, so orders.xml comes back as orders.json. You can also give a web address. Your own browser asks that host for the document, so it travels straight from there to you and never through this site, which is the trade-off for CORS: a host that does not allow being read by a page on another site cannot be loaded, and the tool says that is what happened rather than blaming the address. Something that is not an address is refused, not silently upgraded to an https:// host you did not name. The character encoding is taken from the host's own header, then from the document's <?xml encoding?> declaration, then UTF-8, so a EUC-KR feed served without a charset header still reads as Korean; a file opened from disk is read with the encoding you pick beside the Open file button — Auto, or one of ten code pages including EUC-KR, Shift_JIS, GB18030 and Big5. It pairs with the JSON to XML converter for the reverse direction: with its Attributes option on, as it is by default, attributes, namespace prefixes, repeated tags and every value come back as they were. What does not come back is what the JSON never held — the order of differently named siblings and where mixed text sat among the children.
And JSON back into XML
Press JSON → XML at the top: that side keeps its own input, separate from the XML → JSON side, and turns any valid JSON into a clean, indented XML document. Objects become nested elements keyed by each property name, arrays repeat their key so every item gets its own tag, and primitive values (strings, numbers, booleans) become the text inside an element. With the Attributes option on, as it is by default, a key starting with @ becomes an attribute, an @attributes object — the shape the XML → JSON side writes — becomes one attribute per member, and #text becomes the element's own text. A prefix:name key keeps its prefix only when an xmlns:prefix declaration on that element or one above it binds the prefix (xml: is always bound); otherwise the colon becomes _, because a prefix nothing declares is not XML a browser will read. You can rename the root element to match your schema, and the output updates live as you type; the result can be copied with a single click.
Safe, readable output
Characters that would break XML — &, <, >, and " — are escaped automatically inside text content, so the XML stays well-formed even when your JSON holds HTML snippets or quoted strings. Empty objects render as empty elements. An array repeats its key once per item, so an empty array produces no element for that key (a top-level [] gives an empty root element). Two-space indentation keeps deeply nested structures easy to read at a glance. Turn on the XML declaration option to prepend <?xml version="1.0" encoding="UTF-8"?> when you are saving the output as a standalone .xml file.
What survives the trip both ways
“Turn this JSON back into XML” and “Turn this XML back into JSON” hand a result to the other side, and the @attributes and #text shapes each side writes are the ones the other reads. Two things do not come back: the order of differently named siblings, because a JSON object has no order to keep it in — <a/><b/><a/> returns as a, a, b — and text that sits between child elements, which XML → JSON gathers into one #text.
Frequently asked questions
Is my XML uploaded anywhere?
Your XML is never uploaded. The conversion runs entirely in your browser with the built-in XML parser, and nothing you paste, open or type is sent to a server of ours — there is no server here that could store it. The one request this tool makes is the one you ask for: if you use “Load XML from a web address”, your own browser fetches that address directly, so the host you named sees the request, and the document goes straight from there to you without passing through this site.
How are attributes and repeated tags represented?
Attributes are placed under an @attributes object on the element, and text is kept under a #text key. When a tag name appears more than once inside the same parent, those elements are collected into a JSON array so every value is preserved. The order of differently named siblings is not: <a/><b/><a/> comes out as a, a, b.
What does Compact mode do?
Compact mode, which is on by default, collapses any element that has only text — no attributes and no child elements — into a plain string. Turn it off and that same element is written as an object with a #text key, which keeps the structure explicit.
What happens if my XML is invalid?
The tool detects parser errors such as mismatched or unclosed tags and tells you the line and the column where the parser gave up, written in the language of the page rather than handed over as the browser's own English console paragraph. You get that message instead of broken or misleading JSON.
Can I change the indentation or get the JSON on one line?
Yes. The “JSON spacing” menu has five settings: 2, 4 or 8 spaces per level, one tab per level, or minified onto a single line. Only the whitespace changes — every setting produces the same data.
How do I get rid of the root element in the output?
Use the “Root wrapper” menu. “Drop the root element” gives you the root's own value instead of { "root": … }, and “Drop the root and the level below” goes one step further, turning <rows><row>a</row><row>b</row></rows> into ["a","b"]. The second step is refused when the level below the root does not hold exactly one key — for example when the root also carries attributes — and the keys it found are named, because picking one would throw the others away.
Can I open an XML file instead of pasting it?
Yes. Open a .xml, .svg, .rss, .atom, .xsd, .xsl, .plist or .txt file of up to 5 MB. A larger file is refused with its size and the limit rather than converted in part, and the download takes its name from the file, so orders.xml comes back as orders.json. Files opened from disk are read with the encoding picked beside the Open file button; on Auto that is the byte-order mark, then the document's own encoding declaration, then UTF-8.
Can it load an XML feed from a URL?
Yes — paste an http:// or https:// address and press Load. Your own browser makes that request, so nothing passes through this site, but that is also why some addresses cannot be read: a host that does not allow a page on another site to read it (CORS) is refused with an explanation, as are an address that does not answer within 20 seconds, an HTTP error status, a body over 5 MB and an empty document. Text that is not an address at all is refused rather than silently turned into an https:// host you did not type.
My XML feed is EUC-KR, not UTF-8. Will it read correctly?
For a document loaded from a web address, yes. The encoding is taken from the charset the host declares in its Content-Type header, and if it declares none, from the document's own <?xml encoding="…"?> declaration, falling back to UTF-8 only when neither says anything. A file opened from your disk is read the same way, using the encoding you pick beside the Open file button.
Are namespaces, CDATA and entities preserved?
A namespace prefix stays part of the key, so <x:note> becomes "x:note", and the xmlns declaration itself appears among that element's @attributes. A CDATA block is read as its raw text, and entities such as & are decoded to the character they stand for.
How are JSON arrays converted to XML?
Each array item is written as its own element that repeats the property name. For example {"b":[2,3]} becomes <root><b>2</b><b>3</b></root>. A top-level array uses <item> tags because there is no property name to borrow.
Can I change the root element name?
Yes. Type any name in the Root element box and the outermost tag updates immediately. If you leave it blank it falls back to <root>.
Does it accept JSON with comments or trailing commas?
Yes. JSON.parse runs first, then JSON5, so trailing commas, unquoted keys and single quotes work. A // or /* */ comment is dropped, not turned into XML; use a #comment key.
Can I write CDATA sections, comments or processing instructions?
Yes. Tick "CDATA, comments, instructions (#cdata / #comment / ?name)" and a #cdata key becomes a CDATA section — a lone one sits inside its element as the text — a #comment key becomes an XML comment, and a key starting with ? becomes a processing instruction, so "?xml-stylesheet": {"href": "a.xsl"} gives <?xml-stylesheet href="a.xsl"?>. An array under one of these keys writes several. It is off by default, so a key that happens to be spelled that way stays an ordinary element. A ]]> inside CDATA is split across two sections and a -- in a comment gets a space, rather than the input being refused.