Published: May 13, 2021 Updated: Sep 3, 2026

XML to JSON Converter Free Tool





About XML to JSON Converter

What This Tool Actually Does

This page hosts a browser-only XML to JSON converter, and you paste XML into the left box, press the button, and the right box shows the JSON equivalent, so the entire conversion happens locally in your browser. The conversion happens entirely in your browser without any server upload. The work happens inside your browser tab with the open-source x2js library, first released by Abdulla Abdurakhmanov around 2011 and licensed under Apache 2.0. No copy of your XML travels to this server, and the conversion makes no network request at all.

The converter follows a fixed set of mapping rules, and every element becomes a JSON key, and a text-only element becomes a plain string, so the output structure is always predictable. The output structure mirrors the input hierarchy directly for each node. Attributes become keys with an underscore prefix, so id="7" turns into _id. When an element carries both attributes and text, the text sits under a special key named __text. Repeated sibling elements become a JSON array, while a single element becomes an object. Empty elements become empty strings. Every value, including numbers, stays a string.

You also get one checkbox labeled "Remove top-level root", and when checked, the converter drops the outermost wrapper key and promotes its contents to the top level, which gives you direct access to the inner data. That option changes the output shape for that single element. It matters when you feed in a document with a single root element and you want the JSON to start at the first meaningful child.

The tool cannot upload files, cannot download results, cannot convert JSON back to XML, and will not detect types, so it is a focused, single-direction converter with predictable output that always follows the same rules. The rules are listed with live test results and a corrected description of what the page previously claimed.

A typical configuration file has a root element, several child elements with attributes, and some text values. You have a root element, several child elements with attributes, and some text values. The converter walks each node in document order and builds the JSON object step by step. There is no reordering, no sorting, and no deduplication. What appears in the XML is what appears in the JSON, subject to the mapping rules described below.

The practical value of this tool is its determinism, and feed the same XML twice and you get byte-identical JSON twice, because the mapping rules never change between runs. That predictability makes it useful for testing, for quick inspection of API responses, and for understanding how a third-party XML structure maps to JSON before you write code to handle it.

How to Use This Tool

  1. Open the tool page. Find the input box above this article, labelled "XML Input", and click into it.
  2. Paste your XML. Drop a complete XML document or fragment into the left textarea. Whitespace-only input does nothing.
  3. Set the root option. Tick "Remove top-level root" if you want the single wrapper element dropped from the JSON output.
  4. Run the conversion. Press the button labelled "Convert XML To JSON". The result appears in the right textarea with three-space indentation.
  5. Watch for the alert. If your XML is not well-formed, a browser alert reads "Invalid XML entered." and the output box stays unchanged.
  6. Clear the boxes. Use "Clear Input" to reload the page and start over. There is no download and no copy button, so select the JSON text manually.

The conversion also fires when the input box loses focus after a change. You can paste XML, click anywhere else on the page, and the JSON updates without pressing the button. Both paths run the same code with the same rules.

For a typical workflow, you might start with a small XML snippet from an API documentation page. Paste it, decide whether you want the root wrapper, and read the JSON output to understand the structure. If the XML is malformed, you will see the alert immediately and can fix the markup before converting again.

The page itself is minimal by design. There is no file picker, no settings panel, no history of past conversions, and no export function. The textareas are the entire interface, apart from the checkbox and the two buttons. That simplicity means you can learn the whole tool in under a minute.

The Mapping Rules, One by One

The x2js library applies a strict, deterministic set of rules. There are no configuration dialogs here, no toggles for attribute prefixes, no options for type detection. Every input yields the same output every time. What you see is what the library produces.

Every element in your XML becomes a key in the JSON object. The element name is used as-is, minus any namespace prefix. Text that sits directly inside an element, with no child elements, becomes a plain string value. So <name>Ada</name> becomes "name":"Ada".

Attributes become keys prefixed with a single underscore. The XML <book id="b1"> produces "_id":"b1". The prefix is always an underscore character. When an element has both attributes and text, the text moves under the reserved key __text. The element <item id="1">A</item> becomes {"_id":"1", "__text":"A"}.

