Skip to content
CornerTools

XML to JSON Converter

Convert XML to JSON and back, with attributes, repeated elements and text handled the way you choose.

1
1
Characters: 0

Converts XML to JSON, and JSON back to XML, under a convention you can see and choose: how attributes are told apart from child elements, when a repeated element becomes an array, and where text goes. Both directions read and write the same convention, so a document converted one way comes back the other.

Numbers stay exactly as written, entity references declared in a DOCTYPE are never expanded, and errors in either input name their line and column. It runs in your browser: nothing you paste or open is sent anywhere.

Conventions and options

  • @ for attributes (the default) — an attribute is @name; text beside attributes or child elements is #text. CDATA joins the text; comments and processing instructions are dropped.
  • xml-js compact — the format of the xml-js library's compact mode: attributes under _attributes, text under _text, and _cdata, _comment and _instruction kept. An element is always an object there, {} when empty. Read back, xml-js's _declaration gives way to the declaration option, with a note when it gave a version other than 1.0, an encoding other than UTF-8 or standalone, and its _doctype is dropped, with a note. Converted back, a _comment holding -- or ending in -, an _instruction whose target is not an XML name or is xml in any case or whose content holds ?>, and a character XML 1.0 cannot hold are each an error naming where they sit; ]]> in _cdata is split across two CDATA sections, its text unchanged.
  • Plain keys — attributes and child elements share plain keys. An attribute named like a child element keeps an @, with a note. Converted back, plain keys are child elements, so attributes return as elements.
  • Lossless — every node in order: an element as { name, attributes, children }, text as a string, and CDATA, comments and processing instructions as one-key objects, with attribute values and entity references as written. Converted back, what would break the markup is an error naming where it sits: a < or a bare & in a value; an entity reference other than &amp;, &lt;, &gt;, &quot;, &apos; and numeric ones, since only a DOCTYPE declares it and none is written; ]]> in text or CDATA; a character XML 1.0 cannot hold, written or as a numeric reference; -- in a comment, or a comment ending in -; a processing instruction whose target is not an XML name or is xml in any case, or which holds ?>; text or CDATA outside the root element; or a second root.

Always use arrays makes every element an array, so code reading the JSON need not check whether a list has one item. Numbers and booleans as JSON values turns text that reads as a JSON number or true / false into one, written exactly as in the XML; it is off by default, so ids and codes such as 007 stay intact. Keep the root element and Strip namespace prefixes (which also drops the xmlns declarations) shape the top of the JSON; an attribute keeps its prefix, with a note, where another attribute of its element already has its name without one. Child elements whose names match once stripped, such as a:x and b:x, share one key and become one array, with a note.

From JSON to XML, a JSON object with one key becomes that root element; anything else is wrapped in the Root name (root by default), with each item of a top-level array as an item. Keys that are not XML names are renamed (1abc to _1abc, a b to a_b), and two attributes that renaming gives one name, such as @a b and @a_b, are an error. null is an empty element, an array nested in an array writes an item per value, and an empty array writes no element. A prefixed key such as soap:Body is written as it is, with a warning when no @xmlns:soap above it declares the prefix, since namespace-aware tools reject such XML. Switching between the two directions carries the output into the input.

How elements map

An element's value is its text when it has nothing else; otherwise an object holding its attributes first, then its text and children, each key in the order it first appears. Whitespace between elements is formatting and is dropped, except under xml:space="preserve". Text inside an element is kept as written, line breaks and all. The five predefined references and numeric character references are read; an attribute's tabs and line breaks become spaces, as an XML parser reads them.

Text mixed with child elements, such as a paragraph with a bold word, keeps its pieces in order under the text key, but the readable conventions cannot say where each sat between the children; a note says so. Lossless keeps it.

Examples

A SOAP response to JSON

Input XML
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  <soap:Body>
    <m:Price xmlns:m="https://example.com/prices" currency="INR">
      <m:Item>Apples</m:Item>
      <m:Amount>0120.50</m:Amount>
    </m:Price>
  </soap:Body>
