Конвертер JSON в YAML
Переводит JSON в YAML и объясняет каждые добавленные кавычки — строки, которые без них молча стали бы логическим значением, числом или датой.
name: deploy
country: 'NO'
startsAt: '12:30'
mode: '0755'
version: '1.10'
released: '2024-01-30'
enabled: 'yes'
script: |-
set -e
npm run build
npm test
replicas: 3
tags:
- web
- edge
Значений в кавычках: 6. Нужны только в YAML 1.1: 4. Переключите схему выше, чтобы увидеть разницу.
countryтолько 1.1«NO» прочиталось бы как логическое false.
startsAtтолько 1.1«12:30» прочиталось бы по основанию 60 как 750.
modeУ «0755» ведущий ноль, поэтому оно прочиталось бы как число 493.
version«1.10» прочиталось бы как число 1.1.
releasedтолько 1.1«2024-01-30» прочиталось бы как дата, а не как текст.
enabledтолько 1.1«yes» прочиталось бы как логическое true.
Что делает этот инструмент
Он переводит документ JSON в YAML, а затем говорит, почему каждая строка оказалась в кавычках. Эта вторая часть и есть причина существования инструмента: любой другой конвертер отдаёт результат и оставляет вам обнаружить позже, что одно из ваших значений больше не строка.
Преобразование идёт в одну сторону. Читать YAML — задача куда большая, чем писать его, а отчасти верный разборщик YAML хуже, чем никакой: он принимает ваш файл и без жалоб возвращает неверные данные. Вывод — задача ограниченная, и именно это направление здесь покрыто.
Почему конвертеру вообще нужны мнения
JSON говорит, какого типа всё. У строки есть кавычки, у числа нет, и третьей возможности не существует. YAML же определяет тип некавыченного значения по его виду: совпало с образцом логического — значит логическое, совпало с числом — значит число, и лишь если не совпало ни с чем, остаётся текстом.
Именно это делает YAML приятным для письма от руки и превращает преобразование в вопрос суждения. Каждую строку на входе приходится сверять с каждым образцом, который YAML разрешает, и заключать в кавычки при совпадении. Ошибётесь в осторожную сторону — вывод шумный; ошибётесь в другую — значение молча меняет тип.
Норвежская проблема и её родня
Самый известный случай — список кодов стран. Норвегия — это NO, а в YAML 1.1 некавыченный токен NO есть логическое false. Файл настроек, перечисляющий страны, теряет Норвегию и приобретает false, и нигде ничто не сообщает об ошибке.
Это не одно странное правило, а целое семейство. YAML 1.1 читает y, Y, yes, no, on и off как логические значения в любом написании, и тем ловит химический символ, положение переключателя и ответ на вопрос. А числовые разрешители ещё чуднее:
- 12:30 — это 750. YAML 1.1 читает разделённые двоеточиями цифры по основанию 60, так что время суток или длительность становятся целым числом.
- 0755 — это 493. Ведущий ноль означает восьмеричное в YAML 1.1, а в YAML 1.2 тот же текст — десятичное 755: версии расходятся в том, какое число, а не в том, число ли это.
- 1.10 — это 1.1. Двухчастный номер версии есть число с плавающей точкой, и завершающий ноль исчезает. Зависимость, прикреплённая к 1.10, теперь указывает на 1.1.
- 2024-01-30 — объект даты, а не строка, потому что у YAML 1.1 есть тип метки времени.
- Пустая строка — это null, как и голые слова null, Null, NULL и тильда.
Ничто из этого не ошибка YAML. Это разрешители делают ровно то, что обещают, над текстом, который случайно совпал. Единственная защита — заключать в кавычки всё совпадающее, что этот инструмент и делает, а панель находок отчитывается за это построчно.
Две версии, и почему по умолчанию старшая
YAML 1.2 вышел в 2009 году и убрал большинство неожиданных разрешителей. Его базовая схема оставляет логическими только true и false, полностью отказывается от основания 60 и не имеет типа метки времени. Под 1.2 NO, 12:30 и 2024-01-30 — просто строки.
Загвоздка в том, что именно читает ваш файл. PyYAML реализует YAML 1.1, а PyYAML стоит за огромным количеством инструментов — Ansible, старые клиенты Kubernetes, бесчисленные сценарии. Go’шный yaml.v3 и нынешний js-yaml следуют 1.2. Так что один и тот же документ читается двумя разными способами в зависимости от того, кто его открыл, и единственный безопасный везде вывод — закавыченный под 1.1.
Это и есть здешнее умолчание. Переключение на 1.2 ничего не прячет: вывод строится заново с новыми разрешителями, а панель находок сокращается, так что видно в точности, какие кавычки стояли ради старой схемы. Оставшиеся нужны любому разборщику.
Строки, ломающие синтаксис, а не тип
Вторую группу строк приходится закавычивать по другой причине: не потому что YAML прочёл бы их как иной тип, а потому что они вовсе не разобрались бы как текст.
- Двоеточие с последующим пробелом заканчивает ключ. «note: time: now» прочиталось бы как ключ note, значением которого является ключ time.
- Пробел с последующей решёткой открывает комментарий, и всё, что за ним, исчезает.
- Начальные -, ?, :, [, ], {, }, #, &, *, !, |, >, %, @ или обратный апостроф — символы-индикаторы и означают нечто структурное.
- Ведущий или замыкающий пробел некавыченное значение не сохраняет, поэтому « x » возвращается как «x».
- Табуляция где угодно внутри значения отвергается начисто: PyYAML отказывает всему документу вместо того, чтобы прочесть его неверно, так что этот случай падает громко.
Одинарные кавычки используются везде, где их хватает: у них ровно одно правило экранирования — апостроф пишется дважды — и читаются они лучше, чем обратно-слэшевые экранирования, которые приносят двойные. Двойные оставлены тому, что действительно требует экранирования: управляющим символам, табуляциям и многострочным строкам, которым блок недоступен.
Многострочные строки и указатель обрезки
Строка с переводами строки — сценарий, сертификат, кусок прозы — обычно и есть причина, по которой YAML вообще понадобился. JSON способен записать её лишь экранированиями обратный-слэш-n в одной очень длинной строке; у YAML есть литеральный блочный скаляр, открываемый вертикальной чертой, под которой текст стоит с отступом и читаемо.
Тонкость в том, что происходит с завершающими переводами строки, и этим управляет указатель обрезки:
- Голая вертикальная черта подрезает: сколько бы завершающих переводов у блока ни было, значение получает ровно один.
- Вертикальная черта с минусом срезает: значение не получает ни одного.
- Вертикальная черта с плюсом сохраняет: значение получает их все.
Этот инструмент выбирает указатель по той строке, которую получил, так что значение переживает путь туда и обратно в точности. Знать об этом стоит потому, что умолчание — голая черта — это то, что пишут от руки, и оно молча нормализует строку, оканчивавшуюся двумя переводами или ни одним.
Блочный скаляр вмещает не всё, и там, где не вмещает, вывод откатывается к двойным кавычкам, а панель находок объясняет почему. Возврат каретки не выживает, потому что блочные скаляры нормализуют переводы строк. Первая строка, начинающаяся с пробела, была бы прочитана как лишний отступ и снята. А строка, оканчивающаяся пробелом, спецификацией сохраняется, но на экране невидима и большинством редакторов удаляется при сохранении, так что кавычки надёжнее — это решение, а не ограничение, и о нём сообщается именно так.
Больше одного документа
У YAML есть то, чего нет у JSON: файл может содержать поток документов, разделённых тремя дефисами. Это формат манифеста Kubernetes, и потому массив JSON так часто должен стать чем-то иным, нежели последовательность YAML.
Переключатель здесь выводит каждый элемент массива верхнего уровня отдельным документом. А когда ввод вовсе не одно значение JSON, но каждая строка разбирается сама по себе, он читается как NDJSON — построчный формат, в котором приходят журналы и выгрузки API, — и каждая строка становится документом. Такое прочтение есть догадка, поэтому о нём сообщается над выводом, а не делается молча.
Откат применяется лишь когда весь ввод не разбирается, а каждая строка разбирается, чего просто испорченный документ не сделает. Синтаксическая ошибка по-прежнему всплывает как синтаксическая ошибка, со строкой и столбцом, где произошла.
Чего преобразование сохранить не может
Две вещи теряются ещё до того, как инструмент увидит ваши данные, обе в самом разборе JSON, и стоит знать какие.
Повторяющиеся ключи. JSON позволяет объекту дважды перечислить один ключ, и большинство разборщиков молча оставляет последний. YAML запрещает дубликаты вовсе, так что вывод окажется корректным, но прежнее значение уже потеряно — и никакой конвертер не сообщит о том, чего никогда не получал.
Точность целых. Число JSON больше примерно девяти квадриллионов не переживает разбор в double, поэтому идентификатор вроде 12345678901234567890 возвращается округлённым. Это не беда YAML и не беда, вносимая этим инструментом; так происходит в любом разборщике JSON в языке. Если большой идентификатор важен, его место в строке по обе стороны.
Замечания о выводе
Отступ делается пробелами, всегда, потому что YAML запрещает табуляции для отступа полностью — это одна из немногих вещей, в которых формат строг. Два пробела — общепринято; четыре предлагаются потому, что некоторые внутренние стили их требуют.
Последовательности идут с отступом под своим ключом. И эта форма, и форма без отступа — корректный YAML и значат одно и то же; отступную пишет большинство людей, и её же правильно сворачивает большинство редакторов.
Пустой массив или объект записывается потоковым стилем парой скобок, потому что блочный стиль не имеет способа выразить пустоту: на следующих строках писать нечего.
Вывод завершается переводом строки, и это несёт функцию, а не аккуратность. Обрезка блочного скаляра отмеряется от следующего за ним перевода строки, поэтому подрезанный блок в самом конце файла без завершающего перевода теряет тот перевод, который должен был сохранить.
Манифесты Kubernetes и поля, которые обязаны остаться строками
Kubernetes читает манифест в любом из двух форматов. Его собственная документация называет YAML принятым обычаем и упоминает JSON как альтернативу, а kubectl переводит манифест в JSON, или в другое представление, которое поддерживает API, когда отправляет запрос, — так что дело не в том, что примет кластер. Дело в файле, который остаётся у вас: YAML читает рецензент, в YAML разборчивы различия в запросе на слияние, и только он из двух умеет нести комментарий. JSON обычно приходит из kubectl get -o json, из шаблона или из API, отдающего объекты.
- Один файл, несколько объектов. Манифесты можно собрать в один файл, разделив тремя дефисами, и документация прямо говорит, что они создаются в том порядке, в каком записаны, — поэтому Service обычно пишут выше того Deployment, который его наполняет. Переключатель, выводящий каждый элемент массива верхнего уровня отдельным документом, и превращает список объектов JSON в такой файл.
- Записи окружения контейнера — два строковых поля. Документация API объявляет и name, и value строками, поэтому значение JSON, равное "true", обязано выйти со своими кавычками: без них это логическое значение, а логическое значение не тот тип, который поле объявлено хранить.
- Порт контейнера объявлен целым числом, и он стоит в нескольких строках от тех строковых полей. Двум нужна противоположная обработка, и JSON уже несёт это различие: число становится обычным числом, а строка закавычивается только там, где YAML перестал бы читать её как строку.
- Метки и аннотации — отображения из строки в строку. Именно там проблема Норвегии попадает внутрь манифеста: метка со значением NO, on или off для разборщика YAML 1.1 логическое значение, а значение 1.10 — число с плавающей точкой, теряющее завершающий ноль.
Три записи окружения, заданные как JSON, где каждое значение — строка, преобразуются так:
env:
- name: DEBUG
value: 'true'
- name: REPLICAS
value: '3'
- name: COUNTRY
value: 'NO'Все три закавычены, и панель находок называет все три вместе со значением, которым каждая стала бы: true — логическое, 3 — число, а NO — логическое false. Зависит от версии только последняя: переведите схему на 1.2, и её кавычки уйдут, потому что 1.2 не читает NO ничем, кроме текста. Две другие сохраняют свои в обеих версиях.
Docker Compose, где документация самого формата предупреждает о YAML
Файл Compose — это YAML, и документация Docker для него несёт два предупреждения о разборе YAML. Документация продукта, называющая опасностью собственный формат сериализации, — вещь необычная, и оба предупреждения о том самом, для чего существует этот инструмент: о значении, задуманном как текст, которое разборщик читает иначе.
- Порты. Документация говорит, что отображение HOST:CONTAINER всегда следует давать закавыченной строкой, чтобы избежать конфликта с числом YAML по основанию 60. Без кавычек 22:22 — это целое 1342.
- Значения окружения. Документация просит заключать true, false, yes и no в кавычки, чтобы разборщик их не преобразовал. Два из четырёх — логические значения в обеих версиях YAML, а два, yes и no, только в 1.1, поэтому панель находок помечает их по-разному.
- Правило основания 60 достаёт лишь до того отображения, где число после двоеточия меньше шестидесяти, потому что таков охват одной цифры по основанию 60. Поэтому 22:22 здесь закавычено, а 8080:80 оставлено как есть, и разница — это правило, а не суждение о том, какие порты важнее.
Служба, у которой порты и значения окружения в JSON все строки, преобразуется в это:
services:
proxy:
image: nginx
ports:
- '22:22'
- 8080:80
environment:
TLS_ENABLED: 'no'
DEBUG: 'true'Это и есть вывод, о котором просит документация, и производит его схема по умолчанию. Это же и самая ясная причина не трогать схему: перейдите на 1.2, и отображение порта и no потеряют кавычки, а true свои сохранит, потому что 1.2 отказался от основания 60 и оставил логическими только true и false. Разборщик, реализующий 1.2, прочтёт результат верно — но совет Docker написан без всякого такого условия, и следовать ему стоит две пары кавычек.
Частые вопросы
- Является ли JSON уже корректным YAML?
- Под YAML 1.2 — да: спецификация говорит об этом прямо, и разборщик 1.2 прочтёт файл JSON напрямую. На практике пользы немного, потому что причина преобразовывать — читаемость: комментарии, блочные скаляры, отсутствие фигурных скобок, — а вставка JSON в файл YAML не даёт ничего из этого. Под YAML 1.1 это не вполне верно, что ещё одна причина различать версии.
- Почему моей строке достались кавычки, которые ей будто бы не нужны?
- Почти наверняка нужны. YAML типизирует некавыченное значение сопоставлением образцов, так что NO, yes, off, 12:30, 0755, 1.10, 2024-01-30 и пустая строка — все перестают быть строками. Панель находок называет каждый случай и показывает значение, которым он стал бы, чтобы утверждение можно было проверить, а не принять на веру. Если вы целитесь в разборщик YAML 1.2, смена схемы уберёт те, что нужны только 1.1.
- В чём здесь разница между YAML 1.1 и 1.2?
- 1.2 отказался от разрешителей, вызывающих большинство неожиданностей: yes/no/on/off больше не логические, основание 60 исчезло, а типа метки времени нет. PyYAML реализует 1.1 и по-прежнему повсюду, поэтому осторожный вывод стоит по умолчанию; настройка 1.2 нужна тогда, когда вы знаете, что будет читать файл.
- Может ли он перевести YAML обратно в JSON?
- Нет, намеренно. Читателю YAML нужны якоря, псевдонимы, теги, ключи слияния, пять стилей скаляров и две версии схемы, а тонко ошибиться в любом из них — значит принять файл и вернуть данные, отличные от тех, что в нём были. Такой отказ беззвучен, и это делает его хуже, чем отсутствие возможности вовсе.
- Как получить многодокументный файл в духе Kubernetes?
- Включите переключатель, который выводит каждый элемент массива верхнего уровня отдельным документом, и массив станет документами, разделёнными тремя дефисами. Если же ваш ввод — NDJSON, по одному объекту JSON в строке, как часто приходят журналы и выгрузки API, это распознаётся само и сообщается над выводом.
- Почему в выводе нет комментариев?
- Потому что их не было во вводе. Комментарии — главное, что есть у YAML и нет у JSON, а конвертер не может их выдумать. Это стоит помнить и в обратную сторону: если прогнать файл YAML через JSON и назад, всякий комментарий в нём исчезнет.
- Отправляется ли что-нибудь из вставленного на сервер?
- Нет. Разбор и преобразование целиком выполняются в вашем браузере; ничто не загружается и не записывается, и всё работает без сети.
- Как преобразовать вывод kubectl в формате JSON в манифест YAML?
- Вставьте его и читайте YAML. Kubernetes принимает оба формата — его документация называет YAML обычаем, а JSON альтернативой, — так что причина преобразовывать в файле, который остаётся у вас, а не в том, что примет кластер. Проверять надо кавычки: манифест полон полей, которые API объявляет строками, среди них значения окружения и значения меток и аннотаций, и это как раз те, чей тип YAML иначе поменял бы. Если JSON — список из нескольких объектов, переключатель многодокументного вывода делает из него один файл.
- Почему Docker Compose хочет мои порты в кавычках?
- Потому что для разборщика YAML 1.1 22:22 не пара чисел, а одно число по основанию 60 — 1342. Документация Compose от Docker говорит, что отображение HOST:CONTAINER всегда должно быть закавыченной строкой именно по этой причине, и та же страница просит закавычивать true, false, yes и no в блоке окружения. И то и другое этот инструмент делает при схеме по умолчанию, а панель находок говорит, из какого правила взялись каждые кавычки. Отображение, где число после двоеточия шестьдесят или больше, как 8080:80, лежит вне правила основания 60 и оставляется как есть.
- Какую версию YAML выбрать для Kubernetes или Docker Compose?
- По умолчанию, 1.1. Всякие кавычки, которые она добавляет, принимает и разборщик 1.2, так что осторожный вывод безопасен в любом случае, а оба предупреждения в документации Compose — о правилах 1.1: отображения портов по основанию 60 и yes и no как логические значения. Настройка 1.2 нужна, чтобы показать, какие кавычки существуют только ради старой схемы; вывод их теряет, а это противоположно тому, о чём просят эти предупреждения.
Похожие инструменты
- JSON в TypeScript
Вывод интерфейсов TypeScript из образца JSON.
- Тестер JSONPath
Проверка запросов JSONPath (RFC 9535) к JSON.
- Генератор таблиц Markdown
Создание и выравнивание таблиц Markdown из CSV, TSV или JSON.
- Слияние PDF
Объедините несколько PDF в один файл в своём порядке — ничего не загружается.