induwara.lk
induwara.lkDeveloper · Utility

XML to JSON Converter

Paste or upload an XML document and get clean, well-formed JSON instantly. Handles attributes, nested elements, repeated elements as arrays, and CDATA — all in your browser, with nothing uploaded. Copy or download in one click.

By Induwara AshinsanaUpdated Jun 29, 2026
XML to JSON
Runs in your browser

Added to attribute keys (e.g. @_id). Blank = no prefix.

Holds an element's text when it also has attributes/children.

317 characters, 12 lines.

Verified — re-parses as valid JSON · 9 elements · 5 attributes.

Elements
9
Total XML elements
Attributes
5
Across all elements
Max depth
3
Deepest nesting (root = 1)
Output size
468 B
317 B in

Sources: grammar per W3C XML 1.0, output per RFC 8259. Everything stays on your device.

How it works

This converter is a deterministic tree transform: it reads XML shaped by the W3C XML 1.0 grammar and emits JSON shaped by RFC 8259. There is no external API and no server round-trip, and — unlike many online converters — no DOMParser dependency either: a small hand-written, well-formedness-checking parser runs the same in the browser and during server rendering, so API responses and config files never leave your device.

  1. Read the prolog. An optional <?xml …?> declaration, comments, processing instructions, and a DOCTYPE are skipped. The document must then have exactly one root element (an XML well-formedness rule).
  2. Tokenize elements and attributes. Start tags, end tags, and self-closing tags are matched; attribute values must be quoted, and a duplicate attribute name on one element is rejected. A start tag must be closed by an end tag with the same name, or the parser stops with a line/column error rather than guessing.
  3. Decode text. Outside CDATA, the five predefined entities (&lt;, &gt;, &amp;, &quot;, &apos;) and numeric character references such as &#65; are decoded. CDATA content is kept verbatim, including its < and &.
  4. Map the tree to JSON using the documented fast-xml-parser convention: attributes become keys with the configurable prefix (default @_); a text-only element with no attributes becomes its string directly; otherwise its text moves under the configurable key (default #text).
  5. Collapse repeated siblings. Two or more child elements with the same tag name become a JSON array in document order, so <book/><book/> becomes "book": [ … ]. Empty elements become an empty string (or an object holding just their attributes); inter-element formatting whitespace is dropped.
  6. Coerce values (optional). By default every leaf is a string, so the conversion is lossless. With Parse numbers/booleans on, leaves matching the JSON number grammar (RFC 8259 §6) become numbers and exact true/false become booleans. Because that grammar forbids leading-zero integers, an identifier such as 0712345678 stays a string, and integers past 253−1 are kept as strings to avoid precision loss.
  7. Serialize per RFC 8259 §6–§7. Output is produced with the native JSON.stringify, which already escapes strings and emits valid number, boolean, and null literals.

Every successful run is cross-checked: the emitted text is parsed back with the browser's standards-compliant JSON.parse, and the summary line under the output confirms it re-parses as a JSON object and reports the element and attribute counts.

Worked examples

Attributes and text-only children (default options)

XML input

<note id="1" priority="high">
  <to>Tove</to>
  <from>Jani</from>
</note>

JSON output

{
  "note": {
    "@_id": "1",
    "@_priority": "high",
    "to": "Tove",
    "from": "Jani"
  }
}
  • The root <note> has attributes, so it becomes an object; each attribute gets the @_ prefix.
  • <to> and <from> are text-only with no attributes, so they become their string values directly.

Repeated elements become an array, with mixed content

XML input

<library>
  <book lang="en">Clean Code</book>
  <book lang="si">Sapientia</book>
</library>

JSON output

{
  "library": {
    "book": [
      { "@_lang": "en", "#text": "Clean Code" },
      { "@_lang": "si", "#text": "Sapientia" }
    ]
  }
}
  • Two <book> siblings with the same tag collapse into an array in document order.
  • Each <book> carries an attribute and text, so its text is stored under #text.

Number coercion on, including edge values

XML input

<item>
  <qty>3</qty>
  <price>250.00</price>
  <code>007</code>
  <name>Tea</name>
</item>

JSON output

{
  "item": {
    "qty": 3,
    "price": 250,
    "code": "007",
    "name": "Tea"
  }
}
  • With Parse numbers/booleans on, 3 → number and 250.00 normalises to 250.
  • 007 has a leading zero, which the JSON number grammar forbids, so it stays a string and is not mangled to 7.
  • name is non-numeric, so it stays a string. With the toggle off, all four would be strings — fully lossless.

Frequently asked questions

Sources & references

The grammar and mapping rules on this page were last cross-checked against the W3C XML 1.0 specification and RFC 8259 on 2026-06-29. The page is reviewed whenever a relevant standard or edge-case bug report comes in.

Related tools

Rate this tool
Be the first to rate

Comments & feedback

Spotted a bug or want an improvement? Tell us — our team reviews every comment, and good ideas get built. Comments are public and anonymous.

Found an XML edge case that does not convert right, or want a new option?

Email me at [email protected] — most fixes ship within 24 hours.