</soap:Envelope>
Output, default options
{
  "soap:Envelope": {
    "@xmlns:soap": "http://www.w3.org/2003/05/soap-envelope",
    "soap:Body": {
      "m:Price": {
        "@xmlns:m": "https://example.com/prices",
        "@currency": "INR",
        "m:Item": "Apples",
        "m:Amount": "0120.50"
      }
    }
  }
}
Output, Strip namespace prefixes on, Keep the root element off
{
  "Body": {
    "Price": {
      "@currency": "INR",
      "Item": "Apples",
      "Amount": "0120.50"
    }
  }
}

The amount stays the string 0120.50, its leading zero intact; with Numbers and booleans as JSON values on, it would still be a string, since 0120.50 is not a JSON number.

Mixed content, readable and lossless

Input XML
<p>Tea <b>with</b> milk<!-- house blend --></p>
@ for attributes
{
  "p": {
    "#text": [
      "Tea ",
      " milk"
    ],
    "b": "with"
  }
}
Lossless
[
  {
    "name": "p",
    "attributes": {},
    "children": [
      "Tea ",
      {
        "name": "b",
        "attributes": {},
        "children": [
          "with"
        ]
      },
      " milk",
      {
        "comment": " house blend "
      }
    ]
  }
]

The readable form keeps both pieces of text but not that with sat between them, and drops the comment. Lossless keeps every node in order.

JSON to XML

Input JSON, JSON → XML, default options
{
  "order": {
    "@id": "A-17",
    "customer": "Asha & Co",
    "items": [
      { "sku": "007", "qty": 2 },
      { "sku": "012", "qty": 1 }
    ],
    "note": null
  }
}
XML output
<?xml version="1.0" encoding="UTF-8"?>
<order id="A-17">
  <customer>Asha &amp; Co</customer>
  <items>
    <sku>007</sku>
    <qty>2</qty>
  </items>
  <items>
    <sku>012</sku>
    <qty>1</qty>
  </items>
  <note/>
</order>

@id becomes an attribute, the array repeats items, the ampersand is escaped, and null is an empty element.

XML and its JSON

With the default options
XML@ for attributesxml-js compact
<a>text</a>{"a":"text"}{"a":{"_text":"text"}}
<a x="1"/>{"a":{"@x":"1"}}{"a":{"_attributes":{"x":"1"}}}
<a x="1">text</a>{"a":{"@x":"1","#text":"text"}}{"a":{"_attributes":{"x":"1"},"_text":"text"}}
<a><b>1</b></a>{"a":{"b":"1"}}{"a":{"b":{"_text":"1"}}}
<a><b>1</b><b>2</b></a>{"a":{"b":["1","2"]}}{"a":{"b":[{"_text":"1"},{"_text":"2"}]}}
<a/>{"a":""}{"a":{}}
<a>x<![CDATA[<y>]]></a>{"a":"x<y>"}{"a":{"_text":"x","_cdata":"<y>"}}
<p>a <b>b</b> c</p>{"p":{"#text":["a "," c"],"b":"b"}}{"p":{"_text":["a "," c"],"b":{"_text":"b"}}}

Standards

XML is read as XML 1.0 (Fifth Edition) defines it, and checked for well-formedness as the XML Formatter does. Prefixes and xmlns follow Namespaces in XML 1.0.

Sources

Reviewed

Frequently asked questions

By default an element becomes an array only when it repeats inside its parent, so a list with one item is an object and the same list with two is an array. Turn on Always use arrays when code reads the JSON, so every element has one shape.
The XML declaration's spelling (one is written anew), the DOCTYPE, the quote style of attributes whose value holds no quote, <a/> against <a></a>, and whitespace inside tags. Elements, attributes, text, CDATA, comments and processing instructions come back in order. Entity references the DOCTYPE declares stay in the JSON as written, but without the DOCTYPE they cannot be converted back to XML; a note names them.
XML defines only five named entities; any other is declared in the document's DOCTYPE. Expanding them is how entity bombs work, so they are left as written, with a warning naming them. From JSON to XML, Lossless refuses them, as the output has no DOCTYPE to declare them, and the readable conventions escape their &, writing them as text.

See also