Есть такой известный и весьма простой текстовый формат 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 представлениях используется всего три поля:
К «простым» типам будем относить следующие: null, boolean, string, number.
Определим NSNJSON представление Pnull : null → object
Определим NSNJSON представление Ptrue : true → object
Определим NSNJSON представление Pfalse : false → object
Определим NSNJSON представление Pstring : string → object
Определим NSNJSON представление Pnumber : number → object
Определим 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 : array → object
Теперь разберемся с объектами, то есть значениями типа object.
Пусть объект data это значение типа object, тогда можно представить объект следующим образом:
data = { (name1, value1), ..., (namen, valuen) },
где для всех i = 1, ..., n,
n — количество полей объекта,
(namei, valuei) — поле объекта,
namei — имя поля
valuei — значение поля — значение «простого» типа.
В JSON спецификации сказано, что объект это неупорядоченный набор полей, однако в каждом конкретном случае, мы всегда можем перебрать все поля объекта и пронумеровать их в порядке перебора. Воспользовавшись таким приемом, монжно представить объект data в качестве массива полей без потери общности.
Пусть valuePresentation — результат применения функции представления Psimple к значению value.
Определим NSNJSON представление Pfield : name × value → object
Применим функцию представления Pfield к каждому поля объекта data.
dataFieldsPresentation = (Pfield(name1, value1), ..., Pfield(namen, valuen)).
Определим NSNJSON представление Pobject : object → object
Определим NSNJSON представление Pcontainer : «контейнерный» тип → object:
Pcontainer(value) = Parray(value), если value значение типа array,
Pcontainer(value) = Pobject(value), если value значение типа object.
Наконец, определим итоговое NSNJSON представление Pjson : json → object:
Pjson(value) = Psimple(value), если value значение «простого» типа,
Pjson(value) = Pcontainer(value), если value значение «контейнерного» типа.
Если теперь в алгоритмах представления для «контейнерных» типов вместо функции Psimple использовать функцию Pjson, то получим функции представления, которые могут работать с «контейнерами», содержащими любые JSON значения.
Таким образом была построена схема представления любых корректных JSON данных с помощью всего четырех JSON типов: number, string, array, object.
У нас есть JSON, мы из него теперь можем получить NSNSJON.
Но можно ли теперь восстановить исходный JSON?
Можно.
Определим функцию получения типа JSON значения Ptype : object → string
Пусть type — результат применения функции Ptype к представлению presentation.
Определим функцию восстановления Rnull : object → null
Определим функцию восстановления Rnumber : object → string
Определим функцию восстановления Rnumber : object → number
Определим функцию восстановления Rboolean : object → boolean
Определим функцию восстановления 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»,
Также как и ранее, сперва рассмотрим «контейнеры», значения в которых имеют только «простой» тип.
Пусть имеется представление presentation массива data.
Применим функцию восстановления Rsimple к каждому элементу массива presentation.v.
data = (e1, ..., en),
где для всех i = 1, ..., n,
ei — Rsimple(presentation.v[i]) — элемент массива.
Определим функцию восстановления Rarray : object → array
Пусть теперь имеется представление 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 : object → object
Определим функцию восстановления Rcontainer : object → «контейнерный» тип
Rcontainer(presentation) = Rarray(value), если type = «array»,
Rcontainer(presentation) = Robject(value), если type = «object».
И в итоге, определим функцию восстановления Rjson : object → json:
Rjson(presentation) = Rsimple(presentation), если восстанавливается значение «простого» типа,
Rjson(presentation) = Rcontainer(presentation), если восстанавливается значение «контейнерного» типа.
Если теперь в алгоритмах восстановления для «контейнерных» типов вместо функции Rsimple использовать функцию Rjson, то получим функции представления, которые могут работать с «контейнерами», содержащими любые JSON значения.
В заключении, хотелось бы показать несколько простых примеров демонстрирующих применение формата NSNJSON.
Я сделал два небольших драйвера для желающих поиграться с данным форматом.
Драйверы доступны на GitHub на странице проекта: nsnjson!
Драйверы:
Хорошая новость для любителей npmjs.com!
Теперь Node.js драйвер доступен и там!
А если Вы хотите попробовать NSNJSON с помощью Java драйвера, то на странице проекта Вы сможете найти инструкцию как настроить Maven файлик pom.xml, чтобы не скачивать драйвер вручную! :)
Мне осталось напомнить, что сегодня гостем программы «Ненормальное программирование» был NSNJSON (Not So Normal 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 представлениях используется всего три поля:
- t — type — тип значения (обязательное поле),
- v — value — значение (обязательное поле),
- n — name — имя поля (используется в представлениях полей объекта).
Представления для «простых» типов
К «простым» типам будем относить следующие: null, boolean, string, number.
Определим NSNJSON представление Pnull : null → object
value -> { "t": "null" }
Определим NSNJSON представление Ptrue : true → object
value -> { "t": "boolean", "v": 1 }
Определим NSNJSON представление Pfalse : false → object
value -> { "t": "boolean", "v": 0 }
Определим NSNJSON представление Pstring : string → object
value -> { "t": "string", "v": value }
Определим NSNJSON представление Pnumber : number → object
value -> { "t": "number", "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 : array → object
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 × value → object
(name, value) -> { "n": name, "t": valuePresentation.t, "v": valuePresentation.v }
Применим функцию представления Pfield к каждому поля объекта data.
dataFieldsPresentation = (Pfield(name1, value1), ..., Pfield(namen, valuen)).
Определим NSNJSON представление Pobject : object → object
data -> { "t": "object", "v": dataElementsPresentation }
Определим NSNJSON представление Pcontainer : «контейнерный» тип → object:
Pcontainer(value) = Parray(value), если value значение типа array,
Pcontainer(value) = Pobject(value), если value значение типа object.
Наконец, определим итоговое NSNJSON представление Pjson : json → object:
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 : object → string
presentation -> presentation.t
Пусть type — результат применения функции Ptype к представлению presentation.
Восстановление JSON для «простых» типов
Определим функцию восстановления Rnull : object → null
presentation -> if (type == "null") { return null; }
Определим функцию восстановления Rnumber : object → string
presentation -> if (type == "string") { return presentation.v; }
Определим функцию восстановления Rnumber : object → number
presentation -> if (type == "number") { return presentation.v; }
Определим функцию восстановления Rboolean : object → boolean
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 : object → array
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 : object → object
presentation -> if (type == "object") { return data; }
Определим функцию восстановления Rcontainer : object → «контейнерный» тип
Rcontainer(presentation) = Rarray(value), если type = «array»,
Rcontainer(presentation) = Robject(value), если type = «object».
И в итоге, определим функцию восстановления Rjson : object → json:
Rjson(presentation) = Rsimple(presentation), если восстанавливается значение «простого» типа,
Rjson(presentation) = Rcontainer(presentation), если восстанавливается значение «контейнерного» типа.
Если теперь в алгоритмах восстановления для «контейнерных» типов вместо функции Rsimple использовать функцию Rjson, то получим функции представления, которые могут работать с «контейнерами», содержащими любые JSON значения.
Примеры
В заключении, хотелось бы показать несколько простых примеров демонстрирующих применение формата NSNJSON.
примерчики
JSON | NSNJSON (Not So Normal JSON) |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Драйверы
Я сделал два небольших драйвера для желающих поиграться с данным форматом.
Драйверы доступны на GitHub на странице проекта: nsnjson!
Драйверы:
Хорошая новость для любителей npmjs.com!
Теперь Node.js драйвер доступен и там!
А если Вы хотите попробовать NSNJSON с помощью Java драйвера, то на странице проекта Вы сможете найти инструкцию как настроить Maven файлик pom.xml, чтобы не скачивать драйвер вручную! :)
Заключение
Мне осталось напомнить, что сегодня гостем программы «Ненормальное программирование» был NSNJSON (Not So Normal JSON)!
Спасибо за внимание!