JSON to XML
Convert JSON to XML
JSON to XML Converter: Structural Transformation, Attributes & W3C Standards
1. Quick Overview & Key Benefits
The JSON to XML Converter is an industrial-grade, client-side data transformation engine designed to bridge the structural divide between lightweight JSON (JavaScript Object Notation, RFC 8259) and hierarchical XML (Extensible Markup Language, W3C XML 1.0 Fifth Edition).
While modern web APIs predominantly exchange payloads formatted as JSON, enterprise backends, financial clearing networks (SWIFT, ISO 20022), healthcare standards (HL7, FHIR), and legacy enterprise service buses (SOAP, WSDL) mandate strictly formatted, schema-validated XML documents. Transforming JSON to XML is non-trivial because XML supports metadata concepts absent in JSON: attributes on elements, mixed content text nodes, CDATA blocks, namespace prefixes, and an obligatory single root wrapper.
Key Value Propositions & Technical Advantages
- Comprehensive W3C XML 1.0 Compatibility: Emits well-formed XML documents with optional XML declarations (
<?xml version="1.0" encoding="UTF-8"?>), custom root elements, and deterministic node nesting. - Attribute Prefix Mapping: Seamlessly translates specified JSON object keys (e.g.,
@id,@version, or_attr) into native XML element attributes while mapping sibling keys to child tags. - Text Content & CDATA Directives: Explicitly handles mixed text nodes using
#textconventions and automatically encapsulates unescaped HTML, scripts, or binary blocks inside<![CDATA[ ... ]]>containers. - 100% Client-Side Browser Engine: Powered by in-browser DOM serialization and AST recursion. Payloads execute exclusively within the browser sandboxed V8/SpiderMonkey engine.
- Zero Server Latency & Absolute Confidentiality: Your customer records, financial transactions, and XML schemas never leave your browser. Zero telemetry, zero analytics tracking, and zero remote network requests.
2. Step-by-Step Practical Usage Guide
Converting complex JSON payloads into production-grade XML requires configuring root wrappers, attribute prefixes, and CDATA boundaries.
Step 1: Supply Your Valid JSON Document
Paste your raw JSON into the input editor. The parser checks for structural integrity and constructs an in-memory object graph.
Example Input: Enterprise Payment Order Manifest (payment.json)
{
"order": {
"@id": "ord-2026-9941",
"@currency": "USD",
"timestamp": "2026-09-11T20:15:30Z",
"customer": {
"@type": "corporate",
"name": "Acme Industrial Corp",
"tax_identifier": "US-88291049"
},
"items": [
{
"@sku": "SKU-CLOUD-01",
"description": "High-Throughput Dedicated Node",
"quantity": 3,
"unit_price": 249.99
},
{
"@sku": "SKU-SUPP-04",
"description": "24/7 Enterprise Support SLA",
"quantity": 1,
"unit_price": 999.00
}
],
"memo": "<![CDATA[Customer requested express delivery & priority routing.]]>"
}
}
Step 2: Configure Transformation Flags
Fine-tune how JSON structures map to XML tags:
- Root Element Wrapper: If your root JSON object has multiple top-level keys or is an array, specify an enclosing root tag name (e.g.,
<root>or<request>). - Attribute Marker: Select your attribute indicator string (default:
@, alternatively_or$). Keys bearing this prefix become XML attributes rather than nested elements. - Text Node Property: Define the key used for raw element inner text (default:
#textor_value). - Indentation and Pretty Printing: Select indent width (2 spaces, 4 spaces, or compact single-line minification).
Step 3: View, Copy, and Validate XML Output
The tool produces clean, indented, well-formed XML ready for ingestion into SOAP services or enterprise validators.
Example Output: Well-Formed XML Document (payment.xml)
<?xml version="1.0" encoding="UTF-8"?>
<order id="ord-2026-9941" currency="USD">
<timestamp>2026-09-11T20:15:30Z</timestamp>
<customer type="corporate">
<name>Acme Industrial Corp</name>
<tax_identifier>US-88291049</tax_identifier>
</customer>
<items>
<item sku="SKU-CLOUD-01">
<description>High-Throughput Dedicated Node</description>
<quantity>3</quantity>
<unit_price>249.99</unit_price>
</item>
<item sku="SKU-SUPP-04">
<description>24/7 Enterprise Support SLA</description>
<quantity>1</quantity>
<unit_price>999.00</unit_price>
</item>
</items>
<memo><![CDATA[Customer requested express delivery & priority routing.]]></memo>
</order>
3. Technical Under the Hood: Specifications & Architecture
Structural Impedance Mismatch: JSON vs. W3C XML 1.0
Mapping JSON to XML involves reconciling two distinct data modeling paradigms:
| Architectural Property | JSON (RFC 8259) | XML 1.0 (W3C Fifth Edition) |
|---|---|---|
| Root Boundary | Objects or arrays can exist without wrapping | Single enclosing document element is mandatory |
| Attributes vs. Children | Flat key-value pairs; no concept of attributes | Elements can hold attributes as well as nested child tags |
| Mixed Content | Not supported; strings cannot coexist inside an object without a key | Elements can interleave raw character text between child tags |
| Special Character Escaping | Only quotes " and backslashes \ require escaping |
5 predefined XML entities (&, <, >, ", ') |
| Tag Naming Rules | Any UTF-8 string is a valid key | Strict NCName rules (must start with letter/underscore; cannot contain spaces) |
Entity Encoding and Tag Sanitization Algorithm
To prevent malformed XML and XML Injection vulnerabilities (similar to CWE-91), all string literals and keys must be processed through an entity encoding sanitizer: $\text{sanitize}(s) = s \xrightarrow{& \to &} \xrightarrow{< \to <} \xrightarrow{> \to >} \xrightarrow{" \to "} \xrightarrow{’ \to '}$
Furthermore, JSON keys containing characters prohibited by the W3C XML Recommendation (e.g., spaces, punctuation, or leading numerals) are sanitized into valid NCNames:
function sanitizeTagName(key: string): string {
// Replace invalid leading character
let validName = key.replace(/^[^a-zA-Z_]/, "_amp;");
// Replace any subsequent invalid characters with underscores
return validName.replace(/[^a-zA-Z0-9.\-_]/g, "_");
}
Reference TypeScript AST Transformation Engine
The following production-grade module implements the recursive transformation algorithm, handling attributes, CDATA blocks, and repeated array items:
/**
* W3C-Compliant JSON to XML Transformation Engine
*/
export interface XmlOptions {
attributePrefix?: string; // Default: '@'
textKey?: string; // Default: '#text'
cdataKey?: string; // Default: '#cdata'
rootTag?: string; // Root wrapper if JSON root has multiple keys
indent?: string; // Indentation string (e.g., ' ')
declaration?: boolean; // Include <?xml ... ?>
}
export function jsonToXml(
data: unknown,
options: XmlOptions = {}
): string {
const attrPrefix = options.attributePrefix ?? "@";
const textKey = options.textKey ?? "#text";
const cdataKey = options.cdataKey ?? "#cdata";
const indentStr = options.indent ?? " ";
const emitDeclaration = options.declaration ?? true;
function escapeXml(unsafe: string): string {
return unsafe.replace(/[<>&'"]/g, (c) => {
switch (c) {
case "<": return "<";
case ">": return ">";
case "&": return "&";
case "'": return "'";
case '"': return """;
default: return c;
}
});
}
function serializeNode(tagName: string, value: unknown, depth: number): string {
const pad = indentStr.repeat(depth);
if (value === null || value === undefined) {
return `${pad}<${tagName}/>`;
}
if (typeof value !== "object") {
const strVal = String(value);
if (strVal.startsWith("<![CDATA[") && strVal.endsWith("]]>")) {
return `${pad}<${tagName}>${strVal}</${tagName}>`;
}
return `${pad}<${tagName}>${escapeXml(strVal)}</${tagName}>`;
}
if (Array.isArray(value)) {
return value.map((item) => serializeNode(tagName, item, depth)).join("\n");
}
// Process Object
const obj = value as Record<string, unknown>;
const attributes: string[] = [];
const children: string[] = [];
let innerText: string | null = null;
let innerCdata: string | null = null;
for (const [key, val] of Object.entries(obj)) {
if (key.startsWith(attrPrefix)) {
const attrName = key.slice(attrPrefix.length);
attributes.push(`${attrName}="${escapeXml(String(val))}"`);
} else if (key === textKey) {
innerText = escapeXml(String(val));
} else if (key === cdataKey) {
innerCdata = `<![CDATA[${String(val)}]]>`;
} else if (Array.isArray(val)) {
// Repeated array child elements
for (const element of val) {
children.push(serializeNode(key, element, depth + 1));
}
} else {
children.push(serializeNode(key, val, depth + 1));
}
}
const attrString = attributes.length > 0 ? " " + attributes.join(" ") : "";
if (children.length === 0 && innerText === null && innerCdata === null) {
return `${pad}<${tagName}${attrString}/>`;
}
if (children.length === 0 && (innerText !== null || innerCdata !== null)) {
const textContent = innerCdata ?? innerText;
return `${pad}<${tagName}${attrString}>${textContent}</${tagName}>`;
}
const childContent = children.join("\n");
return `${pad}<${tagName}${attrString}>\n${childContent}\n${pad}</${tagName}>`;
}
let xmlBody = "";
if (typeof data === "object" && data !== null && !Array.isArray(data)) {
const keys = Object.keys(data);
if (keys.length === 1 && !keys[0].startsWith(attrPrefix)) {
const singleRoot = keys[0];
xmlBody = serializeNode(singleRoot, (data as Record<string, unknown>)[singleRoot], 0);
} else {
const wrapper = options.rootTag ?? "root";
xmlBody = serializeNode(wrapper, data, 0);
}
} else {
const wrapper = options.rootTag ?? "root";
xmlBody = serializeNode(wrapper, data, 0);
}
const decl = emitDeclaration ? '<?xml version="1.0" encoding="UTF-8"?>\n' : "";
return decl + xmlBody;
}
4. Real-World Production Use Cases
Scenario A: Banking & Financial Messaging (ISO 20022 & SWIFT MT/MX)
Modern fintech frontends and payment gateways collect checkout information in JSON via mobile SDKs. However, domestic ACH and international SWIFT networks mandate strict ISO 20022 XML messages (such as pain.001.001.09 for credit transfers and pacs.008 for clearing). Payment engineers leverage JSON to XML transformation pipelines to map JSON payment structures into standardized, namespace-compliant XML transaction envelopes.
Scenario B: Legacy SOAP / WSDL Service Integration
Enterprise systems running SAP, Oracle ERP, or mainframe core banking services often expose SOAP (Simple Object Access Protocol) web service endpoints that require XML payloads enveloped in <soapenv:Envelope>. When building modern cloud microservices that need to invoke these legacy APIs, developers convert JSON request bodies into strictly tagged SOAP XML envelopes with accurate namespace attributes (xmlns:soapenv="...").
Scenario C: Electronic Data Interchange (EDI) & Healthcare HL7 / FHIR
Electronic health record systems frequently integrate with medical diagnostic hardware and government reporting registries via HL7 v3 XML documents. Clinical engineering pipelines convert JSON observation payloads generated by diagnostic devices into schema-validated XML schemas containing specialized attributes (@code, @codeSystem, @displayName) and medical narrative CDATA blocks.
5. Frequently Asked Questions (FAQs)
Q1: How does the converter decide between an XML attribute and an XML child element?
By default, the converter uses the industry-standard @ prefix convention (popularized by XML-to-JSON mappers like BadgerFish and xml2js). Any JSON property whose key begins with @ (e.g., "@id": "100") is serialized as an attribute within the parent tag (<tag id="100">). All other properties are serialized as child XML elements.
Q2: What happens if my JSON input contains invalid characters in keys (like spaces)?
XML 1.0 rules forbid spaces, commas, slashes, and initial numbers in element names (NCNames). The converter automatically sanitizes problematic keys by replacing invalid characters with underscores (_) or prefixing leading digits with an underscore. This prevents fatal XML parser errors (XML Parsing Error: not well-formed).
Q3: How do I handle mixed text content (text inside an element that also has child tags)?
To represent mixed content, assign the text to the #text key inside the JSON object:
{
"notice": {
"@priority": "high",
"#text": "System maintenance scheduled.",
"link": "https://status.internal"
}
}
This converts to:
<notice priority="high">
System maintenance scheduled.
<link>https://status.internal</link>
</notice>
Q4: Can I embed raw HTML or unescaped characters using CDATA?
Yes. When a string property is wrapped in <![CDATA[ ... ]]> or assigned to a #cdata property, the converter suppresses normal XML entity escaping (&, <) and retains the literal character content inside the CDATA block. This allows embedding arbitrary HTML snippets, markdown, or scripts without XML syntax errors.
6. Technical Accuracy & Client-Side Privacy Notice
Standards & Compliance
- W3C XML Recommendation: Adheres strictly to Extensible Markup Language (XML) 1.0 (Fifth Edition).
- JSON Specification: Validated against RFC 8259.
- Character Encoding: Standardized on UTF-8 character encoding with mandatory entity escaping for
<,>,&,", and'.
Zero-Telemetry Client-Side Security Guarantee
This converter performs all computational transformations directly inside the user’s browser sandbox. No strings, JSON payloads, attributes, or generated XML schemas are ever transmitted across external networks, captured in remote web logs, or stored on servers. Developers processing confidential HIPAA healthcare payloads, PCI-DSS cardholder data, or corporate financial ledgers can operate with total assurance of confidentiality.