Усложнённый упрощённый JSON

от автора

Есть такой известный и весьма простой текстовый формат JSON.

JSON формат определяет следующие типы: null, boolean (true, false), number, string, array, object.

А что, если поставить задачу о представлении любых JSON данных с помощью всего 4 типов: number, string, array, object?

Добро пожаловать в ненормальное программирование!
Гость программы: NSNJSON (Not So Normal JSON)!

Содержание

Термины и обозначения
Представления для «простых» типов
Представления для «контейнерных» типов
Восстановление JSON
Восстановление JSON для «простых» типов
Восстановление JSON для «контейнерных» типов
Примеры

Попробуем подойти к данной задаче немного формально. В этой статье, я буду использовать обозначения взятые с сайта json.org. И для удобства добавлю немного своих.

Термины и обозначения

Введем тип boolean = true | false.

А еще введем тип name, значения которого, состовляют подмножество значений типа string — те значения, которые являются корректным именем для поля объекта.

В NSNJSON представлениях используется всего три поля:

  • ttype — тип значения (обязательное поле),
  • vvalue — значение (обязательное поле),
  • nname — имя поля (используется в представлениях полей объекта).

Представления для «простых» типов
К «простым» типам будем относить следующие: null, boolean, string, number.

Определим NSNJSON представление Pnull : nullobject

value -> { "t": "null" } 

Определим NSNJSON представление Ptrue : trueobject

value -> { "t": "null", "v": 1 } 

Определим NSNJSON представление Pfalse : falseobject

value -> { "t": "null", "v": 0 } 

Определим NSNJSON представление Pstring : stringobject

value -> { "t": "null", "v": value } 

Определим NSNJSON представление Pnumber : numberobject

value -> { "t": "null", "v": value } 

Определим NSNJSON представление Psimple : «простой» типobject:
Psimple(value) = Pnull(value), если value значение типа null,
Psimple(value) = Ptrue(value), если value значение типа true,
Psimple(value) = Pfalse(value), если value значение типа false,
Psimple(value) = Pstring(value), если value значение типа string,
Psimple(value) = Pnumber(value), если value значение типа number.

Представления для «контейнерных» типов

К «контейнерным» типам будем относить следующие: array, object.

И array и object содержат элементы, поэтому необходимо:

  • во-первых, определить представление для каждого элемента,
  • во-вторых, определить итоговое представление всего «контейнера», на основе представлений его элементов.

Сперва рассмотрим «контейнеры», значения в которых имеют только «простой» тип.

Для начала разберемся с массивами, то есть значениями типа array.

Пусть массив data это значение типа array, тогда можно представить массив следующим образом:
data = (e1, …, en),
где для всех i = 1, …, n,
  n — длина массива,
  ei — элемент массива — значение «простого» типа.

Применим функцию представления Psimple к каждому элементу массива data.

dataElementsPresentation = (Psimple(e1), …, Psimple(en)).

Определим NSNJSON представление Parray : arrayobject

data -> { "t": "array", "v": dataElementsPresentation } 

Теперь разберемся с объектами, то есть значениями типа object.

Пусть объект data это значение типа object, тогда можно представить объект следующим образом:
data = { (name1, value1), …, (namen, valuen) },
где для всех i = 1, …, n,
  n — количество полей объекта,
  (namei, valuei) — поле объекта,
    namei — имя поля
    valuei — значение поля — значение «простого» типа.

В JSON спецификации сказано, что объект это неупорядоченный набор полей, однако в каждом конкретном случае, мы всегда можем перебрать все поля объекта и пронумеровать их в порядке перебора. Воспользовавшись таким приемом, монжно представить объект data в качестве массива полей без потери общности.

Пусть valuePresentation — результат применения функции представления Psimple к значению value.

Определим NSNJSON представление Pfield : name × valueobject

(name, value) -> { "n": name, "t": valuePresentation.t, "v": valuePresentation.v } 

Применим функцию представления Pfield к каждому поля объекта data.

dataFieldsPresentation = (Pfield(name1, value1), …, Pfield(namen, valuen)).

Определим NSNJSON представление Pobject : objectobject

