Skip to content

JSON to XML

Turn JSON into pretty XML with a configurable root element.

Live
Input

What this tool does

Turn JSON into pretty XML 1.0 with a configurable root element name and an optional <?xml version="1.0"?> declaration. Useful for adapters to legacy SOAP services, building RSS / Atom payloads from a JSON source, or feeding data into XSLT pipelines that haven’t been retired yet.

The mapping is element-only and deterministic: every JSON object key becomes a child element, arrays repeat the parent element name, and primitive values become escaped text content. There is no attribute-vs-element heuristic and no schema inference — what you put in is what you get out, just wrapped in tags. Runs entirely in your browser; no server, no telemetry.

How to use it

Paste JSON (or load the example), pick a root element name, and read the XML on the right. Toggle the <?xml …?> declaration on for files you plan to save to disk, off for snippets you’ll inline elsewhere. The pretty-print indent is fixed at 2 spaces.

Input: {"service":"devsmiths","version":2,"public":true}

Output (XML):

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <service>devsmiths</service>
  <version>2</version>
  <public>true</public>
</root>

Limits and edge cases

  • Direction is JSON → XML only. The reverse (XML → JSON) has multiple valid mappings — attributes vs elements, #text vs anonymous strings, namespace prefixes — and a one-size-fits-all converter does more harm than good. Out of scope for P1.
  • The mapping is element-only. There is no attribute-vs-element heuristic, no schema (DTD / XSD / RelaxNG) inference, no namespace declaration. Every JSON key becomes a child element; primitive values become text content.
  • Arrays repeat the parent element name: "tags": ["a","b"] becomes <tags>a</tags><tags>b</tags>. This is the “child-list” mapping — familiar from RSS / Atom — not the “wrapper element” mapping (<tags><tag>a</tag>…).
  • JSON keys that aren’t valid XML Names produce invalid XML output — keys with spaces, leading digits, colons (which look like XML namespaces), or characters outside the Name production. Sanitize keys in your JSON before converting; the tool does not silently rewrite them.
  • Booleans and numbers are rendered as unquoted text: <active>true</active> not <active>"true"</active>. Consumers that expect XML Schema-typed elements need to parse the text content themselves — XML has no native type system.
  • For invalid JSON input, run JSON Repair first. For why JSON has largely replaced XML on the wire (and where XML still wins — documents, mixed content, XSLT), see JSON vs YAML vs XML.

Frequently asked questions

Why doesn't the output include XML attributes for primitive values?
Because there's no general agreement on when a value should be an attribute vs an element. JSON `{"id": 1, "name": "x"}` could become `<root id="1" name="x"/>` or `<root><id>1</id><name>x</name></root>` — both valid, both have downstream consumers. The converter picks element-only because the inverse (parsing this back) is unambiguous, and because most modern XML consumers (DOM, XPath, XSLT) treat attributes and elements interchangeably.
Can I add an XML namespace like xmlns:atom='…'?
Not via the converter UI. Namespaces are application semantics, not JSON structure — the tool has no way to know which keys should live in which namespace. Workaround: convert without a namespace, then add the `xmlns` attribute on the root element manually (it's one line). For non-trivial namespace mapping, use an XSLT pass after conversion.
What encoding is the output XML? Can I change it?
UTF-8, always — the conversion outputs Unicode strings which are emitted as UTF-8 bytes by your browser when you download. The XML declaration says `encoding="UTF-8"` to match. For consumers that genuinely need UTF-16 or ISO-8859-1, do the conversion, then transcode the output file with `iconv` on the command line; embedding non-UTF-8 in the browser-side string is more error-prone than transcoding bytes.
Why is my key `2024-tax-year` producing invalid XML?
XML element names can't start with a digit, and `2024-tax-year` does. The XML spec's <a href='https://www.w3.org/TR/xml/#NT-Name'>Name production</a> restricts the first character to a letter, underscore, or colon (not recommended), and subsequent characters to a small set. Rename the JSON key (`taxYear2024` or `_2024-tax-year`) before converting. The tool does not silently rewrite keys because silent rewrites lose information.
Can the converter produce CData sections for raw strings?
No. Every text value goes through XML escaping (`&` → `&amp;`, `<` → `&lt;`, etc.), which is semantically equivalent to CData for an XML parser. CData exists for human readability of embedded markup (XHTML in XML, scripts in XSLT); the converter has no signal that any particular string is markup, so it escapes uniformly. The output round-trips through every conforming XML parser identically.
Is the output XML 1.0 or XML 1.1?
XML 1.0. XML 1.1 is rare in production (it permitted more characters in names; almost no consumer ever upgraded). The XML declaration says `version="1.0"`. If you need 1.1 specifically, edit the declaration line by hand after copying the output — the body of the document is compatible with both versions because the converter never emits the characters that 1.0 forbids but 1.1 allows.

Content reviewed by