Filed in: Ideas.Superstruct · Modified on : Tue, 14 Dec 10
While JSON is fun, it's really meant for a one-off, "here's your document; I don't need it back" kind of situation. If we compare JSON to XML (and its entourage), JSON's missing a common manipulation framework, for one thing.
Instead of looking at JSON as simply a "notation" and a way to transmit information, in this article, we look at it more as a changeable object in memory, akin to the DOM.
A "superstruct" is used to refer to this new DOM-like idea (sexier name forthcoming).
A JSON document is essentially a tree with a few types of nodes and edges:
The structure of this document can be described using JSONSchema. The schema/structure of a document is fixed for its lifetime.
There are essentially two subtypes of arrays that often need to be treated separately:
There's a need to specify particular node(set)s within the tree. The path syntax I use looks like paths in UNIX:
Every node should have exactly one canonical absolute path.
Unlike UNIX filesystems paths, a superstruct path may specify multiple nodes.
The intention of JSON is to transmit data, not to store it. As such, there are no operations defined to manipulate the tree. Javascript itself has methods for dealing with the components of a superstruct, but not with a superstruct as a whole.
superstruct operations have:
While the parameter and the return value are superstructs, it could be as simple as a single leaf.
This allows for compatibility with JSON-RPC.
Method signatures are specified in the form input:datatype»methodname»output:datatype.
Some common datatypes:
Creates a new superstruct. A superstruct is initialized in a few phases:
Building the structure of the tree is somewhat difficult. Optional elements (including variable-length/non-tuple-typed arrays) should not be precreated, rather this should be done when the optional element is written to.
Evaluates paths and returns the nodesuperset result.
["/a", "/b"] » read is equivalent to ["/(a|b)"] » read.
Write new_values to canonical_paths. Writing is really more of a "graft" operation.
[0:-1] of the path must already exist in the superstruct.
Depending on the last few components, write has different behaviour:
write supports writing to multiple paths at once, so it is in effect a transaction.
Returns subschemas for each canonical_path.