data -> { "t": "object", "v": dataElementsPresentation } 

Определим NSNJSON представление Pcontainer : «контейнерный» типobject:
Pcontainer(value) = Parray(value), если value значение типа array,
Pcontainer(value) = Pobject(value), если value значение типа object.

Наконец, определим итоговое NSNJSON представление Pjson : jsonobject:
Pjson(value) = Psimple(value), если value значение «простого» типа,
Pjson(value) = Pcontainer(value), если value значение «контейнерного» типа.

Если теперь в алгоритмах представления для «контейнерных» типов вместо функции Psimple использовать функцию Pjson, то получим функции представления, которые могут работать с «контейнерами», содержащими любые JSON значения.

Таким образом была построена схема представления любых корректных JSON данных с помощью всего четырех JSON типов: number, string, array, object.

Восстановление JSON

У нас есть JSON, мы из него теперь можем получить NSNSJON.
Но можно ли теперь восстановить исходный JSON?
Можно.

Определим функцию получения типа JSON значения Ptype : objectstring

presentation -> presentation.t 

Пусть type — результат применения функции Ptype к представлению presentation.

Восстановление JSON для «простых» типов

Определим функцию восстановления Rnull : objectnull

presentation -> if (type == "null") { return null; } 

Определим функцию восстановления Rnumber : objectstring

presentation -> if (type == "string") { return presentation.v; } 

Определим функцию восстановления Rnumber : objectnumber

presentation -> if (type == "number") { return presentation.v; } 

Определим функцию восстановления Rboolean : objectboolean

presentation -> if (type == "boolean") { return presentation.v != 0; } 

Определим функцию восстановления Rsimple : object«простой» тип
Rsimple(presentation) = Rnull(presentation), если type = «null»,
Rsimple(presentation) = Rstring(presentation), если type = «string»,
Rsimple(presentation) = Rnumber(presentation), если type = «number».
Rsimple(presentation) = Rboolean(presentation), если type = «boolean»,

Восстановление JSON для «контейнерных» типов

Также как и ранее, сперва рассмотрим «контейнеры», значения в которых имеют только «простой» тип.

Пусть имеется представление presentation массива data.

Применим функцию восстановления Rsimple к каждому элементу массива presentation.v.
data = (e1, …, en),
где для всех i = 1, …, n,
  ei — Rsimple(presentation.v[i]) — элемент массива.

Определим функцию восстановления Rarray : objectarray

presentation -> if (type == "array") { return data; } 

Пусть теперь имеется представление presentation объекта data.

Применим функцию восстановления Rsimple к каждому элементу массива presentation.v и используя значение поля n восстановим поля объекта.
data = (e1, …, en),
где для всех i = 1, …, n,
  ei — (namei, valuei) — поле объекта,
    namei — presentation.v[i].n — имя поля
    valuei — Rsimple(presentation.v[i]) — значение поля.

Определим функцию восстановления Robject : objectobject

presentation -> if (type == "object") { return data; } 

Определим функцию восстановления Rcontainer : object«контейнерный» тип
Rcontainer(presentation) = Rarray(value), если type = «array»,
Rcontainer(presentation) = Robject(value), если type = «object».

И в итоге, определим функцию восстановления Rjson : objectjson:
Rjson(presentation) = Rsimple(presentation), если восстанавливается значение «простого» типа,
Rjson(presentation) = Rcontainer(presentation), если восстанавливается значение «контейнерного» типа.

Если теперь в алгоритмах восстановления для «контейнерных» типов вместо функции Rsimple использовать функцию Rjson, то получим функции представления, которые могут работать с «контейнерами», содержащими любые JSON значения.

Примеры

В заключении, хотелось бы показать несколько простых примеров демонстрирующих применение формата NSNJSON.

примерчики

JSON 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",       "v": ""     },     {       "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"         }       ]     }   ] } 

Мне осталось напомнить, что сегодня гостем программы «Ненормальное программирование» был NSNJSON (Not So Normal JSON)!
Спасибо за внимание!

ссылка на оригинал статьи http://habrahabr.ru/post/269461/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *