XML to JSON Converter

Paste XML on the left, get JSON on the right. Attributes preserved with the @_ prefix. Runs entirely in your browser — no upload.

  1. Paste XML into the left textarea.
  2. Click "Convert to JSON". Element nesting becomes nested objects.
  3. Copy the JSON, or download as data.json.
  4. Repeated child elements collapse into arrays automatically.
What does it do?

Parses XML into a JSON object using fast-xml-parser conventions: child elements become object properties, repeated children become arrays, attributes are preserved with the `@_` prefix on the parent object, and text content of mixed nodes lands on a `#text` key. Numeric and boolean attribute values are auto-typed via `parseAttributeValue: true` — an XML `count="42"` round-trips as `"@_count": 42`, not the string `"42"`.

Example

XML input:

<root version="1">
  <name>Ada</name>
  <tags>math</tags>
  <tags>logic</tags>
</root>

JSON output:

{
  "root": {
    "@_version": 1,
    "name": "Ada",
    "tags": ["math", "logic"]
  }
}

Common XML pitfalls and how to handle them

XML has corner cases that JSON does not. These are the patterns that produce surprising output.

  • Single child vs. multiple children. `<a><b/></a>` produces `{"a":{"b":""}}` (single child as object property), but `<a><b/><b/></a>` produces `{"a":{"b":["",""]}}` (multiple as array). If your downstream code always expects an array, normalize after conversion.
  • Attributes vs. child elements. Attributes appear with `@_` prefix on the same level as children. `<user id="1"><name>Ada</name></user>` becomes `{"user":{"@_id":1,"name":"Ada"}}`. Some tools merge attributes into properties — that is a different convention than the one used here.
  • Mixed content (text + child elements). `<p>Hello <b>world</b></p>` produces `{"p":{"#text":"Hello ","b":"world"}}`. The text gets captured but its position relative to children is lost — JSON has no way to represent ordered mixed content. Most config-style XML does not hit this case.
  • Namespaces. Namespaces (`<x:foo xmlns:x="...">`) are preserved as part of the element name (`x:foo`). Many XML consumers strip the prefix; if you need that, do it as a post-processing step.
  • CDATA sections. `<![CDATA[some text]]>` is parsed as plain text and joins the `#text` of its parent. The CDATA framing is lost — fine for most cases but worth noting if the framing was semantically meaningful.
  • Self-closing vs. empty. `<x/>` and `<x></x>` are equivalent in XML and produce the same JSON output (`""` for the value). The original framing is not recoverable from the JSON.
Frequently asked questions

Why does my output have an `@_` prefix on attributes?

It distinguishes XML attributes from child elements. Without a prefix, `<user id="1"><id>foo</id></user>` would have two `id` keys — a JSON object can only have one. The prefix keeps both round-trippable. If you do not need the prefix, replace `"@_"` with `""` in a post-processing step (and accept the collision risk).

Can I get the JSON without the wrapping root key?

XML always has a single root element. The JSON keeps that wrapping for round-trippability. Strip it after conversion if you want the inner object — `result.root` rather than `result`.

Are XML comments preserved?

No. JSON has no comment syntax, and the parser is configured to ignore XML comments. If you need to preserve comments, you would have to use a different intermediate representation that supports them.

Are attribute values typed?

Yes — `parseAttributeValue: true` is set, so `count="42"` becomes `"@_count": 42` (number) and `enabled="true"` becomes `"@_enabled": true` (boolean). If you need attributes as strings, post-process or fork the configuration.

Is my XML uploaded?

No. Everything runs in your browser — your XML is parsed by JavaScript on this page and never sent to any server. Verify in your browser developer tools.

Can it handle very large XML files?

Up to about 30 MB before the textarea slows down. The parser scales linearly. For larger inputs, run fast-xml-parser on the command line — same library.