Комментарии в формате JSON

Наткнулся случайно на ссылку, где автора очень изящно решает проблему комментариев в формате «джейсон». Это лучшее решение, которое я только видел (обычно либо выделяют специальный ключ, либо расширяют формат). Только поглядите:
{
  "api_host" : "The hostname of your API server. You may also specify the port.",
  "api_host" : "hodorhodor.com",

  "retry_interval" : "The interval in seconds between retrying failed API calls",
  "retry_interval" : 10,

  "auth_token" : "The authentication token. It is available in your developer dashboard under 'Settings'",
  "auth_token" : "5ad0eb93697215bc0d48a7b69aa6fb8b",

  "favorite_numbers": "An array containing my all-time favorite numbers",
  "favorite_numbers": [19, 13, 53]
}
Он полностью синтаксически верен и разбирается правильным образом во всех языках, по всей видимости.
24 октября 2014 15:53

alxt (инкогнито)
24 октября 2014, 16:19

Работает. Но что-то в этом кривое. Хотя для web'а это привычно- там всё такое.

RomaS (инкогнито)
24 октября 2014, 16:21

An object structure is represented as a pair of curly brackets
   surrounding zero or more name/value pairs (or members). A name is a
   string. A single colon comes after each name, separating the name
   from the value. A single comma separates a value from a following
   name. The names within an object SHOULD be unique.

Евгений Степанищев (bolknote.ru)
24 октября 2014, 16:29, ответ предназначен RomaS

RFC 2119
SHOULD This word, or the adjective "RECOMMENDED", mean that there
may exist valid reasons in particular circumstances to ignore a
particular item, but the full implications must be understood and
carefully weighed before choosing a different course.

Евгений Степанищев (bolknote.ru)
24 октября 2014, 16:30, ответ предназначен alxt

Работает. Но что-то в этом кривое. Хотя для web'а это привычно — там всё такое.
Мда? Ну вот, скажем, Perl был разработан не для веба, а Си весь вызывает ощущение кривизны.

alxt (инкогнито)
24 октября 2014, 16:37

Я ж не говорю, что всё, что не для веба- хорошо :D

SunChaser (sunchaser.info)
24 октября 2014, 16:38

Проверил — это так же норм жуётся парсерами Yaml в Ruby и PHP (ext-yaml)
Неправильно работает парсер Yaml в Symfony, но он и в целом плохо парсит JSON

(т.к. json подмножество yaml, неплохо бы не терять эту совместимость)

Евгений Степанищев (bolknote.ru)
24 октября 2014, 17:15, ответ предназначен SunChaser (sunchaser.info):

Симфони поддерживает Yaml 1.2 же, а JSON — это Yaml 2.0, если не ошибаюсь.

Евгений Степанищев (bolknote.ru)
24 октября 2014, 17:23, ответ предназначен alxt

Ну так и утверждение «там всё такое» тоже неверно.

Евгений Степанищев (bolknote.ru)
24 октября 2014, 18:02, ответ предназначен SunChaser (sunchaser.info):

Симфони поддерживает Yaml 1.2 же, а JSON — это Yaml 2.0, если не ошибаюсь.
Ошибаюсь, 2.0 не существует, как раз с 1.2 перепутал.

SunChaser (sunchaser.info)
24 октября 2014, 18:36, ответ предназначен Евгений Степанищев (bolknote.ru):

ага, но там даже не Yaml 1.2, а "selected subset of features" из Yaml 1.2

kxepal (инкогнито)
25 октября 2014, 02:24

Это все равно решение из разряда "костыль" т.к. стандарт JSON ничего не говорит о том, как обрабатывать дубликаты ключей в объекте. YAML например, прямо и явно их запрещяет. Это ведет к неопределенному поведению в различных библиотеках, которые могут совершенно спокойно взять первый ключ "с комментарием" и выбросить все остальные "с данными" - и это поведение будет совершенно корректно с точки зрения стандарта. Так же некоторые JSON парсеры раскладывают object не в hash-map, а в список ключ-значение сохраняя тем самым и "комментарий" и "значение" перекладывая на пользователя ответственность за дубликаты ключей - это поведение так же совершенно корректо с точки зрения стандарта.

Закладываться на такое поведение не рекомендуется - можно в один прекрасный момент наткнуться на интересные баги. Если нужны комментарии в JSON, возможно стоит обратить внимане на другие форматы. Или остановиться на том же YAML (для которого, кстати, JSON не является полным подмножеством - там есть пограничные случаи когда JSON не будет соответствовать стандарту YAML).

Евгений Степанищев (bolknote.ru)
25 октября 2014, 12:13, ответ предназначен kxepal

Всегда обход ограничений чего-либо — это костыль, разумеется, как иначе? Но вы так говорите, как будто «джейсон» — формат данный свыше. Вот есть решение, которое малой кровью добавляет комментарии. Осталось его правильно оформить и закинуть на json.org, пусть сделают новый формат JSON 1.1 — тот же JSON, но с комментами. Потому что другие решения явно хуже.