Repeated sibling elements with the same name become an array. Two <item> elements under one parent produce "item":[{...}, {...}]. A single <item> element produces "item":{...} as an object. That rule is fixed and does not depend on any setting.

Empty elements become empty strings. The element <empty/> produces "empty":"". Namespace declarations appear as attribute keys with the _xmlns prefix, so xmlns:ns="urn:x" becomes "_xmlns:ns":"urn:x". The internal __prefix key that x2js uses during parsing is removed from the final output.

Every value in the output is a string. The library keeps the characters exactly as they appeared in the XML. That rule applies to integers, decimals, dates, and booleans alike.

Nested elements with attributes become nested JSON objects. Suppose you have a product catalog with a root element, a category attribute, and several product children. Each product has a name, a price, and an optional description. The converter builds an object for the root, an object for each product, and plain strings for the leaf values. The category attribute becomes _category on the root object. If one product lacks a description, that key simply does not appear in its object.

The order of keys within an object follows the order of appearance in the XML. Attributes come first, then text content, then child elements. That ordering is stable across runs, which helps when you diff two outputs or write tests against the JSON structure.

Five Live Examples in a Table

The live test run for this rewrite produced five concrete outputs. Each row below shows the input and the exact JSON that the tool returned on 2026-09-04.

Input XML JSON output
<root><item id="1">A</item><item id="2">B</item><single>x</single><empty/><n>42</n></root> {"root":{"item":[{"_id":"1","__text":"A"},{"_id":"2","__text":"B"}],"single":"x","empty":"","n":"42"}}
Same input with one item and root removal {"item":{"_id":"1","__text":"A"}}
<a><b>1</b></a> with root removal {"b":"1"}
<ns:a xmlns:ns="urn:x"><ns:b>1</ns:b></ns:a> {"a":{"b":{"__text":"1"},"_xmlns:ns":"urn:x"}}
<broken><x></broken> Alert "Invalid XML entered.", empty output

The first row shows the full rule set in action. Two repeated <item> elements become an array, the single <single> element becomes a plain string, the empty element becomes an empty string, and the numeric-looking text stays a string. The second row shows what happens when only one <item> exists and the root is removed. It becomes an object.

The third row shows a nested element with text only. With root removal, the wrapper a disappears and {"b":"1"} is the entire output. The fourth row shows namespace handling. The prefix ns vanishes from the element names, and the namespace declaration survives as _xmlns:ns. The fifth row shows the error path. The malformed input triggers the alert and leaves the output untouched.

These five cases cover the core behaviours you will encounter in practice. The first row is the most instructive because it packs four distinct rules into one small document. Study that row and you understand how the converter treats repetition, singletons, emptiness, and numeric text.

How to Predict Arrays Versus Objects

The single most common question about this converter is when you get an array and when you get an object. Repeated sibling elements become an array. A single element becomes an object. That is the whole rule, with no settings involved.

Consider a <books> element containing two <book> children. You get "book":[{...}, {...}]. Now consider the same <books> element with only one <book> child. You get "book":{...}. The shape of your JSON changes based on the number of siblings in the source XML.

That behaviour creates a practical problem for consumers of your JSON. Code that expects an array will break when the XML has only one item, because it receives an object. Code that expects an object will break when the XML has two or more items. You can write defensive checks, or you can normalise the output yourself after conversion.

The rule applies at every level of the document. If a parent element has repeated children of one name and a single child of another name, the repeated name becomes an array and the single name becomes an object. The decision is made independently for each element name.

Empty elements follow the same logic. Two empty <note/> siblings become "note":["", ""]. One empty <note/> becomes "note":"". The type of the value changes from string to array based on repetition, and that matters when you process the JSON programmatically.

A realistic scenario uses a product feed with categories and prices. An API returns a list of users, and you are testing with a single user record. The XML has one <user> element, so your JSON has "user":{...}. Your JavaScript code that does users.map(...) fails because users is an object, not an array. You need a guard like Array.isArray(data.user) ? data.user : [data.user] to handle both shapes.

The same issue appears in Python. If you parse the JSON with the standard library and expect a list of dictionaries, a single-element XML gives you a dictionary instead. Your loop over the list breaks. The fix is the same normalisation step, checking whether the value is a list before iterating.

