JSON vs YAML vs XML: choosing and converting formats
Compare JSON, YAML and XML for APIs, configuration and documents. Check what may change when converting attributes, types and mixed content.
By ToolsNow · Published
JSON, YAML and XML can describe similar data, but they represent some details differently. Converting between them may change attributes, value types, comments or mixed text content.
Start with the format required by the system reading the file. When using the data format converter, check a representative example before converting a larger dataset.
Common uses for each format
JSON is a data-interchange format with a deliberately tiny grammar: objects, arrays, strings, numbers, booleans, null. No comments, no schema mechanism, no way to annotate a value. That minimalism is exactly why it won for APIs. There’s almost nothing to disagree about.
YAML is a configuration format designed to be written by humans. It’s a superset of JSON, it adds comments, and it swaps punctuation for indentation. The flexibility is both the appeal and the reason for its reputation for surprises.
XML is a document markup language that also gets used for data. It carries things the other two have no native concept of: attributes, namespaces, mixed content, processing instructions, and a mature schema ecosystem.
Where conversion loses information
Comments exist only in YAML. Convert YAML to JSON or XML and every comment vanishes; convert back and they don’t come home. For a configuration file that documents itself in comments, this is usually the most damaging loss of the lot.
Attributes exist only in XML. An element can carry an attribute and text
content at once, and JSON has no equivalent. Every converter invents a
convention for it, commonly prefixing attribute keys with @ and putting
the text under #text. That’s a convention, not a standard, so the
converter here lets you change both.
Arrays versus repeated elements is the subtlest trap. XML has no array type at all, just elements that may repeat:
<list><item>a</item></list>
becomes {"list": {"item": "a"}}
<list><item>a</item><item>b</item></list>
becomes {"list": {"item": ["a","b"]}}
The same structure gives you an object in one case and an array in the other, purely because of how many children happened to be there. Code consuming the JSON has to handle both, and the single-item case is exactly the one that slips through testing.
Namespaces can be preserved as prefixed key names or stripped, but either way the namespace semantics are gone once you’re in JSON. The prefix has become an ordinary part of a string.
Types are where YAML earns its reputation. Its type inference is eager.
Unquoted yes, no, on and off were booleans in YAML 1.1, which
produced the famous Norway problem: the country code NO parsing as
false. YAML 1.2 parsers treat them as strings, but the behaviour depends
on your parser, so quoting anything that has to stay a string is still good
practice. In XML everything is text until something decides otherwise, so a
port number might arrive as a number or a string depending on the
converter’s settings.
Whitespace is significant inside XML elements in ways JSON doesn’t model, so mixed content, where text and elements interleave in a paragraph, converts badly or not at all.
The security difference
This is where the three genuinely diverge, because one of them can hurt you.
XML external entities (XXE) are the classic attack. XML lets a document declare entities, and an entity can point at an external resource: a local file path, or a URL on an internal network. A parser that resolves external entities will fetch that resource and drop its contents into the parsed output, which is a straightforward file-disclosure vulnerability. The related billion laughs attack nests entity definitions so that expansion grows exponentially and exhausts memory.
The defence is to refuse external entities outright, which the parser used here does unconditionally: entity declarations get rejected, not resolved. There’s an automated test asserting exactly that, so a dependency update can’t quietly weaken it.
Unsafe YAML is the other one. YAML tags can tell a parser to instantiate
a language-specific type, and parsers that honour this can be made to
construct arbitrary objects. That’s why older PyYAML’s load was a remote
code execution risk and why safe_load exists. The converter here uses the
core schema, so tags resolve to ordinary strings and arrays and nothing
gets constructed or executed. Also covered by a test.
JSON has no equivalent hazard. Its grammar has no mechanism for referencing external resources or instantiating types. Parsing untrusted JSON is safe. The risks with JSON are all downstream, in what you do with the values.
Choosing between them
- APIs and data interchange: JSON. Universal support, no ambiguity, no parsing hazards.
- Configuration humans edit: YAML, for the comments, with values quoted anywhere type inference could bite.
- Documents, or anywhere schema validation and namespaces matter: XML. It’s verbose because it’s doing more.
When you convert, the safe habit is to check instead of assuming: convert, convert back, compare. Where the round trip isn’t clean, the difference is telling you something real about the two formats, not about the tool.
Sources and further reading
- RFC 8259 — the JSON data interchange format
- YAML 1.2.2 specification — including the core schema and tag resolution
- W3C XML 1.0 (Fifth Edition) — entities, DTDs and namespaces
- OWASP XML External Entity Prevention Cheat Sheet
- fast-xml-parser documentation — parser and validator options
Last reviewed 31 July 2026.
Published by ToolsNow. Read how tools and sources are checked.
Found a mistake or an outdated detail? Send a correction with the article title and the detail to review.