JSON, YAML и TOML: почему одинаковые данные ведут себя по-разному

Строка country: NO выглядит настолько очевидно, что от неё трудно ожидать сюрприза. Однако старый YAML-парсер мог прочитать NO как логическое false, тогда как JSON потребовал бы кавычки, а TOML однозначно отличил бы строку от булева значения. Причина не в одном неудачном синтаксическом решении: у этих форматов разные модели данных, цели и правила определения типов. Поэтому выбор между ними начинается не с вопроса о красоте записи, а с того, кто будет создавать файл, какая программа станет его читать и допустима ли неоднозначность при обмене.
JSON отделил данные от выполняемого кода
JSON вырос из литералов объектов JavaScript, но у него нет единственного момента изобретения. Дуглас Крокфорд вспоминал, что несколько разработчиков независимо использовали эту запись для передачи данных, а сам он пришёл к такому решению в State Software в апреле 2001 года. В 2002 году Крокфорд зарегистрировал json.org и начал описывать формат как самостоятельную, не зависящую от языка запись. Затем появились RFC 4627 в 2006 году, стандарт ECMA-404 в 2013-м и действующий RFC 8259 в 2017-м.
Сила JSON состоит в небольшой и предсказуемой модели. Значение может быть строкой, числом, логическим значением, null, массивом или объектом со строковыми именами полей. Эта модель легко переносится между языками, поэтому JSON удобен для API, журналов событий и данных, которые в основном создаёт и обрабатывает программа.
Минимализм одновременно задаёт границы. В грамматике JSON нет комментариев и отдельного типа даты, а большие числа могут потерять точность в системах, которые представляют их обычным 64-битным floating-point значением. Стандарт также рекомендует уникальные имена полей: при дубликатах один парсер может оставить последнее значение, другой сообщить об ошибке, а третий сохранить все пары. Таким образом, короткая грамматика не отменяет требования договориться о смысле данных поверх неё.
YAML выбрал удобство записи и получил несколько способов прочитать скаляр
YAML впервые предложил Кларк Эванс в 2001 году, а проектировал формат он вместе с Инги дёт Нетом и Ореном Бен-Кики. Ранний черновик спецификации расшифровывал название как Yet Another Markup Language, но современное рекурсивное имя YAML Ain't Markup Language подчёркивает, что это язык сериализации данных, а не разметка документа. История авторства и нынешнее значение названия зафиксированы на официальной странице YAML.
Формат задумывался для чтения и редактирования человеком. Отступы выражают вложенность, комментарии объясняют настройки, блоковые скаляры хранят многострочный текст, а якоря и ссылки позволяют повторно использовать узлы. Эти возможности особенно удобны в больших конфигурациях, но они делают YAML существенно шире обычной пары «ключ и значение».
Именно из системы типов появилась Norway Problem. Схема YAML 1.1 считала логическими значениями не только true и false, но также разные варианты yes, no, on и off. Поэтому такой документ мог изменить смысл без явной ошибки:
country: NO
maintenance: ON
При схеме YAML 1.1 значения могли превратиться в false и true. В Core Schema YAML 1.2 логическими считаются только варианты true и false, поэтому NO и ON остаются строками. Однако номер стандарта сам по себе не гарантирует результат: библиотека может поддерживать старую версию, другую схему или собственные расширения. Если значение должно оставаться строкой во всех окружениях, кавычки сообщают это прямо:
country: "NO"
maintenance: "ON"
Проблема здесь не доказывает, что YAML плох. Она показывает цену неявного определения типов и объясняет, почему версию парсера нужно считать частью конфигурационного контракта.
TOML сделал конфигурацию своей основной задачей
Том Престон-Вернер начал TOML в 2013 году как формат с очевидной семантикой, который однозначно отображается в хеш-таблицу. Вместо значимой иерархии отступов он использует присваивания key = value, таблицы [server] и массивы таблиц [[products]]. Строки заключаются в кавычки, логические значения записываются только как true или false, а даты и время имеют собственные типы. Полная версия 1.0 закрепила эти правила в официальной спецификации TOML.
Такая явность хорошо подходит для настроек приложения или пакета, которые регулярно правит человек. Она же ограничивает область применения. Корнем TOML всегда служит таблица, значения null не существует, а граф с общими узлами, который можно представить ссылками YAML, в эту модель не помещается напрямую. TOML поэтому не является «исправленным YAML» или более новым JSON; он решает более узкую задачу конфигурации.
Формат выбирают по пути данных
Для сетевого обмена и машинной генерации JSON обычно остаётся самым простым контрактом: его модель невелика, а совместимые реализации доступны почти везде. Если конфигурацию часто редактируют люди и ей нужны комментарии, многострочный текст или повторное использование фрагментов, YAML может быть удобнее при условии, что команда контролирует парсер и договорилась о схеме. TOML хорошо работает там, где документ естественно раскладывается на именованные таблицы и важны явные типы.
Файлы .env и строки shell export находятся ещё ближе к границе запуска процесса. Переменная окружения в итоге является строкой, поэтому вложенные объекты, массивы, числа, логические значения и null приходится кодировать соглашениями. Единого формата, который гарантированно восстановит такую структуру во всех dotenv-библиотеках, нет. По этой причине перевод между форматами следует рассматривать как преобразование моделей данных, а не как косметическую замену скобок отступами.
Что именно делает конвертер
Конвертер YAML, JSON, TOML и .env работает с пятью представлениями: JSON, YAML, TOML, .env и строками shell export. Исходный текст сначала разбирается в обычное значение JavaScript, а затем сериализуется в выбранный формат. Этот промежуточный слой позволяет переводить распространённые конфигурации в любом направлении, но не сохраняет особенности, которых нет в модели JavaScript, например комментарии, YAML-якоря или отдельный TOML-тип даты.
JSON обрабатывается нативными JSON.parse и JSON.stringify. Для YAML и TOML инструмент использует практические подмножества синтаксиса, а не пытается заменить полноценные стандартные парсеры. YAML-ветка понимает обычные карты, последовательности и скаляры, намеренно распознаёт булевыми только true и false и сохраняет NO, YES, ON и OFF строками. Сложные теги, якоря, merge keys, блоковые скаляры и несколько документов нужно обрабатывать специализированной библиотекой. Для YAML-вывода лучше выбирать два или четыре пробела, поскольку табуляция в отступах YAML недопустима.
TOML-ветка поддерживает таблицы, массивы таблиц, строки, числа, даты и распространённые составные значения, но при переходе через JavaScript дата становится строкой. В TOML также нельзя записать null, поэтому конвертер оставляет поясняющий комментарий или сообщает о замене в составном значении вместо того, чтобы скрыть потерю. Документ с массивом или скаляром в корне тоже нельзя сериализовать как TOML, потому что его корнем должна быть таблица.
При переводе в .env или shell вложенность разворачивается в имена вида DATABASE__HOST, а элементы массивов получают числовые сегменты. Обратное преобразование понимает это же соглашение, но все конечные значения остаются строками. Автоопределение исходного формата является эвристикой, особенно когда короткая запись одновременно похожа на TOML и .env, поэтому формат можно выбрать вручную.
Все преобразования выполняются локально в браузере. Инструмент показывает замечания о переименованных ключах и потерях типов, позволяет поменять направление одной кнопкой и скопировать результат, но для производственной миграции всё равно нужно прогнать итоговый файл через тот же парсер и схему, которые использует целевое приложение.
Похожие инструменты
Частые вопросы
Кто создал JSON?
JSON вырос из объектной записи JavaScript, и похожий способ обмена данными независимо находили разные разработчики. Дуглас Крокфорд вспоминал, что пришёл к нему в State Software в апреле 2001 года, а в 2002 году зарегистрировал json.org и занялся описанием формата. Первая спецификация IETF появилась как RFC 4627 в 2006 году; действующий Internet Standard RFC 8259 опубликован в 2017 году.
Что такое Norway Problem в YAML?
В схеме типов YAML 1.1 не заключённые в кавычки NO, YES, ON и OFF распознавались как логические значения. Поэтому country: NO могло превратиться в false. В Core Schema YAML 1.2 логическими значениями считаются варианты true и false, но реальное поведение всё равно зависит от версии и схемы конкретного парсера.
Чем отличаются JSON, YAML и TOML?
JSON является компактным форматом обмена данными с небольшим набором типов. YAML предлагает удобную для человека запись, комментарии, многострочные значения, якоря и другие возможности, но его результат зависит от выбранной схемы. TOML предназначен прежде всего для конфигурации и однозначно отображается в таблицы с типизированными значениями.
Может ли TOML выразить любой документ JSON или YAML?
Нет. Корнем TOML всегда является таблица, в формате нет null, зато есть отдельные типы даты и времени. YAML также умеет описывать графы через якоря и ссылки, а его модель данных шире обычного объекта JavaScript. Поэтому некоторые документы нельзя перевести в TOML или JSON без потери типа, структуры либо смысла.
Почему один и тот же YAML разные программы читают по-разному?
На интерпретацию некавыченных значений влияет версия YAML и выбранная схема типов, а библиотеки не всегда используют одинаковые настройки по умолчанию. Для переносимой конфигурации неоднозначные строки лучше заключать в кавычки и фиксировать версию парсера в проекте.
Можно ли конвертировать JSON или YAML в .env и обратно без потерь?
Не всегда. Переменные окружения являются строками и не хранят типы, вложенность или null. Этот конвертер разворачивает объекты в ключи с двойным подчёркиванием, а при обратном преобразовании собирает их обратно, но это соглашение самого инструмента, а не универсальный стандарт dotenv.
Поддерживает ли конвертер все возможности YAML и TOML?
Нет. Он рассчитан на распространённые конфигурации и поддерживает практические подмножества обоих форматов. Сложный YAML с тегами, якорями, merge keys или несколькими документами, а также редкие конструкции TOML следует проверять специализированным парсером и валидатором проекта.
Автор
Alex RelFullstack Engineer
В коммерческой разработке с 2011 года — больше 15 лет. Автор двух SaaS-продуктов: TeleGo.io и LingvoHabit.com. Статьи здесь выросли из реальной клиентской и продуктовой работы.