This array-versus-object behaviour is the most common source of surprise for new users of this tool. It is also the behaviour most likely to differ between XML to JSON converters. Some libraries always produce arrays for elements that could repeat. Others, like x2js as configured here, make the array decision based on the actual document content.

What Happens to Namespaces

XML namespaces are a common source of confusion in conversion tools. This converter handles them in a specific way. The namespace prefix is stripped from the element name, and the namespace declaration itself becomes an attribute key.

Take the input <ns:a xmlns:ns="urn:x"><ns:b>1</ns:b></ns:a>. The output is {"a":{"b":{"__text":"1"},"_xmlns:ns":"urn:x"}}. The element ns:a becomes the key a, and the element ns:b becomes the key b. The declaration xmlns:ns="urn:x" becomes "_xmlns:ns":"urn:x" at the level where it appeared.

The design creates several outcomes. If two different namespaces use the same local element name, the JSON keys collide. The converter does not disambiguate them. The namespace URI itself is preserved only in the _xmlns attribute key, so you can recover the mapping if you need it. Default namespaces, declared without a prefix, appear as _xmlns. The value is the default namespace URI.

If your XML relies heavily on namespaces for meaning, you will need to inspect the _xmlns keys to reconstruct the full picture. The conversion is lossy in that sense, since the prefix-to-URI mapping is flattened into a handful of attribute keys.

Consider a SOAP envelope, which uses multiple namespaces for the envelope, the header, the body, and the payload. Converting such a document with this tool strips all the prefixes and leaves you with generic names like Envelope, Header, and Body. The _xmlns keys tell you which URI each declaration pointed to, but you must do the mental work of matching them back to the elements.

For documents that use namespaces purely as a formality, with a single namespace throughout, the stripping is harmless. The local names are unique, and the _xmlns key simply records the one URI. For documents that mix several vocabularies, you should expect collisions and plan for them in your downstream code.

What Happens to Empty Elements

Empty elements follow a simple rule. They become empty strings. The element <empty/> produces "empty":"". The element <empty></empty> produces the same result, since the parser treats both forms identically. That rule has a subtle consequence when you combine it with the array rule. Two empty siblings become "empty":["", ""]. The JSON now contains an array of empty strings, which is a different shape from the single empty string. Your downstream code needs to handle both.

The converter also drops comments and processing instructions. Anything inside <!-- --> or <? ... ?> never appears in the JSON output. CDATA sections become plain text, so <![CDATA[<b>bold</b>]]> turns into the string <b>bold</b> with the markup preserved as characters.

Whitespace handling is configured with stripWhitespaces enabled. Leading and trailing whitespace around text content is removed. Indentation between elements does not become part of the text values. That keeps the JSON clean but means you lose the exact whitespace from the original document.

Consider an XML file that uses indentation for readability. Each line starts with spaces, and elements are nested with increasing indentation. Without whitespace stripping, those spaces would appear in your text values and clutter the JSON. With stripping enabled, the text values contain only the meaningful content between the tags.

The trade-off appears when your XML uses whitespace intentionally. A <pre> element in an XHTML document, for example, might contain leading spaces that matter for display. Those spaces are stripped, and the JSON no longer reflects the original content exactly. For data-oriented XML, the stripping is almost always what you want. For document-oriented XML, it can lose information.

Why Numbers Stay Strings

The converter makes no attempt to detect types. Every value in the output is a string, including values that look like numbers. The input <n>42</n> produces "n":"42", with the quotes in the JSON marking it as a string. That behaviour comes from the x2js library design. The library reads XML text nodes and assigns them to JSON values without parsing them as numbers, booleans, or dates. There is no type detection option in this tool, and no way to enable one.

The practical effect is that you lose JavaScript type coercion. If you write code that adds parsed.n to another number, you get string concatenation. You need to call Number() or parseInt() on the values yourself.

The same applies to booleans. The XML <flag>true</flag> produces "flag":"true", with the string value. The string "true" is truthy in JavaScript, so conditional checks work by accident, but strict equality checks against the boolean true fail. Dates, decimals, and scientific notation all stay as their original text.

