Update: I was not aware of JSPON - JavaScript Persistent Object Notation (JSPON) - which addresses the problem below (I wrote the text below before my knowledge of JSPON!). Thanks to Andres Almiray for pointing me about that.
JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. JSON can be used as replacement for XML (AJAX without the "X" for XML).
But, JSON does not have syntax for circular references - most JSON libraries expect the data structure to-be-serialized to have no cycles. In XML, typically special attributes such as ID and IDREF (or HREF in HTML) are used to create links between elements. (see also XML:id).
Here is a proposal for simple conventions to handle circular references. We can use few special properties with name starting with a "$". "$id" property uniquely identifies a JSON object within a JSON document. Such objects can be referred elsewhere by "$idref". In addition, we may "reserve" all properties starting with a letter "$".
Few examples:
String valued property that identifies an object uniquely within a JSON document/file.
String valued property that refers to another object within the same JSON document/file.
Example:
{
"$id" : "thisobj",
"name": "Simple object",
"date": { "day" : 16, "month": 10, "year": 2006},
"mycontainer" : { "$idref": "thisobj" }
}
In the above example, "mycontainer" property refers back to the JSON object that contains "name", "date" and "mycontainer" properties.
Since, we cannot add "$xxx" properties to JSON arrays, we need a slighly different mechanism for hanlding array references. We can serialize an array that will be referred elsewhere as follows:
{
"x": { "$id" : "myarray" , "$": [2, 3, 54654] },
"y": { "$idref": "myarray" }
}
"$class" property helps while mapping JSON objects back to language specific objects - for example, objects of specific Java bean classes. "$class" property may be used differently with other language bindings. For example, with JavaScript, the value of this property may be treated as a code string that will be evaluated to get "prototype" of the object being parsed. This way
{
"$class" : "java.util.Date",
"day" : 16,
"month" : 9,
"year": 106,
}
After deserialization, the object will have two array valued properties "x" and "y" both would point to the same array.
String valued property that refers to another JSON document/file - like HTML Anchor tag. Also, "fragment" identifiers can be mapped to "$id" within the referred JSON URI. This way we can have "network" of JSON documents. Such "href"-ed fragments may be loaded using XMLHttpRequest or some such mechanism [may be lazily when that property is referred for the first time].
I've checked-in Java classes to serialize/de-serialize JSON with the above "extensions" at http://scripting.dev.java.net - the code is here
There is one issue with this scheme - with JavaScript we can deserialize JSON with "$id" and "$idref" etc. and resolve references, it is difficult to serialize. There is IdentityHashMap or equivalent in (pure) JavaScript [did I miss any such cool-trick?]. To detect whether we have serialized an object already or not [so that we can generate $idref instead of serializing it again], we may have to keep a list of visited objects (i.e, JS array) and walk through that list everytime and so the implementation would be slow for bigger object graphs. Note that this issue does not arise with Rhino implementation - because we can use IdentityHashMap API with Rhino.
Posted by Andres Almiray on October 16, 2006 at 09:05 PM IST #