There is such a well-known and very simple text format
JSON .
JSON format defines the following types:
null ,
boolean (
true ,
false ),
number ,
string ,
array ,
object .
But what if you set the task of representing any JSON data using only 4 types:
number ,
string ,
array ,
object ?
')

Welcome to the abnormal programming!
Program Guest:
NSNJSON (Not So Normal JSON)!
Content
Terms and designationsRepresentations for "simple" typesViews for “container” typesJSON recoveryJSON recovery for “simple” typesJSON recovery for “container” typesExamplesDriversConclusionLet's try to approach this task a little formally. In this article I will use the notation taken from
json.org . And for convenience I will add some of my own.
Terms and designations
We introduce the type
boolean =
true |
false .
And also we will enter the type
name , the values ​​of which make up a subset of the values ​​of type
string — those values ​​that are the correct name for the object field.
NSNJSON views use only three fields:
- t - type - value type (required field),
- v - value - value (required field),
- n - name - the name of the field (used in the field representations of the object).
Representations for "simple" types
To the “simple” types we will refer the following:
null ,
boolean ,
string ,
number .
Define an NSNJSON representation of P
null :
null →
objectvalue -> { "t": "null" }
Define an NSNJSON representation of P
true :
true →
object value -> { "t": "boolean", "v": 1 }
Define an NSNJSON representation of P
false :
false →
object value -> { "t": "boolean", "v": 0 }
Define the NSNJSON representation of P
string :
string →
object value -> { "t": "string", "v": value }
Define the NSNJSON representation of P
number :
number →
object value -> { "t": "number", "v": value }
Define an NSNJSON representation of P
simple :
“simple” type →
object :
P
simple (value) = P
null (value), if
value is a value of type
null ,
P
simple (value) = P
true (value) if
value is of type
true ,
P
simple (value) = P
false (value) if
value is of the type
false ,
P
simple (value) = P
string (value), if
value is of type
string ,
P
simple (value) = P
number (value) if
value is of type
number .
Views for “container” types
The following will be attributed to “container” types:
array ,
object .
Both
array and
object contain elements, therefore it is necessary:
- first, determine the presentation for each element,
- secondly, to determine the final representation of the entire "container", based on the representations of its elements.
First, consider the "containers", the values ​​in which have only the "simple" type.
First, let's deal with arrays, that is, values ​​of type
array .
Let
data array be a value of type
array , then you can represent an array as follows:
data = (e
1 , ..., e
n ),
where for all i = 1, ..., n,
n is the length of the array
e
i - array element - the value of the “simple” type.
Apply the presentation function P
simple to each element of the
data array.
dataElementsPresentation = (P
simple (e
1 ), ..., P
simple (e
n )).
Define an NSNJSON representation of P
array :
array →
object data -> { "t": "array", "v": dataElementsPresentation }
Now let's deal with objects, that is, values ​​of type
object .
Let
data object be a value of type
object , then you can represent an object as follows:
data = {(name
1 , value
1 ), ..., (name
n , value
n )},
where for all i = 1, ..., n,
n is the number of fields of the object
(name
i , value
i ) - the field of the object,
name
i - field name
value
i - field value - value of the “simple” type.
The JSON specification says that an object is an unordered set of fields, but in each specific case, we can always iterate over all the fields of the object and number them in the order of enumeration. Using this technique, it is possible to represent the
data object as an array of fields without loss of generality.
Let
valuePresentation be the result of applying the function P
simple to the value
value .
Define the NSNJSON representation of the P
field :
name Ă—
value →
object (name, value) -> { "n": name, "t": valuePresentation.t, "v": valuePresentation.v }
Apply the representation function P
field to each field of the
data object.
dataFieldsPresentation = (P
field (name
1 , value
1 ), ..., P
field (name
n , value
n )).
Define an NSNJSON representation of P
object :
object →
object data -> { "t": "object", "v": dataElementsPresentation }
Define the NSNJSON representation of P
container :
“container” type →
object :
P
container (value) = P
array (value), if
value is of type
array ,
P
container (value) = P
object (value) if
value is of type
object .
Finally, we define the final NSNJSON representation of P
json :
json →
object :
P
json (value) = P
simple (value), if
value is a value of "simple" type,
P
json (value) = P
container (value), if
value is the value of a “container” type.
If now in the presentation algorithms for “container” types instead of the function P
simple we use the function P
json , then we get the presentation functions that can work with “containers” containing any JSON values.
Thus, a scheme was constructed for representing any valid JSON data using only four JSON types:
number ,
string ,
array ,
object .
JSON recovery
We have JSON, we can now get NSNSJON from it.
But is it possible now to restore the original JSON?
Can.
Define the function of getting the type of JSON values ​​P
type :
object →
string presentation -> presentation.t
Let
type be the result of applying the
type function to the
presentation .
JSON recovery for “simple” types
Define the recovery function R
null :
object →
null presentation -> if (type == "null") { return null; }
Define the restore function R
number :
object →
string presentation -> if (type == "string") { return presentation.v; }
Define the restore function R
number :
object →
number presentation -> if (type == "number") { return presentation.v; }
Define the recovery function R
boolean :
object →
boolean presentation -> if (type == "boolean") { return presentation.v != 0; }
Define the recovery function R
simple :
object →
"simple" typeR
simple (presentation) = R
null (presentation), if
type = "null",
R
simple (presentation) = R
string (presentation), if
type = "string",
R
simple (presentation) = R
number (presentation), if
type = "number".
R
simple (presentation) = R
boolean (presentation), if
type = "boolean",
JSON recovery for “container” types
As before, we first consider “containers”, the values ​​of which have only the “simple” type.
Let there be a
presentation presentation of the
data array.
Apply the restore function R
simple to each element of the
presentation.v array.
data = (e
1 , ..., e
n ),
where for all i = 1, ..., n,
e
i - R
simple (presentation.v [i]) is an element of an array.
Define the recovery function of the R
array :
object →
array presentation -> if (type == "array") { return data; }
Suppose now there is a
presentation of the
data object.
Apply the recovery function R
simple to each element of the
presentation.v array and using the value of the
n field, we restore the object fields.
data = (e
1 , ..., e
n ),
where for all i = 1, ..., n,
e
i - (name
i , value
i ) - the field of the object,
name
i - presentation.v [i] .n - field name
value
i - R
simple (presentation.v [i]) - field value.
Define the recovery function R
object :
object →
object presentation -> if (type == "object") { return data; }
Define the recovery function R
container :
object →
"container" typeR
container (presentation) = R
array (value), if
type = "array",
R
container (presentation) = R
object (value) if
type = "object".
And finally, we define the recovery function R
json :
object →
json :
R
json (presentation) = R
simple (presentation), if the value of the “simple” type is restored,
R
json (presentation) = R
container (presentation) if the value of the “container” type is restored.
If now in the recovery algorithms for “container” types instead of the function R
simple we use the function R
json , then we will get presentation functions that can work with “containers” containing any JSON values.
Examples
In conclusion, I would like to show some simple examples demonstrating the use of the NSNJSON format.
examplesJson | NSNJSON (Not So Normal JSON) |
---|
null | { "t": "null" } |
true | { "t": "boolean", "v": 1 } |
false | { "t": "boolean", "v": 0 } |
213 | { "t": "number", "v": 213 } |
"Habrahabr" | { "t": "string", "v": "Habrahabr" } |
[ null, true, false, 213, "Habrahabr" ] | { "t": "array", "v": [ { "t": "null" }, { "t": "boolean", "v": 1 }, { "t": "boolean", "v": 0 }, { "t": "string", "v": "Habrahabr" } ] } |
[ { "userId": 17, "status": "online" }, { "userId": 19, "status": "offline" } ] | { "t": "array", "v": [ { "t": "object", "v": [ { "n": "userId", "t": "number", "v": 17 }, { "n": "status", "t": "string", "v": "online" } ] }, { "t": "object", "v": [ { "n": "userId", "t": "number", "v": 19 }, { "n": "status", "t": "string", "v": "offline" } ] } ] } |
{ "null_field": null, "true_field": true, "false_field": false, "number_field": 213, "string_field": "Habrahabr", "array_field": [ "JSON", "NSNJSON" ] } | { "t": "object", "v": [ { "n": "null_field", "t": "null" }, { "n": "true_field", "t": "boolean", "v": 1 }, { "n": "false_field", "t": "boolean", "v": 0 }, { "n": "number_field", "t": "number", "v": 213 }, { "n": "string_field", "t": "string", "v": "Habrahabr" }, { "n": "array_field", "t": "array", "v": [ { "t": "string", "v": "JSON" }, { "t": "string", "v": "NSNJSON" } ] } ] } |
Drivers
I made two small drivers for those who want to play with this format.
Drivers are available on GitHub on the project page:
nsnjson !
Drivers:
Good news for fans of
npmjs.com !
Now the Node.js driver is available
there too !
And if you want to try NSNJSON using the Java driver, then on the project page you can find instructions on how to configure the
Maven pom.xml
file so as not to download the driver manually! :)
Conclusion
It remains for me to remind you that NSNJSON (Not So Normal JSON) was the guest of the program “Abnormal Programming” today!
Thanks for attention!