A real integration requires handling API rate limits and error responses. You convert an XML order feed that contains prices, quantities, and timestamps. The JSON output has every one of those values as strings. When you load that JSON into a JavaScript application, you must convert the price with parseFloat(), the quantity with parseInt(), and the timestamp with new Date(). None of that happens automatically.

The same applies in Python. The json module gives you strings for all those values. You need float() for the price, int() for the quantity, and datetime.fromisoformat() for the timestamp. The conversion step is entirely on you.

Some XML to JSON converters attempt type inference, guessing that a digit-only value is a number and true is a boolean. This tool does not. The advantage of the string-only approach is predictability. You never have to wonder whether a value came through as a number or a string, because the answer is always the same. The cost is the extra conversion work in your own code.

Mixed Content and Text Next to Elements

XML allows text to appear directly inside an element alongside child elements. That construct is called mixed content. The converter handles it in a limited way. When an element has both attributes and text, the text goes under __text. That rule covers the common case of <item id="1">A</item>. The text A is not a child element, so it becomes the __text value.

When an element has child elements and text between them, the behaviour is less faithful. The library does not preserve the exact interleaving of text and child elements. Text that appears between children may be dropped or merged in ways that do not round-trip.

The live test for this rewrite did not exercise mixed content with text between children, so the precise output for that case is not documented here. The safe approach is to avoid mixed content in your source XML if you need a faithful JSON representation. Use attributes for metadata and keep text-only elements for content.

Consider a paragraph element in a document format that mixes bold and italic spans with plain text. The XML might look like <p>Hello <b>world</b> and <i>friends</i>.</p>. The text "Hello ", " and ", and "." sits between child elements. A faithful conversion would preserve the order of text and elements. This converter does not guarantee that, so the output may lose some of the text nodes or merge them in unexpected ways.

For data-oriented XML, mixed content is rare. You typically see either text-only elements or elements with children, not a blend of both. If your source documents follow that pattern, you will not encounter the limitation. If they do contain mixed content, you should test a sample before relying on the conversion.

The "Remove Top-Level Root" Option

The checkbox labelled "Remove top-level root" changes the shape of the output in one specific situation. When the parsed JSON has exactly one top-level key, checking the box drops that wrapper key and promotes its value to the top level.

The live tests show the effect clearly. The input <a><b>1</b></a> with root removal produces {"b":"1"}. Without the checkbox, the output would be {"a":{"b":"1"}}. The wrapper key a disappears. The condition matters. The option only applies when there is exactly one top-level key. XML with more than one top-level element is not well-formed, so it triggers the 'Invalid XML entered.' alert and the checkbox never comes into play.

The option is useful when you want to merge the converted JSON into a larger structure. You can paste a fragment, check the box, and get the contents without the outer document element. That saves a manual step of unwrapping the result in your own code.

Think about a sitemap file. The root element is <urlset>, and it contains many <url> children. Without root removal, your JSON looks like {"urlset":{"url":[...]}}. With root removal, it becomes {"url":[...]}. The second shape is often more convenient when you are building a data structure that does not need the sitemap wrapper.

The same logic applies to any single-root XML document. An RSS feed has <rss> as its root. An Atom feed has <feed>. A configuration file might have <config>. In each case, root removal gives you direct access to the meaningful content one level down.

One caution applies. A fragment with more than one top-level element is rejected with the 'Invalid XML entered.' alert, so the checkbox is never applied. You should check the output to confirm whether the option had the effect you expected.

Correcting the Old Description of This Tool

The previous version of this page made several claims that do not match the actual tool. This section names those claims and gives the correct behaviour.

The old copy said you could "paste or upload your XML". There is no upload control on this page. The form has a textarea for input, a checkbox, a convert button, and a clear button. You cannot select a file from your disk.

The old copy said attributes are "typically preserved as prefixed keys (commonly @attributeName)". The prefix here is an underscore, so id="1" becomes _id. Text next to attributes lives under __text.

The old copy said "the conversion happens entirely in the browser or on the server". The conversion happens only in the browser. The x2js library runs client-side, and no data is sent to this server. There is no server-side conversion path.

The old FAQ said single elements may become arrays "depending on settings". There are no settings that control array formation. A single element is always an object here. Only repeated siblings become arrays.

