какие форматы данных вы знаете кроме json xml
Tree — убийца JSON, XML, YAML и иже с ними
Здравствуйте, меня зовут Дмитрий Карловский и я… много думал. Думал я о том, что не так с XML и почему его в последнее время променяли, на бестолковый JSON. Результатом этих измышлений стал новый стандарт формат данных, который вобрал в себя гибкость XML, простоту JSON и наглядность YAML.
Tree — двумерный бинарно-безопасный формат представления структурированных данных. Легко читаемый как человеком так и компьютером. Простой, компактный, быстрый, выразительный и расширяемый. Сравнивая его с другими популярными форматами, можно составить следующую сравнительную таблицу:
Больше — лучше | JSON | XML | YAML | INI | Tree |
---|---|---|---|---|---|
Человекопонятность | 3 | 1 | 4 | 5 | 5 |
Удобство редактирования | 3 | 1 | 4 | 5 | 5 |
Произвольная иерархия | 3 | 3 | 3 | 1 | 5 |
Простота реализации | 3 | 2 | 1 | 5 | 5 |
Скорость парсинга/сериализации | 3 | 1 | 1 | 5 | 5 |
Размер в сериализованном виде | 3 | 1 | 4 | 5 | 5 |
Поддержка поточной обработки | 0 | 0 | 5 | 5 | 5 |
Бинарная безопасность | 3 | 0 | 0 | 0 | 5 |
Распространённость | 5 | 5 | 3 | 3 | 0 |
Поддержка редакторами | 5 | 5 | 3 | 5 | 1 |
Поддержка языками программирования | 5 | 5 | 3 | 5 | 1 |
Сравнение форматов
Человекопонятность
JSON и XML позволяют произвольно форматировать вывод пробелами и переносами строк. Однако, часто по различным причинам (основные — меньший объём, проще реализация) их форматируют в одну строку и тогда они становятся крайне не читаемыми.
Кроме того, JSON не поддерживает многострочные тексты — они всегда представляются в виде одной строки, со специальной escape-последовательностью вместо переводов строк.
С другой стороны, XML позволяет внедрять свои тэги внутрь текста, что наглядно для простой разметки типа «выделение жирным», но сложная разметка типа «гиперссылка» даёт резко противоположный эффект.
Если текст содержит «специальные символы», то их приходится экранировать escape-последовательностями. В XML эти последовательности особенно громоздки и ненаглядны. А вот в Tree, наоборот, экранирование не требуется вовсе.
Удобство редактирования
JSON и XML довольно неудобно редактировать без специальных редакторов, понимающих их синтаксис. Как минимум необходима разноцветная подсветка лексем. Очень помогает — автоформатирование, автодополнение и подсветка ошибок. К сожалению, экранировать спецсимволы приходится вручную во всех форматах, кроме Tree, где оно не требуется.
Произвольная иерархия
INI имеет жёстко ограниченную глубину иерархии.
В XML произвольные дочерние узлы могут быть только у элементов — это вынуждает использовать их вместо, например, аттрибутов, для большей гибкости и единообразия.
JSON и YAML для создания иерархий предлагают «списки» и «мапки». Не все структуры данных хорошо представимы с их помощью. Например, различные AST, где имена узлов могут повторяться и порядок следования которых важен.
В Tree есть только один тип узлов и любой узел может содержать произвольные дочерние. Как следствие, он не накладывает никаких ограничений на иерархию.
Простота реализации
Довольно простая грамматика (30 паттернов), чем и обусловлено большое число реализаций под разные языки.
Довольно сложная грамматика (90 паттернов), которая могла бы быть куда проще, если бы не требование совместимости с sgml.
Крайне сложная грамматика (210 паттернов). Нужно быть очень терпеливым человеком, чтобы реализовать все нюансы, и потратить много человекочасов, чтобы избавиться ото всех багов.
Крайне простая грамматика (8 паттернов), позволяющая описывать лишь одну, довольно простую структуру (ключ-ключ-значение).
Очень простая грамматика (10 паттернов), что, однако, не мешает описывать с его помощью произвольные иерархические структуры.
Скорость парсинга/сериализации
Не вдаваясь в сравнение скорости работы конкретных имплементаций, оценим теоретические пределы скоростей работы с разными формтами.
Предельная скорость обработки данных зависит от сложности синтаксиса. Именно поэтому YAML парсится на порядок дольше, чем JSON, а XML по скорости где-то между ними.
Tree помимо простой грамматики имеет ещё одно существенное преимущество — отсутствие необходимости в экранировании и разэкранировании спецсимволов.
Размер в сериализованном виде
Как видно, существенно больше всех места занимает XML, даже если его минифицировать. JSON в читабельном виде и YAML где-то по середине. А самые компактные — INI, Tree и минифицированный в одну строку JSON.
Поддержка поточной обработки
Поддерживающие поточную обработку форматы, позволяют добавлять данные в файл, просто подклеивая их в конец. Яркий пример — различные логи. И наоборот — нормально распарсить данные, имея лишь некоторое число начальных строк.
В случае XML и JSON такой возможности нет — документ с обрезанным концом или дополнительными данными в конце, является невалидным.
Бинарная безопасность
Почти все текстовые форматы не совместимы с бинарными данными. Именно поэтому Tree — на самом деле не текстовый формат, хотя его и можно редактировать в текстовом редакторе при соблюдении некоторых ограничений (использовать только unix-переводы строк, табуляцию для отступов, и не использовать произвольные бинарные данные).
Распространённость
XML довольно продолжительное время был в тренде, так что нашёл применение во множестве мест. Сейчас уверенными темпами популярность набирает JSON, благодаря своей простоте, но ценой некоторой потери гибкости. INI за счёт своей ограниченности применялся лишь для различных конфигов, но сейчас замещается более гибкими форматами. YAML остаётся довольно нишевым форматом ввиду своей переусложнённости, хотя и снискал некоторую популярность у любителей «писать меньше, делать больше, а потом хоть трава не расти». Tree пока ещё вначале пути и надеюсь не в конце.
Поддержка редакторами
XML и JSON благодаря своей популярности поддерживаются везде. Над поддержкой YAML многие разработчики редакторов просто не видят целесообразности заморачиваться. INI настолько прост, что для него никакой особой поддержки и не нужно. С Tree в принципе та же картина, но есть один плагин к IDEA о котором будет рассказано далее.
Поддержка языками программирования
Тут в целом та же ситуация, что и с поддержкой редакторами. Разве что для Tree есть две реализации — на языках D и TypeScript/JavaScript.
Подробнее о Tree
Уровни представления
• Уровень формата. Определяет базовую модель данных и представление её в сериализованном виде.
• Уровень языка. Определяет семантику узлов и представление их в отличных от Tree форматах.
• Уровень приложения. Определяет API для взаимодействия с моделью данных Tree.
Модель данных
Модель Tree крайне проста — есть только один тип узлов, и каждый узел имеет: имя, значение, список дочерних узлов. Имя и значение являются взаимоисключающими, так что условно все узлы можно разделить на 3 типа:
• Имена — узлы с непустым именем и пустым значением. Используются для именования поддеревьев. В имени не может быть пробельных символов, символа перевода строки и символа равенства.
• Значения — узлы с пустым именем. Используются для хранения значений. Единственное ограничение на значения — они не могут содержать символ перевода строки.
• Коллекции — узлы с пустым именем и значением, но не пустым списком дочерних узлов. Используются для работы со списком узлов как с одним узлом. В результате парсинга возвращается именно коллекция, содержащая список корневых узлов.
В Tree нет комментариев или инструкций процессору, знакомых нам из XML. Нет списков или мапок из JSON и YAML. Нет специального синтаксиса для секций, как в INI. Однако они и не только они могут быть введены в языках, основанных на формате Tree.
Строковое представление
Tree-файл состоит из набора строк, разделённых символом перевода строки (0x0D). Каждая строка начинается с некоторого количества символов табуляции, показывающих какой из предков является родителем первого узла в строке. И далее идёт список узлов разделённых пробелами. Каждый следующий при парсинге вкладывается в предыдущий. Узлы-имена представляются просто своим именем. Узлы-значения – значением, предварёнными символом равенства.
В одной строке может быть произвольное число узлов-имён, но узел-значение может быть только один, причём самым последним. Значение может содержать абсолютно любые символы за исключением символа перевода строки. Когда нужно поместить произвольные бинарные данные – их предварительно надо разбить по символу перевода строки на несколько узлов-значений. А при приведении дерева к строке именованные узлы будут отброшены, а данные из узлов-значений будут выведены как есть и между ними будут вставлены переводы строк.
Наличие табуляции в строке означает, что первый узел в этой строке должен быть вложен в последний узел последней строки имеющей табуляцию на один меньше.
По сухому описанию довольно сложно ухватить суть, так, что далее будет множество наглядных иллюстраций…
Примеры применения Tree в разных областях
Контекстно свободные грамматики
Хоть формат Tree и не является контекстно свободным, но разбить на лексемы его можно по сравнительно не сложной контекстно свободной грамматике, которую можно выразить тоже в формате Tree:
Описание грамматики состоит из списка слов, для каждого из которых внутри задан соответствующий ему шаблон.
Предикат эквивалентности. Обозначает, что родительский узел может быть заменён на последовательность дочерних шаблонов.
Данное выражение определяет STATEMENT как последовательность из некоторого «выражения», за которым следует символ «точка с запятой».
octet
Совпадает с одним октетом (8 бит) с указанным внутри шестнадцатиричным значением.
Тут мы определяем SEMICOLON как октет с заданным значением. Если значение опущено, то такой шаблон совпадает с любым значением.
optional
Допускает отсутствие дочернего шаблона.
Совпадает либо с двумя байтами: возвращения каретки после которого идёт перевода строки. Либо с одним переводом строки.
any-of
Сопоставится с одним и только одним из дочерних шаблонов.
list-of
Позволяет последовательно повторить дочерний шаблон произвольное число раз (но как минимум одно совпадение должно быть).
Тут DELIMITER совпадёт с не пустой последовательной группой пробелов.
except
Служит для исключения дочернего шаблона из родительского. Это значит, что родительский шаблон будет сопоставлен лишь с таким набором байт, с которым не может быть сопоставлен дочерний.
Тут мы определяем EXPRESSION как произвольное число байт ни один из которых не является «точкой с запятой».
А этот шаблон уже совпадёт с произвольным набором байт (в том числе содержащего «точку с запятой»), но только не с одиночной «точкой с запятой».
with-delimiter
Указывает, что совпадения сестринских шаблонов должны быть разделены дочерним шаблоном.
Здесь SCRIPT определён как набор выражений, разделённых заданным символом.
Лог доступа к веб-серверу
Расширяемый структурированный формат логов. Может показаться громоздким, зато очень быстро и точно парсится как человеком так и машиной.
Поток сообщений от сервера в чате
Специальный разделитель «—» говорит клиенту о том, что завершилась пересылка очередной порции данных и можно приступать к её обработке.
Вёрстка статической веб-страницы
Специальный DSL на базе Tree позволяет лаконично описывать XML любой сложности. Трансформер из xml.tree в xml понимает специальные узлы «@», «!» и «?» формируя атрибуты, комментарии и инструкции процессору.
Структурные узлы соответствующие QName – элементы. Узлы данных – текстовые узлы.
Атрибуты представляются как узлы с QName именем, помещённые в узлы с именем «@».
Двоичное кодирование вместо JSON
Почему меня это должно волновать
Типы форматов кодирования
Существует два типа форматов кодирования:
Текстовые форматы
Текстовые форматы в некоторой степени человекочитаемы. Примеры распространенных форматов — JSON, CSV и XML. Текстовые форматы просты в использовании и понимании, но имеют определенные проблемы:
JSON-кодировка этого примера после удаления всех символов пробела занимает 82 байта.
Двоичное кодирование
Для анализа данных, которые используются только внутри организации, вы можете выбрать более компактный или более быстрый формат. Несмотря на то, что JSON менее многословен, чем XML, оба они все равно занимают много места по сравнению с двоичными форматами. В этой статье мы обсудим три различных бинарных формата кодирования:
Thrift и Protocol Buffers
Thrift разработан Facebook, а Protocol Buffers – Google. В обоих случаях для кодирования данных требуется схема. В Thrift схема определяется с помощью собственного языка определения интерфейса (IDL).
Эквивалентная схема для Protocol Buffers:
Как видите, у каждого поля имеется тип данных и номер тега (1, 2 и 3). У Thrift есть два различных формата двоичной кодировки: BinaryProtocol и CompactProtocol. Двоичный формат прост, как показано ниже, и занимает 59 байт для кодирования данных, приведенных выше.
Кодирование с использованием двоичного протокола Thrift
Компактный протокол семантически эквивалентен бинарному, но упаковывает одну и ту же информацию всего в 34 байта. Экономия достигается за счет упаковки типа поля и номера метки в один байт.
Кодирование с использованием протокола Thrift Compact
Protocol Buffers кодирует данные аналогично компактному протоколу в Thrift, и после кодирования эти же данные занимают 33 байта.
Кодирование с использованием Protocol Buffers
Номера тегов обеспечивают эволюцию схем в Thrift и Protocol Buffers. Если старый код попытается прочитать данные, записанные с новой схемой, он просто проигнорирует поля с новыми номерами тегов. Аналогично, новый код может прочитать данные, записанные по старой схеме, пометив значения как null для пропущенных номеров тегов.
Avro отличается от Protocol Buffers и Thrift. Avro также использует схему для определения данных. Схему можно определить, используя IDL Avro (человекочитаемый формат):
Или JSON (более машиночитаемый формат):
Обратите внимание, что у полей нет номеров меток. Те же самые данные, закодированные с помощью Avro, занимают всего 32 байта.
Кодирование с помощью Avro.
Как видно из вышеприведенной последовательности байт, поля не могут быть идентифицированы (в Thrift и Protocol Buffers для этого используются метки с номерами), также невозможно определить тип данных поля. Значения просто собираются воедино. Означает ли это, что любое изменение схемы при декодировании будет генерировать некорректные данные? Ключевая идея Avro заключается в том, что схема для записи и чтения не обязательно должна быть одинаковой, но должна быть совместимой. Когда данные декодируются, библиотека Avro решает эту проблему, просматривая обе схемы и транслируя данные из схемы записывающего устройства в схему читающего устройства.
Устранение различий между схемой читающего и записывающего устройства
Вы, наверное, думаете о том, как читающее устройство узнает о схеме пишущего. Все дело в сценарии использования кодировки.
Заключение
В этой статье мы рассмотрели текстовые и двоичные форматы кодирования, обсудили как одни и те же данные могут занимать 82 байта с кодировкой JSON, 33 байта с кодировкой Thrift и Protocol Buffers, и всего 32 байта с помощью кодировки Avro. Двоичные форматы предлагают несколько неоспоримых преимуществ по сравнению с JSON при передаче данных в сети между внутренними службами.
Ресурсы
Чтобы узнать больше о кодировках и проектировании приложений c интенсивной обработкой данных, я настоятельно рекомендую прочитать книгу Мартина Клеппмана «Designing Data-Intensive Applications».
Узнайте подробности, как получить востребованную профессию с нуля или Level Up по навыкам и зарплате, пройдя платные онлайн-курсы SkillFactory:
Языки разметки. XML и альтернативные форматы
XML – одна из самых широко используемых в современном интернете технологий работы с данными. Однако в чём именно она заключается, в состоянии сказать лишь немногие пользователи Глобальной сети. Давайте попробуем вместе разобраться в XML и альтернативных ему форматах.
Что такое XML?
XML – это eXtensible Markup Language, что в переводе значит «расширенный язык разметки». Фактически, это способ записи данных в структурированном виде, который будет читаем для пользователя, но при этом удобен для обработки программному обеспечению. Вот пример данных в виде XML:
Содержимое XML-документа можно представить в виде древовидной структуры данных. При этом стандарт XML требует, чтобы у этого дерева был «ствол» ‑ корневой элемент, который будет содержать внутри себя все остальные, и такой корневой элемент должен быть единственным. Как и в HTML-разметке, специальные символы (амперсанд «&», знаки неравенства, кавычки и апостроф) должны быть записаны в виде специальных символьных комбинаций, которые называются предопределёнными сущностями. Аналогично можно вставлять ссылки на сущности – это символическая замена какой-либо сущности (то есть комбинации символов) выражением вида «&имя_сущности;» (без кавычек в документе). При этом ссылка может быть на предопределённую сущность или на какую-то сущность, хранящуюся в DTD-документе.
Что такое DTD?
DTD (англ. Document Type Definition – описание типа документа) – документ, в котором описывается структура XML-документа. Описание документа при помощи DTD выглядит примерно следующим образом:
Здесь мы видим следующую картину: корневой элемент – это list, а элементы, содержащиеся внутри него – это item. Значок «*» означает, что этих элементов может быть любое число, от 0 до практически бесконечности. Каждый элемент item содержит в себе элементы par1 и par2, причём значок вопроса означает, что присутствие par2 не является обязательным.
В последнее время формат описания структуры DTD всё больше меняется на XML Schema. Оба эти формата описывают, какие элементы должен содержать в себе XML-документ, какими атрибутами могут обладать эти самые элементы и какого типа должны быть значения атрибутов и элементов. Синтаксисы DTD и Schema существенно отличаются. С помощью Schema то же самое можно записать следующим образом:
Как видите, описание документа при помощи Schema больше похоже на саму XML-разметку (собственно, если присмотреться, это именно она и есть).
JSON – первая альтернатива XML
Несмотря на то, что XML – очень распространённый способ записи данных, он не является единственным и неповторимым в своём роде. Одна из альтернативных текстовых форм записи данных называется JSON. Расшифровывается эта аббревиатура как JavaScript Object Notation – что-то вроде «запись объектов с помощью JavaScript». Стоит отметить, что для пользователя этот формат, на мой взгляд, удобнее, чем XML. Для того, чтобы это утверждение не выглядело голословным, приведу пример данных в JSON-представлении:
Пользователю гораздо проще, как говорится, отделить зёрна от плевел, чем в случае с XML, поскольку нет открывающих и закрывающих тегов. Это, кстати, приводит и к тому, что на больших объёмах данных экономится память, которую эти теги занимают. Программистам будет приятно узнать, что JSON лучше, чем XML, подходит и для использования в AJAX. Основное его преимущество – в простоте обработки JSON-данных на стороне клиента.
Вторая альтернатива: YAML
YAML – это рекурсивная аббревиатура, которая расшифровывается как «YAML Ain’t Markup Language» (по-русски это будет звучать как «YAML не является языком разметки»). Чем он при этом является, правда, его создатели уточнять не берутся, но, пожалуй, определение «язык разметки» будет всё-таки довольно подходящим. Чем YAML отличается от XML? Компактностью представления данных и удобством их редактирования для человека. Вот как выглядят данные, записанные с помощью YAML:
YAML-разметка в больших документах больше подходит для их ручного редактирования, поскольку здесь теги не загромождают смысловую часть документа. Сейчас YAML применяется активно в некоторых инструментах программирования, но в целом эта технология ещё довольно молода, а потому не слишком распространена.
Зачем нужны XML, JSON, YAML?
XML и альтернативные форматы в последнее время начинают использоваться всё более активно по всему миру. И на то есть множество объективных причин. Одной из главных специалисты обычно называют доступность этих форматов для чтения как человеком, так и компьютером. Сейчас в мире существует великое множество инструментов для работы с XML, которые могут применять как программисты, так и конечные пользователи программного обеспечения.
Также большим плюсом XML и прочих подобных форматов является то, что они позволяют описывать данные практически любой структуры и сложности, поскольку данные представляются в древовидной форме. К тому же, поскольку любые данные в них – это просто текст, то и работать с ними можно как с текстом: кодировать, набирать XML-документы в блокноте, а в случае потери части данных остальные будут по-прежнему читабельны. Кроме того, текст можно использовать на любой платформе.
Что касается XML, то очень широкое применение этот стандарт нашёл во Всемирной паутине. На базе XML разработана технология XSL, с помощью которой XML-документы преобразуются специальным образом, в соответствии со стандартами и правилами, в HTML-документы, которые уже можно отображать в браузере. Хотя на самом деле суть технологии XSL значительно шире, и её можно применять для преобразования XML-документа в практически любой формат. JSON и YAML используются пока что реже, но у этих технологий большой потенциал, связанный с развитием Web 2.0, и в интернете можно найти всё больше мест, где они также применяются.