Mapping rules in use
About this tool
JSON and XML do not describe data the same way. XML has attributes, text content, repeated elements, comments and namespaces. JSON has objects, arrays, strings, numbers, booleans and null. Because there is no official standard for converting between them, every converter has to choose a set of rules, and most tools do not say which rules they chose. This converter uses one documented convention in both directions and lists the rules under the tool, so you can predict the output before you paste anything. Everything runs in your browser; nothing is uploaded.
How to use the converter
- Paste JSON into the input box. A small product catalog is loaded as a sample.
- Set the options: the root element name, the element name used for items of a top-level array, the attribute prefix (
@by default), the indent and whether strings go into CDATA sections. - Click Convert. The status line counts elements and attributes, and any renamed keys or dropped values are listed underneath.
- Click Swap direction to convert XML to JSON instead. If there is output, it moves into the input box, so you can check a round trip in two clicks.
- Copy or download the result as
converted.xmlorconverted.json.
JSON to XML mapping rules
- Root element. XML needs exactly one root element. If the JSON is an object with a single key (like
{"catalog": {...}}), that key becomes the root. Otherwise the whole value is wrapped in the root element you name,rootby default. Untick Single top-level key as root to always wrap. - Objects become elements, and each key becomes a child element in the original order.
- Attributes. A key that starts with the prefix (
"@id": "p100") becomes an attribute (id="p100"), as long as its value is a string, number, boolean ornull. - Text content. A
"#text"key sets the text of an element that also has attributes, so{"@currency": "USD", "#text": 89.99}becomes<price currency="USD">89.99</price>. - Arrays become repeated elements with the key's name:
"tag": ["a", "b"]gives two<tag>elements. A top-level array, or an array nested directly inside another array, uses the array item name (item). An empty array produces nothing, and the tool warns you. nulland empty strings become an empty element such as<discontinued/>.- Numbers and booleans are written as text exactly as JavaScript prints them, so
12.50in the JSON becomes12.5. XML has no data types of its own; the type is lost. - Invalid names are fixed. JSON keys can be any string, but XML names cannot start with a digit, hyphen or period and cannot contain spaces or most punctuation. Each invalid character becomes
_, a_is added in front when the first character cannot start a name, and the tool lists every rename. One colon is allowed, for namespace prefixes such asinv:stock. - Characters XML 1.0 cannot hold, such as most control characters below U+0020, are removed with a warning, because even an escaped form is not allowed.
Escaping and CDATA
The W3C XML 1.0 specification says a literal & or < must never appear in text, and that > must be escaped in the sequence ]]>. This tool escapes all three in text, and in attribute values (which it writes in double quotes) it escapes both quote characters too:
| Character | In text | In attribute values |
|---|---|---|
& | & | & |
< | < | < |
> | > | > |
" | left as is | " |
' | left as is | ' |
Choose a CDATA option to write strings as <![CDATA[...]]> instead, either for every string or only for strings that contain &, < or >. A CDATA section cannot contain ]]>, so the tool splits the section at that point. Numbers, booleans and attribute values are never put in CDATA.
XML to JSON mapping rules
- The result is an object with one key, the root element's name.
- Attributes become prefixed keys (
"@id"), listed before child elements. - An element with only text becomes a string. An empty element with no attributes becomes
null. - Text next to attributes or child elements goes in
"#text". - Repeated sibling elements become an array. A single child stays a plain value, which means the shape of your JSON can change when a list has one item. Tick Always use arrays for child elements to make every child an array.
- Comments and processing instructions are dropped. Namespace prefixes stay in the key names, and
xmlnsdeclarations become ordinary attribute keys. - Type conversion is off by default, so every value is a string. Tick Convert numbers and true/false to turn
"42"into42and"true"intotrue.
Watch out for leading zeros. ZIP codes, SKUs and phone numbers such as 00731 look numeric, but turning them into numbers would lose the zeros. Even with conversion on, this tool only converts text that is a valid JSON number (as defined in RFC 8259, which rules out leading zeros), so 00731 stays a string. Conversion can still change formatting: 12.50 becomes 12.5. Integers larger than 9,007,199,254,740,991 (the largest integer a JavaScript number holds exactly) are left as strings.
Worked example
The sample JSON has a single top-level key, catalog, so it becomes the root. The product array becomes two product elements, @id becomes an attribute, the & and < in the strings are escaped, null becomes a self-closing element, and the key 2for1 is renamed _2for1 because an XML name cannot start with a digit. Convert gives:
<?xml version="1.0" encoding="UTF-8"?>
<catalog updated="2026-10-01">
<product id="p100">
<name>Trail Running Shoes</name>
<price currency="USD">89.99</price>
<tags>
<tag>outdoor</tag>
<tag>footwear</tag>
</tags>
<inStock>true</inStock>
</product>
<product id="p101">
<name>Tom & Jerry Socks</name>
<price currency="USD">12.5</price>
<sku>00731</sku>
<note>Ships in <2 days</note>
<_2for1>false</_2for1>
<discontinued/>
</product>
</catalog>
Swap the direction and convert back, and the first product comes out as:
{
"catalog": {
"@updated": "2026-10-01",
"product": [
{
"@id": "p100",
"name": "Trail Running Shoes",
"price": {
"@currency": "USD",
"#text": "89.99"
},
"tags": {
"tag": [
"outdoor",
"footwear"
]
},
"inStock": "true"
},
The structure survives, but the types do not: 89.99 and true are now strings, because XML text has no type. Tick Convert numbers and true/false to get them back as a number and a boolean, while 00731 stays a string. The key _2for1 keeps its new name.
Common mistakes
- Expecting a perfect round trip. Types, empty arrays, the difference between
nulland"", comments and key renames cannot all survive a trip through XML and back. - Code that assumes an array. Without Always use arrays, a list with one child becomes a single object. Code that loops over it then breaks on the day only one record comes back.
- Pasting several JSON documents at once. Newline-delimited JSON (one object per line) is not one JSON value. Wrap the lines in
[ ]with commas between them first. - HTML entities in XML.
is not defined in XML and the parser will reject it. Use .
Use cases
- Sending JSON data to a SOAP service, an RSS or sitemap generator, or an older system that only accepts XML
- Reading an XML API response or config file as JSON in JavaScript
- Checking how a library's XML mapping will treat attributes and repeated elements before writing code
Related tools: tidy the input first with the JSON Formatter or the XML Formatter, convert config files with the YAML to JSON Converter, or flatten records into a spreadsheet with JSON to CSV.
Related reading
For a longer explanation, read our guide: JSON vs XML: differences and when to use each.
Frequently asked questions
No single standard exists, so each library picks its own convention for attributes and text. This tool uses an @ prefix for attributes and a #text key for text, the same defaults as the Python xmltodict library, and lets you change the attribute prefix to match whatever convention your other code expects.
XML stores everything as text, so the converter cannot know whether 42 was meant as a number or as a code. Strings are the safe default. Tick the option to convert numbers and true or false, and values with leading zeros such as ZIP codes will still stay strings.
Paste the array as it is. A top-level array is wrapped in the root element and each entry becomes an element named by the array item name option, item by default. An array stored under a key, such as "product": [...], becomes repeated product elements instead.
No. Both directions run in JavaScript in your browser tab, using the built-in JSON parser and XML parser. Nothing is sent to a server, so you can convert internal API responses or configuration files, and the tool keeps working offline once the page has loaded.
Yes. Element and attribute names keep their prefixes, so inv:stock becomes the key "inv:stock", and namespace declarations such as xmlns:inv become ordinary attribute keys. Converting that JSON back to XML writes the same prefixes and declarations, so the namespaces survive a round trip.
They are dropped, along with processing instructions such as xml-stylesheet, because JSON has no place for them. A note under the status line tells you how many were skipped. If you need to keep comments, store them in an element or attribute before converting.