XML to JSON Converter

Convert XML to JSON in your browser — your XML never leaves your browser, and nothing you paste is uploaded.

Or drag and drop a file onto this box. The file is read in your browser and never uploaded. The encoding named in the XML declaration is used.
Options
The text key holds the text of an element that also has attributes or child elements. It cannot be empty or __proto__.
Advanced options

XML has no data types, so values stay strings unless you turn on type inference. For XML exported by this site, turn on type inference and keep Auto arrays: records of plain text, numbers and booleans convert back to the same JSON. Null, numbers stored as text, very large integers, empty arrays and objects, and arrays do not survive an XML round trip, because XML has no types. Exports with several top-level keys have no single root, so tick Wrap multiple root elements. With inference on, a number is converted only if it reads back exactly as written, so numbers beyond 2^53 stay strings.

    Your XML never leaves your browser; nothing you paste is uploaded. The two Send buttons pass the result between pages inside your browser tab only.

    XML to JSON conversion turns tagged documents into data that JavaScript, REST clients and databases can read directly. You decide how attributes, repeated elements, namespaces and CDATA map to JSON, and your XML stays in your browser.

    How do I convert XML to JSON?

    Paste your XML into the input box or upload an .xml file, and the JSON appears in the output box as soon as you stop typing. Check the root name and key count above the output, adjust any options, then copy the result, download it as a .json file, or send it to the JSON Formatter. Nothing is uploaded.

    How to use this XML to JSON converter

    • Add your XML by pasting it, choosing a file or dropping one on the upload box. Load sample XML inserts an example.
    • Pick the options: attribute prefix, text key, Auto or Always arrays, namespaces, indent, and optional type inference (off by default).
    • Open Advanced options to keep CDATA, comments or the XML declaration, or to turn empty elements into an empty string, null or nothing.
    • Copy, Download as .json, Send to JSON Formatter, or Validate against a schema. Results over about 2 MB show a preview, but all four buttons use the whole result.
    • Large inputs: live updates pause above about 1 MB, so press Convert. Cancel appears after a second.

    Afterwards, the JSON Formatter beautifies and explores the result, the JSON Schema Validator checks its shape, and Compare JSON shows what changed between conversions. For spreadsheet data use CSV to JSON.

    What happens to XML attributes in JSON?

    JSON has no attributes, so each XML attribute becomes a key with a prefix, @_ by default, which keeps it apart from a child element of the same name. You can change the prefix to @ or _, or ignore attributes. When an element has attributes and text, the text is stored under the key #text, which you can rename.

    Why does a single XML element become an object instead of an array?

    XML has no array type, so a list is just an element that repeats. A repeated element becomes a JSON array, but an element that appears once stays a single object or string, so a list with one item changes shape. Set Arrays to Always arrays to make every child element an array, even when it appears once.

    When to use Always arrays

    Always arrays gives your code one shape: every child element is an array, so item[0] works whether the file holds one item or fifty. The root stays an object and attributes are never arrays. The cost is noise, since a plain name becomes a one-item array.

    How are CDATA, comments and namespaces handled?

    By default CDATA text is merged into the surrounding text, comments and the XML declaration are dropped, and namespace prefixes stay in the key names, such as dc:creator. Advanced options keep CDATA as #cdata, comments as #comment and the declaration as ?xml. Strip prefixes removes namespace prefixes and merges keys that collide into an array.

    What happens when stripped prefixes collide

    Elements such as a:id and b:id both become id when prefixes are stripped, so they merge into one array and a warning counts the merged keys. If stripping would make two attribute names identical, those attributes keep their prefixes and the warning counts them. Declarations such as xmlns:a are never stripped.

    Worked example: attribute, repeated element and CDATA

    Both outputs were copied from this converter. The XML has attributes on the root, a repeated item element and a CDATA section; only the Arrays option differs.

    XML input

    <order id="A-1001" status="shipped">
      <customer>Ada Lovelace</customer>
      <item sku="K-42">Keyboard</item>
      <item sku="M-17">Mouse</item>
      <note><![CDATA[Fragile: <handle> with care & smile]]></note>
    </order>

    Arrays: Auto (default)

    {
      "order": {
        "@_id": "A-1001",
        "@_status": "shipped",
        "customer": "Ada Lovelace",
        "item": [
          {
            "@_sku": "K-42",
            "#text": "Keyboard"
          },
          {
            "@_sku": "M-17",
            "#text": "Mouse"
          }
        ],
        "note": "Fragile: <handle> with care & smile"
      }
    }

    Arrays: Always arrays

    {
      "order": {
        "@_id": "A-1001",
        "@_status": "shipped",
        "customer": [
          "Ada Lovelace"
        ],
        "item": [
          {
            "@_sku": "K-42",
            "#text": "Keyboard"
          },
          {
            "@_sku": "M-17",
            "#text": "Mouse"
          }
        ],
        "note": [
          "Fragile: <handle> with care & smile"
        ]
      }
    }

    With Auto, the item elements become an array of objects holding the sku attribute and text, and the CDATA arrives as ordinary text. With Always arrays, customer and note become one-item arrays too, but the attributes stay as they were.

    XML to JSON gotchas

    There is no single standard for converting XML to JSON. Conventions such as BadgerFish and Parker exist and libraries use their own, so the same XML can give different JSON in different tools. Every example below comes from this converter with default settings unless stated.

    Attributes and child elements can look alike

    These two documents carry the same information but convert differently:

    id as an attribute

    <book id="1">
      <title>Dune</title>
    </book>
    {
      "book": {
        "@_id": "1",
        "title": "Dune"
      }
    }

    id as a child element

    <book>
      <id>1</id>
      <title>Dune</title>
    </book>
    {
      "book": {
        "id": "1",
        "title": "Dune"
      }
    }

    The prefix is part of the key, so code must know which form the source used. Set Attributes to Ignore if you do not need them.

    One item is an object, two items are an array

    One item, Auto

    {
      "list": {
        "item": "apple"
      }
    }

    Two items, Auto

    {
      "list": {
        "item": [
          "apple",
          "pear"
        ]
      }
    }

    One item, Always arrays

    {
      "list": {
        "item": [
          "apple"
        ]
      }
    }

    A parser cannot tell a one-item list from a single value, so the shape of item depends on the data. Always arrays removes that surprise.

    Mixed content loses its order

    When an element holds text and child elements, JSON cannot record where each piece sat. The text pieces are joined end to end into one #text value.

    XML input

    <p>Hello <b>bold</b> and <i>italic</i> world.</p>

    JSON output

    {
      "p": {
        "#text": "Hello  and  world.",
        "b": "bold",
        "i": "italic"
      }
    }

    Hello, and and world. are joined with only the spaces that were already there, so they run together with double spaces, and the position of bold and italic is gone. If order matters, keep the data in XML.

    Namespace prefixes and collisions

    Two namespaces can reuse a local name. Stripped prefixes make the keys collide and merge:

    XML input

    <r xmlns:a="urn:a" xmlns:b="urn:b">
      <a:id>1</a:id>
      <b:id>2</b:id>
    </r>

    Namespaces: Keep prefixes (default)

    {
      "r": {
        "@_xmlns:a": "urn:a",
        "@_xmlns:b": "urn:b",
        "a:id": "1",
        "b:id": "2"
      }
    }

    Namespaces: Strip prefixes

    {
      "r": {
        "@_xmlns:a": "urn:a",
        "@_xmlns:b": "urn:b",
        "id": [
          "1",
          "2"
        ]
      }
    }

    The warning reads Prefix stripping merged keys: 1. The xmlns declarations keep their names.

    Round trip with the JSON Formatter's XML export

    The JSON Formatter can export XML and this page can read it back, but not losslessly. A key becomes the root only when an object has one top-level key; several keys, or a top-level array, produce side-by-side elements, so tick Wrap multiple root elements in <root>. Array items are named by dropping a trailing s (tags becomes tag) or adding _item (book becomes book_item), and null is written as the text null. Our guide to converting JSON to CSV, XML and YAML covers the export, and JSON vs XML compares the formats.

    Is my XML uploaded anywhere?

    No. Your XML never leaves your browser, and nothing you paste is uploaded. Conversion runs locally in a background worker, using a copy of the open-source fast-xml-parser library served from this site. The page uses Google Analytics for anonymous usage counts, which never include your XML, tag names, attribute names or file names.

    Uploaded files are read locally too. The Send buttons hand the result over through session storage in your tab, and the receiving page removes it once read.

    What are the limitations of this converter?

    Values are text unless you turn on type inference, the order of mixed content is lost, and the converter stops at 1,000 levels of nesting. It also refuses output above about 20 MB and files above 100 MB. A DOCTYPE is ignored, so custom entities are never expanded, and a notice tells you when that happens.

    Whitespace-only text between child elements is always dropped, even when Trim whitespace is off, because it is indentation. Numeric character references such as &#65; are decoded, invalid ones are rejected with a line and column, and undefined entities such as &copy; stay as written.

    Type inference is decided per element path, all or nothing: 007, 1.50, 1e5 and numbers beyond 2^53 keep the whole path as text, and a notice names the path and the first blocking value. That notice appears on the page only; analytics never receive paths, names or values.

    Frequently Asked Questions

    How do I convert XML to JSON?

    Paste your XML or upload an .xml file, keep the default options, and the JSON appears in the output box. Then copy it, download it as a .json file, or send it to the JSON Formatter. Nothing is uploaded.

    What happens to XML attributes?

    Each attribute becomes a key with a prefix, @_ by default, so it cannot be confused with a child element. Choose the prefix @ or _, or ignore attributes. An element with attributes and text keeps its text under the key #text.

    Why does a single XML element become an object instead of an array?

    XML has no array type. An element becomes an array only when it repeats, so a list with one item looks like a single object or string. Choose Always arrays to make every child element an array.

    How are CDATA, comments and namespaces handled?

    CDATA is merged into the text by default and comments are dropped, but both can be kept as #cdata and #comment. Namespace prefixes stay in key names, or you can strip them, in which case colliding keys merge into an array and a warning counts them.

    Is my XML data uploaded?

    No. Conversion runs in your browser, and your XML never leaves it. Nothing you paste or upload is sent to a server.

    Built and maintained by Deepak Kumar. Your XML never leaves your browser, and nothing you paste is uploaded.