Да и проблем, описанных вами, я не вижу. Очевидно же (или нет?), что формат с комментариями нужен не для обмена (зачем там комментарии?), а я для хранения (конфигов и чего-то близкого к ним), а это значит парсить его будут управляемый нами код. Что я сделал в подобных случаях, я описал — в одном случае расширил JSON обычными JS-комментариями (это удобно, но совершенно несовместимо с текущим форматом), в другом — завёл «мусорные» ключи (ужасно неудобно, но 100% совместимо). Решение с двойными ключами находится посередине — (вероятно) полностью совместимо, но не так удобно, как отдельные комментарии.

kxepal (инкогнито)
25 октября 2014, 20:22, ответ предназначен Евгений Степанищев (bolknote.ru):

Очевидно же (или нет?), что формат с комментариями нужен не для обмена (зачем там комментарии?), а я для хранения (конфигов и чего-то близкого к ним), а это значит парсить его будут управляемый нами код.
В таком случае возникает вполне логичный вопрос: "а зачем нам JSON?". Или перефразируя: "а зачем нам втыкать костыли в формат, не предназначенный для конфигов?". Есть много других замечательным форматов для конфигурации как то YAML, INI, TOML...XML в конце концов. Тем более, что парсить его будет управляемый нами код. Понимаю, что адаптировать любимый инструмент под случай, на который он не рассчитывался, всегда интересно, но это редко когда заканчивается чем-то хорошим.

Иван (инкогнито)
26 октября 2014, 08:13

На мой взгляд, конфиги лучше хранить в старом добром ини-файле. Там и секции, и комментарии. Джейон лучше использовать для передачи файлов.
И никто не гарантирует, что в каком-то языке библиотека парсинга будет брать первое поле и пропускать последующие дубли.

Иван (инкогнито)
26 октября 2014, 08:13

*для передачи данных

Евгений Степанищев (bolknote.ru)
26 октября 2014, 10:52, ответ предназначен kxepal

Не люблю зоопарки, в том числе и форматов. JSON хорош как для конфигурирования, так и для обмена данными. INI для обмена данными плох, YAML сложный, XML ужасен, что такое TOML я не знаю и, видимо, знать этого мне не нужно.
Понимаю, что адаптировать любимый инструмент под случай, на который он не рассчитывался, всегда интересно, но это редко когда заканчивается чем-то хорошим.
Да что тут адаптировать? Оно ж само работает. Причём понятно каждому, кто хоть раз писал парсер, почему оно так работает.

Иван (инкогнито)
26 октября 2014, 11:57

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

Евгений Степанищев (bolknote.ru)
26 октября 2014, 12:28, ответ предназначен Ивану

Мда? Как же хранить в ini-файле произвольные массивы?

Иван (инкогнито)
26 октября 2014, 14:20, ответ предназначен Евгений Степанищев (bolknote.ru):

# some.ini
[mysection]
myarray = 1 2 3 4 5

# some.code
myIni.read('/path/to/file')
myIni.getIntArray('mysection', 'myarray')

Евгений Степанищев (bolknote.ru)
26 октября 2014, 14:55, ответ предназначен Ивану

То есть никак? Вот у меня есть такой массив в джейсоне, например:
{"APM": [1,3], "other": [8], "KKM": [5,2]}, что с ним делать? А бывают структуры и ещё более сложные.

Иван (инкогнито)
26 октября 2014, 15:19, ответ предназначен Евгений Степанищев (bolknote.ru):

Что значит никак? Ини файл предполагает упрощение структуры данных.
В вашем случае в ини-файле будет секция [foo] и три поля: APM = 1 3, other = 8, KKM = 5 2
Сложные древовидные структуры очень плохо поддаются редактированию человеком. Добавить новое поле в объект на третьем уровне сложности становится реально тяжело. Про перестановки с места на место вообще не говорю. Настройки нужно упрощать, сложные структуры проводить к линейному виду.

Евгений Степанищев (bolknote.ru)
26 октября 2014, 15:44, ответ предназначен Ивану

Я вот смотрю на конфиг нашего проекта (он в «джейсоне»), там аж до 7 уровня сложности есть и не ощущаю ровно никаких сложностей в его редактировании. Не вижу никакого смысла приводить нормальные сложные структуры, где ещё и типы сразу видно, к плоским ini-файлам.

Иван (инкогнито)
26 октября 2014, 15:53, ответ предназначен Евгений Степанищев (bolknote.ru):

Конфиг в 7 уровней кажется вам удобным только потому, что вы с ним каждый день работаете.
И вы не можете вписать в него комментарий нормальным способом. Как разбирать этот ад без коментов -- загадка. Если делать это дублирование полей, то такой комментарий не будет выделен цветом и его трудно увидеть. И можно случайно переставить порядок ключей при редактировании и зафакапиться.

Евгений Степанищев (bolknote.ru)
26 октября 2014, 16:34, ответ предназначен Ивану

