JSON and XML both move structured data between systems, but they started in different places. XML grew out of document markup (SGML) in the late 1990s, to describe marked-up text. JSON came out of JavaScript a few years later, to serialize plain data objects. That difference in origin explains most of the practical differences.
This guide compares JSON vs XML on data model, size, validation, and where each one still fits. It uses the same record in both formats so the differences stay concrete. To move data between the two, the JSON ⇄ XML converter handles the round trip, with the caveats covered below.
The same data in both formats
The quickest way to see the difference is to look at one record. Here is a customer with an id, a name, two roles and a nested address, written as JSON:
{
"id": 4021,
"name": "Ada Lovelace",
"active": true,
"roles": ["admin", "editor"],
"address": {
"city": "London",
"postcode": "NW1 6XE"
}
}Here is the same record as XML. Every value sits between an opening and a closing tag, and the array becomes repeated elements. Nothing in the format says that 4021 is a number or that active is a boolean. Everything is text:
<?xml version="1.0" encoding="UTF-8"?>
<customer>
<id>4021</id>
<name>Ada Lovelace</name>
<active>true</active>
<roles>
<role>admin</role>
<role>editor</role>
</roles>
<address>
<city>London</city>
<postcode>NW1 6XE</postcode>
</address>
</customer>The XML version uses about twice the bytes for the same information. The array also needed a wrapper element (roles) and a repeated child (role). JSON makes that choice for you with square brackets.
Data model: types, attributes and namespaces
The biggest difference is not syntax. It is the data model behind each format.
JSON has a small, typed model
JSON defines six value types: string, number, boolean, null, object and array. A parser returns them as native values. A JSON number becomes a float or int, true becomes a real boolean, and an array becomes a list. There is nothing to interpret. See JSON Data Types Explained for details.
XML has one type, text, plus structure
In plain XML, every leaf is character data. The format only sees a string, so your application or an attached schema decides whether <id>4021</id> is a number. In return, XML has structural features that JSON lacks:
- Attributes. Metadata attached to an element, like
<price currency="USD">42.00</price>. JSON has no attributes. Everything is a key. - Namespaces. Prefixes like
xsl:orsoap:let documents from different vocabularies sit together without name collisions. - Mixed content. Text and elements interleaved, as in
<p>See <b>this</b> note</p>. XML was designed for this document use case. - Comments and processing instructions. Both are part of the XML spec. Standard JSON has no comments.
Verbosity, payload size and readability
Closing tags and wrapper elements make XML larger than the same data in JSON, often 1.5x to 2x the raw bytes. Over the network this matters less than it used to. HTTP compression (gzip or brotli) shrinks repeated tags well, so gzipped XML is much closer to gzipped JSON than the raw numbers suggest.
Verbosity still costs you in readability and CPU. Repeated open and close tags are harder to read and write by hand. Larger raw payloads also mean more bytes to parse and more memory allocations, whatever the compression. For an API that returns thousands of small objects, JSON's smaller size adds up. The JSON Minifier strips whitespace from JSON, but most of the savings come from the format choice itself.
| Aspect | JSON | XML |
|---|---|---|
| Primary purpose | Data interchange | Document markup (and data) |
| Value types | 6 native types | Text only (typed via schema) |
| Attributes | No | Yes |
| Namespaces | No | Yes |
| Comments | No (standard JSON) | Yes |
| Mixed content | No | Yes |
| Typical size | Baseline | About 1.5x to 2x larger raw |
| Schema language | JSON Schema | XSD, RELAX NG, DTD |
| Query language | JSONPath, jq | XPath, XQuery |
| Native fit | JavaScript, most langs | Document tooling, .NET, Java |
Parsing and language support
Every language can parse both formats, but the work differs. JSON parses into native data structures in one call, with no object model to walk:
const data = JSON.parse(jsonString);
console.log(data.roles[0]); // "admin"
console.log(typeof data.id); // "number"
console.log(data.active === true); // trueAn XML parser usually returns a DOM tree or fires SAX events, and you walk the result with a query language like XPath. Reading the same fields takes more code, and each value comes back as a string you must cast yourself:
import xml.etree.ElementTree as ET
root = ET.fromstring(xml_string)
first_role = root.find("roles/role").text # "admin"
customer_id = int(root.find("id").text) # cast "4021" -> 4021
is_active = root.find("active").text == "true" # cast to boolThat casting step is the cost of XML's text-only model. The parser cannot know that 4021 is a number or that active is a boolean, so your code has to. In JSON, working with the parsed result means working with normal objects and arrays.
Schema and validation: XSD vs JSON Schema
Both formats can enforce structure. XML uses XSD (XML Schema Definition), a mature standard that also carries data types. An XSD can declare that <id> is an xs:integer, which gives typed XML what JSON has built in. RELAX NG and the older DTD are alternatives.
JSON uses JSON Schema, which is itself a JSON document that describes the shape, types and constraints of your data. Here is a minimal schema for the customer record:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["id", "name", "roles"],
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
"active": { "type": "boolean" },
"roles": {
"type": "array",
"items": { "type": "string" }
},
"address": {
"type": "object",
"properties": {
"city": { "type": "string" },
"postcode": { "type": "string" }
}
}
}
}In practice, XSD is stronger for document rules such as element order, occurrence counts and built-in types. JSON Schema is lighter and reads like the data it validates. You can generate a starting schema from a sample with the JSON Schema Generator, then tighten it by hand. For more, see the JSON Schema guide.
Where each format still fits
Use XML when
- You produce documents: anything with mixed content, formatting or prose structure. XHTML, DOCX, SVG and RSS are all XML-based for this reason.
- You must speak SOAP, or integrate with enterprise, government, healthcare (HL7) or financial systems where XML is the standard.
- You need namespaces to combine vocabularies, or validation and transformation with XSD and XSLT.
- Your data is tree-shaped markup rather than records.
Use JSON when
- You are building a web or mobile API. JSON is the default for REST and the response format for GraphQL.
- You work mainly in JavaScript/TypeScript, where JSON maps straight to objects.
- You want compact, readable config or data that people edit and programs read.
- You value simplicity. Fewer features means fewer traps and less to learn.
A simple test: if you would call your payload a record or a list of records, use JSON. If you would call it a document, use XML. Most application data is records, which is why new projects mostly use JSON while XML stays in documents and established protocols.
Converting between JSON and XML, and the caveats
Conversion is common, for example when you wrap a legacy SOAP service in a JSON API or feed an XML feed into a JSON pipeline. There is no single official mapping, because the two data models do not line up one to one. Watch for three gaps:
- Attributes. XML attributes have no JSON equivalent, so converters add a prefix, often
@.<price currency="USD">becomes a key like"@currency": "USD". A round trip only works if both sides use the same convention. - Arrays. XML has no array type. It uses repeated elements. A single
<role>looks the same as a plain value, so a converter cannot always tell "array of one" from "scalar". You often need a schema or an explicit rule to force a list. - Types. XML leaves are text, so
<id>4021</id>converts to the string"4021"unless the converter is told, or guesses, that it is a number. Guessing can go wrong. A zip code like"01234"must stay a string.
If your data is tabular rather than tree-shaped, a flat format may suit it better than XML. The JSON to CSV converter handles that case, and JSON vs CSV explains when to choose it.