The old copy hinted at numbers being detected. Numbers are never detected. Every value is a string, including the numeric-looking text from the live test.

These corrections matter because the old description could lead you to expect features that do not exist. You might have prepared a file for upload, only to find no upload button. You might have expected @ prefixed attributes and written code that looks for the wrong key names. You might have assumed your data was sent to a server and worried about privacy, when in fact the conversion is fully local.

The corrected description matches what the code actually does. The tool is a browser-only converter with a fixed set of rules, one checkbox, and no file handling. Knowing that from the start saves you from testing features that are not there.

Limitations

This tool has limits that come directly from its code. There is no file upload, no download button, and no copy button. You cannot save the JSON to disk from the page itself. There is no pretty or compact toggle, so the three-space indentation is the only format available.

There is no way to change the attribute prefix. The underscore is fixed. There is no type detection, so numbers and booleans stay as strings. There is no reverse direction, so you cannot convert JSON back to XML on this page. Comments and processing instructions are dropped from the output. CDATA becomes plain text. Mixed content with text between child elements is not preserved faithfully. Namespace prefixes are stripped from element names, which can cause key collisions when two namespaces use the same local name.

There is no explicit size limit, but the browser's memory is the real constraint. Very large XML documents, such as multi-megabyte sitemaps, can freeze the tab because the whole tree is parsed in memory at once. The live test for this rewrite used small documents only, so the behaviour at scale is a code-derived expectation rather than a measured result.

The error handling is minimal. Input that is not well-formed XML triggers a browser alert reading "Invalid XML entered." and the output box stays unchanged. Whitespace-only input does nothing at all. There is no error message that explains which part of the XML is malformed.

The rate limit applies only to page loads. The conversion itself makes no request to this site. A site-wide throttle blocks an address for the rest of the day after roughly fifteen requests within a single second, but that throttle has no connection to the conversion button.

Let's consider the practical consequences of these limits. If you work with a 50 megabyte XML export, this tool is not the right choice. The browser will attempt to parse the entire document into a DOM tree, and that operation can exhaust memory or freeze the tab for a long time. You would be better served by a command-line tool or a script that processes the file in chunks.

If you need to convert JSON back to XML, this page cannot help. The mapping rules are directional, and there is no inverse implementation here. You would need a separate library or service that handles the reverse direction.

If your XML contains comments that carry meaning, such as annotations or section markers, those comments disappear from the JSON. The same applies to processing instructions. Only elements, attributes, and text content survive the conversion.

What This Tool Cannot Do for You

You cannot convert JSON to XML here. The tool is single-direction. If you need the reverse mapping, you will need a separate converter that handles the JSON to XML direction. You cannot upload a file from your computer. The input must be pasted as text. For a large sitemap file, you would need to open the file in an editor, copy the contents, and paste them into the textarea.

You cannot download the output as a file. There is no download link and no copy button. You select the JSON text in the right textarea and copy it with your browser's copy command.

You cannot control the attribute prefix, the indentation width, or the array formation rule. The tool has exactly one checkbox, for root removal. Everything else is fixed by the x2js library configuration.

You cannot rely on number detection. The output for the numeric-looking input is a quoted string. If your downstream code expects a number, you must convert it yourself.

You cannot preserve comments, processing instructions, or the exact interleaving of mixed content. The converter drops or flattens those constructs. For documents that depend on those features, this tool will not give a faithful JSON representation.

The list of things this tool cannot do is as important as the list of things it can do. Knowing the boundaries helps you decide whether to use it for a given task. It converts a small, well-structured XML document in seconds. For a large file, a bidirectional conversion need, or a document with mixed content, you should look elsewhere.

Practical Use Cases

The converter handles XML with a regular, element-based structure. Configuration files, data exports, and API responses that use elements for values and attributes for metadata convert cleanly. The underscore-prefixed attributes and __text keys are easy to recognise in the output.

XML sitemaps are a common input. A sitemap has a root element, repeated <url> elements, and child elements like <loc>, <lastmod>, and <priority>. The repeated <url> elements become an array, which maps naturally to a list of URLs in JSON.

