I am designing an API for my webapp.
I was thinking to support only JSON responses (not XML) because more streamlined.
But I have just bumped to this XML:
JSON is more uniform than XML and doesn't distinguish between plain-text attributes and hierarchical contents. The natural representation for your example would be
[
{"id": 123, "private": 0, "archived": 0, "order": 1, "name": "Shopping"}
]
This is still more compact than the respective XML.
It seems to me that the most exact correspondence between XML and JSON would need to represent an XML node as a triplet (i.e. array): [name, attributes, value], with name being a string, attributes an object with attribute names as keys and attribute values as (string) values, and value a string (for atomic values) or an array of such triplets.
By such mapping the JSON-equivalent of
<folders>
<folder id="123" private="0" archived="0" order="1">Shopping</folder>
</folders>
would be
[ "folders",
{},
[
[ "folder",
{ "id": "123",
"private": "0",
"archived": "0",
"order": "1"
},
"Shopping"
]
]
]
Actually the idea behind this mapping is that:
1) XML-JSON transformation be reversible. 2) The "sibling" relationship of sub-nodes be preserved
At the same time the distinction between attribute nodes and value nodes is explicit here.
Does it make sense? And does it justify the complexity overhead?
edit
A similar method is advocated on http://www.jsonml.org/. They coined the term json markup language.
You can pick any mapping you like, but if you map
<el attr="value">
txt
</el>
to
{"el":{"attr":"value","content":"txt"}}
then how would you map:
<el attr="value" content="txt1">txt2</el>
I'd make use of the fact that some attibute names are forbidden.
{"el":{"attr":"value", "content":"txt1", "":["txt"]}
Or a more compex example:
<widget>
<debug>on</debug>
<window title="Sample Konfabulator Widget">
I just put some text here
<name>main_window</name>
<width>500</width>
<height>500</height>
</window>
<image src="Images/Sun.png" name="sun1">
<hOffset>250<unit>mm</unit></hOffset>
<vOffset>250</vOffset>
<alignment>center</alignment>
</image>
</widget>
could map to:
{"widget":{"":[
{"debug":{"":["on"]}},
{"window":{"title":"Sample Konfabulator Widget", "": [
"I just put some text here",
{"name":{"":["main window"]}},
{"width":{"":["500"]}},
{"height":{"":["500"]}}
]},
{"image":{"src":"Images/Sun.png", "name":"sun1", "":[
{"hOffset":{"":["250",{"unit":{"":["mm"]}}]}},
{"vOffset":{"":["250"]}},
{"alignment":{"":["center"]}}
}
]}
The rules for this conversion are unambiguous:
To safe space, there is a way to unambigously simplify mentioned mapping:
{"widget":{"":[
{"debug":"on"},
{"window":{"title":"Sample Konfabulator Widget", "": [
"I just put some text here",
{"name":"main window"},
{"width":"500"},
{"height":"500"}
]},
{"image":{"src":"Images/Sun.png", "name":"sun1", "":[
{"hOffset":["250",{"unit":"mm"}]},
{"vOffset":"250"},
{"alignment":"center"}
}
]}
If an element doesn't have any attibutes, the value object (containing the special empty string mapping to an array) is replaced by the array directly. So instead of:
{"hOffset":{"":["250",{"unit":{"":["mm"]}}]}}
you get
{"hOffset":["250",{"unit":["mm"]}]}
If the element content is just text, the array containing the string value is replaced by the string value directly, so you get:
{"hOffset":["250",{"unit":"mm"}]}
This way, there will always be exactly one way to map the jml (json markup language) back to xml (or html)
Opening caveat: In this answer I am deliberately standing back from the original question, and expanding the scope somewhat. Sometimes to ask the question behind the question we need to look at the big picture first.
Just as all animals are equal, all translations from JSON to XML, and from XML to JSON are unequal. There can be no mathematically correct answers to this question, and even if there are, they may be wrong. All answers will be a matter of opinion, and depend on the exact use-case(s).
JSON and XML both support and omit concepts that make perfect, reversible and native translations difficult.
To name just some:
XML requires a root element. JSON does not.
XML distinguishes between Elements and Attributes. Attributes are leaves, Elements maybe leaves or branches. JSON objects are close to Elements, but have no direct equivalent to Attributes.
JSON has arrays; the nearest XML equivalent is a parent Element, but some translations fall foul where there is only one child element.
XML has namespaces….. The less said about those the better…
JSON is intended to be compact and lightweight, and is closer (in my humble opinion) to YAML than XML.
Where a concept exists in the source language, but not in the target language, we need to be inventive and creative in our translation. Your use-cases are key.
e.g.
Should the result be as native as possible in the target language? Would we model it like this in JSON? Would we model it like this in XML?
Should the result be reversible to the original source, even at the expense of “native feel”?
Is compactness a criteria? This can be a case for JSON over an element-heavy XML, but not for JSON translated from XML and designed to be translated back.
To make a comparison with human languages: In Swiss German we love our diminutives: Nouns are routinely reduced to the small form where this would be strange in English; but even more bizarrly, we have diminutives of verbs!
So: “wir machen es köchele”, might translate technically to “we will cook littely”, or “we do a little cooking” but either would be poor and incorrect english, and somehow miss the idea.
“we will do a spot of cooking” or “we will have some fun cooking” would be much closer to the original idea. But I suspect that Anthea Bell (of Asterix-to-english translation fame) would truly get the point; “let’s cook a feast….”
Back to the original question. Python programmers have a concept of pythonesque: = most fitting to the core ethos of python. The answer by user166390 (the accepted answer at the time of this answer) strikes me as the most JSONesque.
Could be compact in the JSON too, attribute is just the same as the value inside tag
from here:
http://www.json.org/example.html
{"widget": {
"debug": "on",
"window": {
"title": "Sample Konfabulator Widget",
"name": "main_window",
"width": 500,
"height": 500
},
"image": {
"src": "Images/Sun.png",
"name": "sun1",
"hOffset": 250,
"vOffset": 250,
"alignment": "center"
}
}}
The same text expressed as XML:
<widget>
<debug>on</debug>
<window title="Sample Konfabulator Widget">
<name>main_window</name>
<width>500</width>
<height>500</height>
</window>
<image src="Images/Sun.png" name="sun1">
<hOffset>250</hOffset>
<vOffset>250</vOffset>
<alignment>center</alignment>
</image>
</widget>
An example of how YQL presents XML and the corresponding JSON. No need to know anything about YQL to understand this but if you are interested your can check the YQL console and try it out yourself in the YQL console
XML
<results>
<a href="/">NBA</a>
<a class="topnav" href="#">TEAMS</a>
<a href="/teams/">Teams</a>
<a href="/hawks/">Atlanta</a>
JSON
"results": {
"a": [
{
"href": "/",
"content": "NBA"
},
{
"class": "topnav",
"href": "#",
"content": "TEAMS"
},
{
"href": "/teams/",
"content": "Teams"
},
{
"href": "/hawks/",
"content": "Atlanta"
},