Reading XML as a tree
XML has three things JSON does not: attributes, text mixed in with children, and repeated element names. Any tool that shows XML as a JSON-shaped tree has to decide what to do with them. Here is what jsontree.app decided, and what it costs.
Attributes get an @ in front
<book id="1" lang="en">
<title>Dune</title>
</book>
book
@id "1"
@lang "en"
title "Dune"
The prefix keeps attributes and child elements in one flat list without them colliding, and
it is obvious at a glance which is which. An element name can never start with
@ in XML, so nothing legitimate is ever mistaken for an attribute.
An element with only text becomes the text
If there are no attributes and no element children, there is nothing to keep, so the element collapses to its text:
<title>Dune</title> becomes title "Dune"
Without this rule every leaf in the document would be a one key object wrapping a
#text, which is technically faithful and horrible to read. When there is
something else to keep, the text lands under #text alongside it.
Repeated names become an array
<catalog>
<book>Dune</book>
<book>Neuromancer</book>
</catalog>
catalog
book [ "Dune", "Neuromancer" ]
This is the rule with the sharpest edge, and it is worth knowing about. The shape depends on
the data, not on the schema. One <book> gives you a string, two give you
an array. If you are writing code against the result rather than just reading it, that
difference will find you eventually. Every XML to JSON converter has this problem and none
of them solve it without a schema.
What gets thrown away
Being honest about this matters more than the mapping itself.
-
The order of mixed content. Text interleaved with child elements loses
its position.
<p>a<b/>c</p>keeps the text and keepsb, but not the fact that the text sat on both sides of it. For documents this is fatal. For configuration and data, which is what people usually paste into a viewer, it never comes up. -
Namespace prefixes are kept as written.
ns:tagstaysns:tag. No prefix is resolved to a URI, so two documents using different prefixes for the same namespace will not look alike. - Comments and processing instructions are dropped. They are not data and they would double the size of the tree.
-
Whitespace between elements goes. Indentation is not content. Text inside
CDATAkeeps its whitespace exactly, because there the whitespace is the point.
Entities
The five predefined entities are decoded, along with numeric ones in both forms, so
&, A and A all come out as
the characters they mean. A DOCTYPE with an internal subset is skipped rather
than interpreted, which means custom entity definitions are not expanded. This is
deliberate. Expanding entities from a document you were just handed is how billion laughs
works.
A note on doing this in a browser
Web Workers have no DOMParser. If you want to parse XML off the main thread,
and for a large file you do, you have to bring your own scanner. That is also the only way
to get progress out of it: DOMParser is a single call that tells you nothing
until it is finished, so a hand written scanner is what lets a progress bar move by bytes
instead of pretending.
Try it
jsontree.app reads XML with its own scanner in a worker, so the page stays alive and the progress bar is real. Errors come back with a line number and the source around them.
Open a file