Как разбирать этот ад без коментов — загадка
По документации? На ад, кстати, он совсем не похож. Кроме того, в нашем конфиге комментарии всё же есть — мы расширили JSON.

Иван (инкогнито)
26 октября 2014, 18:02, ответ предназначен Евгений Степанищев (bolknote.ru):

мы расширили JSON.
Вок к каким велосипедам можно прийти, если использовать формат не по назначению.

Евгений Степанищев (bolknote.ru)
26 октября 2014, 18:12, ответ предназначен Ивану

Вы так говорите, как будто велосипеды — это плохо. Альтернативы-то всё одно нет.

Иван (инкогнито)
26 октября 2014, 18:42, ответ предназначен Евгений Степанищев (bolknote.ru):

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

Евгений Степанищев (bolknote.ru)
26 октября 2014, 19:33, ответ предназначен Ивану

Да ничего подобного. Новички читают этот конфиг, даже не замечая, что комментариев там быть не должно вообще-то. ini-файлы это уж точно не формат, подходящий для конфига, потому что у него нет типов данных, у него есть интерпретация и она зашита в коде, не читая код, нельзя сказать что перед нами.

Вы мне предложили сделать буквально следующее:
В вашем случае в ини-файле будет секция [foo] и три поля: APM = 1 3, other = 8, KKM = 5 2
Это одни из самых зверский костылей, которые я только видел. Во-первых, секция должна быть вложена тут в другую секцию, а та — в свою, это будет очень нечитаемо, во-вторых, неясно что перед нами: массив чисел? Строка? Как перемешать в массив числа, строки, булевы значения и null? Думаю, что вы просто предло́жите какое-то соглашение, которое будет интерпретироваться на уровне кода. JSON туда куда лучше.

Иван (инкогнито)
26 октября 2014, 19:58, ответ предназначен Евгений Степанищев (bolknote.ru):

в джейсоне тоже ограниченная система типов. в реальном проекте вам потребуется хранить даты, регулярки. Например, чтобы получился datetime, нужно нужно распарсить строку, а для регулярки получить скомпилленый объект.
Во-первых, секция должна быть вложена тут в другую секцию, а та — в свою
зачем вкладывать? у вас есть какой-то словарь, ему можно присвоить имя и записать в секцию. делайте данные линейными. ваша вложеность на 7 уровней -- дело только ваших рук. Вы в курсе, что питоноский LoggingDict может быть свободно описан в ини-файле?
Как перемешать в массив числа, строки, булевы значения и null?
я коров с лошадьми не мешаю. Это явно неудачный кейс.

Евгений Степанищев (bolknote.ru)
26 октября 2014, 20:08, ответ предназначен Ивану

Ну, у меня проект реальный. Я описываю с тем, с чем сталкиваюсь.
зачем вкладывать? у вас есть какой-то словарь, ему можно присвоить имя и записать в секцию.
Потому что есть модули, в них — другие модули. Конфиг отражает эту вложенность. Плоский конфиг ничего не отражает.
я коров с лошадьми не мешаю. Это явно неудачный кейс.
В реальной жизни null запросто мешается с остальными типами, это очень частый случай (а не «кейс»).

Иван (инкогнито)
26 октября 2014, 20:19, ответ предназначен Евгений Степанищев (bolknote.ru):

Плоский конфиг ничего не отражает.
заведите доменную систему имен, типа app.module.menu и будет все норм
В реальной жизни null запросто мешается с остальными типами
массив, в котором все до кучи -- числа, строки, нулл -- это какой-то нонсенс. Смешанные типы могут пригодиться разве что в jsonschema для проверки входных данных (в отдельном файле)

Евгений Степанищев (bolknote.ru)
26 октября 2014, 20:20, ответ предназначен Ивану

заведите доменную систему имен, типа app.module.menu и будет все норм
Вы упорно сопротивляетесь нормальному формату, сочиняя костыли на ходу.
массив, в котором все до кучи — числа, строки, нулл — это какой-то нонсенс
Так давайте рассмотрим более простой вариант: однородные скаляры перемешанные с null

Иван (инкогнито)
27 октября 2014, 08:14

myarray = 0 1 2 null 3 null 4 5
в питоне это парсится в [0, 1, 2, None, 3, None, 4, 5] двумя строчками (свой метод в ConfigParser)

Евгений Степанищев (bolknote.ru)
27 октября 2014, 15:22, ответ предназначен Ивану

Я не хочу уже спорить. Мне не нравится идея не знать на уровне конфига что значат какие-то данные и придавать из значение внутри кода.

Николай (инкогнито)
14 января 2015, 17:39

json - сам по себе убогий костыль и одна их худших вещей, которые могли случиться. То же касается разнообразных ямлов и подобного. На фоне этой истории к xml претензий нет, он вполне.

bolknote.ru (bolknote.ru)
15 января 2015, 06:53, ответ предназначен Николаю

Можно ли услышать какие-то аргументы?

Ваше имя или адрес блога (можно OpenID):

Текст вашего комментария, не HTML:

Кому бы вы хотели ответить (или кликните на его аватару)