📜 ⬆️ ⬇️

Advanced Simplified JSON

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 designations
Representations for "simple" types
Views for “container” types
JSON recovery
JSON recovery for “simple” types
JSON recovery for “container” types
Examples
Drivers
Conclusion

Let'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:


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 → object
value -> { "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, 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" type
R 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" type
R 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.

examples
JsonNSNJSON (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!

Source: https://habr.com/ru/post/269461/


All Articles