The root removal option helps with sitemaps. A sitemap has a single root element, <urlset>. Checking the box drops that wrapper and leaves you with the url array at the top level. That shape suits a JavaScript application that iterates over URLs.

The converter also works for RSS feeds, Atom feeds, and other syndication formats. Those documents have repeated <item> or <entry> elements that become arrays. The text inside each item becomes readable string values.

For JSON generation from XML that you control, the fixed rules are an advantage. You can predict the output shape before you convert. You know that a repeated element becomes an array, a single element becomes an object, and every value is a string.

Consider a configuration file for a build system. It has a root element, several sections, and key-value pairs expressed as elements with text. Converting it to JSON gives you a nested object that mirrors the configuration hierarchy. You can then load that JSON into a script that validates the configuration or generates documentation.

Consider an export from a content management system. The XML contains articles, each with a title, a body, and metadata attributes. The converter produces an array of article objects, with the metadata as underscore-prefixed keys and the body as a text value. That structure is easy to import into a database or a search index.

The common thread across these use cases is regular structure. Elements contain either text or child elements, attributes carry metadata, and repetition follows clear patterns. When your XML matches that shape, the converter gives you clean, predictable JSON.

What the Output Looks Like in Practice

The JSON output uses three-space indentation. That is a fixed choice of this tool and cannot be changed. Each level of nesting adds three spaces. The output is valid JSON. Keys are quoted, strings are quoted, arrays use square brackets, and objects use curly braces. You can paste the output into any JSON parser or validator and it will accept it.

The output preserves the order of keys as they appear in the XML. Attributes come before text content in the key order, and child elements follow in document order. That ordering is deterministic for the same input.

The output drops the __prefix key that the x2js library uses internally. You will not see that key in the final JSON. The namespace declarations appear as _xmlns keys, and the prefix itself is removed from element names.

Let's look at how the output behaves when you feed it into a JavaScript program. You can use JSON.parse() on the text from the right textarea and get a plain object. The underscore-prefixed keys are accessible with dot notation, like parsed.root._id. The __text key is accessible the same way, parsed.root.__text. There is nothing unusual about the structure from the parser's perspective.

In Python, you would use the json module to load the output. The result is a dictionary with string keys and string values. The __text key appears as a normal dictionary key. You can iterate over the structure with standard Python loops.

The three-space indentation is a minor aesthetic choice. Most JSON tools accept any consistent indentation, and many formatters would normalise it to two or four spaces if you run the output through them. The important part is that the output is syntactically valid JSON, which it is.

Related Tools

When your source data is in CSV rather than XML, use the CSV to JSON Converter to turn rows and columns into JSON arrays of objects.

When you need to create a sitemap from scratch, the XML Sitemap Generator builds the XML structure for you.

When your sitemap is too large for one file, the XML Sitemap Chunker splits it into smaller, valid pieces.

Frequently Asked Questions

Does the conversion send my XML to a server?

No. The conversion runs entirely in your browser using the x2js library. The tool makes no network request for the conversion itself, and no copy of your XML is transmitted to this site. A site-wide throttle applies only to page loads, roughly fifteen requests within a single second from one address.

Why do attributes have an underscore prefix instead of an @ symbol?

The x2js library uses an underscore prefix for attributes. The XML id="1" becomes _id in the JSON output. Some other converters use an @ prefix, but this tool does not offer that option. The prefix is fixed and cannot be changed.

When will I get an array instead of an object?

Repeated sibling elements become a JSON array. A single element becomes an object. The input with two <item> children produces an array of two objects, while the input with one <item> child produces a single object. There is no setting that changes this behaviour.

Why is my number returned as a string?

The converter performs no type detection. Every value from an XML text node is assigned to a JSON string. That includes integers, decimals, booleans, and dates. You need to convert the values to numbers yourself in your own code.

What happens when my XML is not well-formed?

The tool shows a browser alert reading "Invalid XML entered." and the output box stays unchanged. Whitespace-only input does nothing at all. There is no detailed error message that points to the location of the malformed markup.

Can I convert JSON back to XML with this tool?

No. The tool only converts XML to JSON. There is no reverse direction available on this page. For the reverse mapping, you will need a separate JSON to XML converter that handles that direction.


Free Software