Есть такой известный и весьма простой текстовый формат 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)!
Спасибо за внимание!
Комментарии (15)
michael_vostrikov
26.10.2015 08:44Так можно и одним типом string обойтись. И передавать через JSON не только невалидный JSON, но и код в любом другом формате или на языке программирования. Надо будет просто функцию восстановления написать.
{ value: "................................................" }
jxcoder
26.10.2015 09:03+1Мне не понравилась такая идея и я решил изобрести NSNJSON. К тому же в Вашей идее необходимо знать природу этих данных. Здесь же всё прозрачно и универсально.
jxcoder
26.10.2015 12:43+2Уважаемые, почему такая реакция в разделе «Ненормальное программирование»? :) Решение не предлагается для промышленного внедрения. Преследовалась совершенно простая цель. Никаких намеков на производительность и крутость! :) Разве данная статья противоречит правилам Хабра или раздела «Ненормальное программирование»? :) За что минусы-то? :)
TheRabbitFlash
Ничего не понял. А зачем это надо и что оно даст?
jxcoder
Ну это же ненормальное программирование. Оно не должно что-то давать. Оно просто есть.
В качестве одно из примеров применения могу предложить передачу объектов, содержащие значения не входящие в спецификацию JSON. Для простоты возьму ObjectId из MongoDB.
Вот берем какой-нибудь документик:
Этот документ, не является валидным JSON.
А мы возьмём и преобразуем его в JSON-формат:
И всё, теперь это валидный JSON. Написать функцию восстановления тоже не составит труда.
RPG18
Что-то не понимаю примера. Берем BJSON и перегоняем в NSNJSON только из-за того, что можем так сделать?
jxcoder
:) пример демонстрирует один из способов применения. Примером я хотел показать, как передавать данные, которые не являются валидным JSON. Хотелось придумать формат, который основывался на каком-нибудь известном формате и требовал бы минимум усилий для написания драйверов для этого формата.
vintage
Не лучше ли вместо JSON использовать более приспособленные для этого форматы?
jxcoder
Можно. Почему бы нет?! :)
Я ставил задачу реализовать все множество JSON на основе лишь его подмножества. И более-менее формально описал процесс. Не нужно думать, что я предлагаю какое-то новое решение для промышленных задач. Вовсе нет. Просто была идея и просто она реализованна! :)