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,
#textvs 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 (`&` → `&`, `<` → `<`, 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 ShiangYu Huang