Конвертер XML в JSON и обратно

Преобразовать XML в JSON и JSON в XML: атрибуты отдельным ключом, повторяющиеся элементы как массив, текстовые узлы и сохранение вложенности. Выбор способа записи атрибутов и значений, имя корневого элемента. Всё считается в браузере.

Настройки

Разобрать XML и записать его в JSON: как записывать атрибуты, текстовые узлы и повторяющиеся элементы — настраивается ниже

Каждый атрибут становится отдельным ключом: <user id="7"> → "@id": "7". Собака отделяет атрибут от дочернего элемента с тем же именем

Элемент без атрибутов и детей становится значением: <name>Чайник</name> → "name": "Чайник". Текст рядом с вложенными тегами всё равно уходит в «#text»

В XML типов нет, поэтому результат ничего не додумывает: «2990» остаётся строкой

На каждый уровень вложенности — два пробела

Одинаковые дочерние элементы — всегда массивДва и более ребёнка с одним именем становятся массивом, одиночный остаётся значением. Без флажка останется только последний ребёнок

Исходный XML

Разбор идёт по мере ввода — результат обновляется сразу

JSON

Зачем переводить XML в JSON и обратно

XML никуда не ушёл: в нём отдают данные выгрузки из 1С и CRM, на нём работают SOAP, RSS, SVG и большинство файлов настроек. Но инструменты вокруг сегодня чаще говорят на JSON — скрипты, таблицы, запросы по JSONPath, загрузчики в базы. Перевод нужен не потому, что один формат лучше другого, а потому, что данные остаются теми же, а окружение вокруг них другое.

Инструмент строит по XML дерево элементов и записывает его в JSON по вашим настройкам: атрибуты отдельным ключом с собакой, без префикса или не выгружаются вовсе; повторяющиеся дочерние элементы собираются в массив; текст листа становится значением элемента или отдельным ключом «#text»; числа и логические значения распознаются либо остаются строками. Отступы — от нуля до табуляции — влияют только на вид файла. Часть сведений при переводе теряется навсегда: комментарии, DOCTYPE и порядок текста между тегами в JSON не выражаются, и обратный перевод даст уже не исходный документ.

В обратную сторону инструмент собирает XML из JSON по тем же правилам, только наоборот: ключ с собакой становится атрибутом, ключ «#text» — текстом элемента, массив — несколькими элементами с одним именем, вложенный объект — вложенными элементами. Имя корневого элемента задаётся отдельно: в JSON у корня имени нет — объект это набор ключей, а массив и вовсе список значений, — поэтому без этой настройки корень назывался бы никак, и её значение по умолчанию root приходится менять руками. Ключи, которые в XML именем быть не могут, — пробел, начало с цифры, двоеточие — приводятся к допустимому виду заменой знака на подчёркивание: выбрасывать знак значило бы склеить «цена руб» и «цена-руб» в одно имя, а такой файл прочитался бы с другими данными. Амперсанд, угловые скобки и кавычки экранируются: без этого собранный файл разобрался бы иначе, чем выглядит. Заметная разница с разбором в том, что сборка идёт строкой, без участия браузерного разборщика, — и потому работает одинаково всюду, где выполняется JavaScript.

Разбор, запись и подсчёт размера выполняются в браузере на JavaScript: XML не отправляется на сервер и не сохраняется. Это важно, когда в файле выгрузка с персональными данными, конфигурация с адресами и ключами доступа или ответ внутренней системы, который не должен уходить наружу.

Частые вопросы

Куда попадают атрибуты элемента?

За это отвечает настройка «Атрибуты». По умолчанию каждый атрибут становится отдельным ключом с собакой: <user id="7"> превращается в "@id": "7". Собака нужна не для красоты: у записи <user id="7"><id>7</id></user> ключ id от атрибута и ключ id от дочернего элемента совпали бы, и одно из значений исчезло бы из результата. Режим «Ключом как есть» пишет ключом само имя атрибута — он годится, когда таких совпадений в файле нет. Режим «Не выгружать» выбрасывает атрибуты совсем: в JSON остаётся только структура элементов.

Как элемент с несколькими одинаковыми детьми превращается в массив?

Флажком «Одинаковые дочерние элементы — всегда массив», он включён по умолчанию. Если у элемента два и более ребёнка с одним именем, они становятся массивом в порядке появления: <tag>кухня</tag><tag>техника</tag> превращается в "tag": ["кухня", "техника"]. Одиночный ребёнок остаётся обычным значением, а не массивом из одного элемента: так JSON короче, а структура — точнее. Если флажок снять, массив не собирается и остаётся только последний ребёнок с таким именем: остальные из файла пропадут.

Что происходит с текстом внутри элемента с вложенными тегами?

Настройка «Текстовые узлы» решает только тот случай, когда у элемента нет ничего, кроме текста. В режиме «Значением элемента» такой элемент становится значением: <name>Чайник</name> становится "name": "Чайник". Если же внутри есть и текст, и дочерние теги — <p>Текст <b>жирный</b> конец</p>, — выразить текст значением нельзя, и он попадает в ключ "#text" рядом с детьми, причём в любом режиме. Порядок при этом теряется: ключ "#text" один, и по нему видно, что текст в элементе был, но не то, где именно он стоял между тегами. Режим «Ключ #text» записывает так всегда, в том числе листья.

Почему числа иногда становятся строками?

По умолчанию выбран режим «Всё строками»: в XML типов нет, «2990» и 2990 в нём неразличимы, поэтому результат остаётся текстом и ничего не теряет. Режим «Определять автоматически» превращает 123 и -4.5 в числа, а слова true, false и null — в логическое значение и null. Но часть строк он намеренно оставляет строками: 007 — из-за ведущего нуля (числом он стал бы 7), а 1.2.3 или 8-800-555-35-35 — потому что это не число, а идентификатор или телефон. Две тонкости, о которых стоит знать заранее: слово null в тексте станет пустым значением, а длинный идентификатор из 19 цифр потеряет последние — точность числа в JSON ограничена. Для выгрузок с такими полями надёжнее режим «Всё строками».

Как быть с пространствами имён и CDATA?

Префиксы не трогаются: <soap:Body> становится ключом "soap:Body", атрибут xsi:type — ключом "@xsi:type". Так значение остаётся ровно тем, что было в файле, а разбирать префикс дальше приходится тому, кто читает JSON: склеивать его с адресом пространства имён или срезать инструмент не берётся. CDATA читается как обычный текст: <![CDATA[<b>текст</b>]]> становится строкой "<b>текст</b>" — содержимое не экранируется заново, теги внутри просто часть строки. Комментарии, инструкции обработки и DOCTYPE в JSON не попадают вовсе: дерево строится только из элементов, и объявление <!DOCTYPE ...> с сущностями в результат не переносится.

Зачем переводить XML в JSON?

XML и JSON описывают одно и то же дерево, но окружение вокруг них разное. JSON разбирается в браузере одной строкой, сразу становится объектом и дальше идёт в скрипт, в таблицу, в запрос по JSONPath или в выгрузку. Для XML то же самое требует разбора с учётом пространств имён и схемы. Перевод нужен, когда данные остаются прежними, а инструменты вокруг них — из мира JSON. Обратная сторона в том, что часть сведений о форме документа при этом теряется: атрибут, порядок текста и комментарии в JSON выражаются соглашениями, а не языком, и обратный перевод даст уже не тот файл, что был.

Как перевести JSON обратно в XML?

Переключите направление на «JSON в XML»: настройки панели сменятся, а в поле вставляется уже JSON — атрибуты, текстовые узлы и типы значений в этой стороне не настраиваются, потому что вопрос ставится иначе. Разбор идёт встроенным JSON.parse, и ошибка показывается так же, как у XML: текст движка, строка и столбец. Читается JSON по тем же соглашениям, по которым был записан: ключ с собакой становится атрибутом (@id → id="p-1"), ключ «#text» — текстом элемента, массив — несколькими элементами с одним именем, вложенный объект — вложенными элементами. Имя корневого элемента задаётся настройкой: в JSON у корня имени нет — объект это набор ключей, а массив и вовсе список значений, — поэтому по умолчанию корень называется root, а элементы массива на верхнем уровне получают имя item. Ключи, которые в XML именем быть не могут, — пробел, начало с цифры, двоеточие — заменяются подчёркиванием: иначе файл не разобрал бы никто. Флажок «Объявлять версию и кодировку» добавляет в начало строку объявления, а «Отступ» тот же, что и в обратную сторону: «Без отступов» пишет результат одной строкой.

Восстановится ли исходный XML, если перевести его в JSON и обратно?

Нет, и это не ошибка инструмента: часть сведений об XML в JSON просто не выражается, поэтому получается другое, хотя и равнозначное дерево. Имя корневого элемента в JSON не хранится — обратно корень называется по настройке, и у исходного <catalog> после круга выйдет <root>, если имя не задать руками. Атрибуты становятся обычными ключами, и порядок их в теге сохраняется лишь потому, что JSON помнит порядок ключей; но если атрибут был выключен настройкой «Не выгружать», брать его обратно неоткуда. Комментарии, объявление <?xml?>, DOCTYPE и инструкции обработки в JSON не попадают вовсе — это не элементы, и вернуть их нечем. Порядок текста между тегами теряется: текст собирается в один ключ «#text», а на обратном пути ставится перед детьми, а не туда, где стоял. Отступы и переводы строк исходника — оформление, а не данные: обратный файл форматируется по своей настройке. Наконец, типы: в режиме «Всё строками» <price>2990</price> вернётся текстом, и это точный ответ — в XML число и строка «2990» неразличимы, так что терять тут нечего. Побитово совпадёт только тот файл, который сам был собран из этого JSON при тех же настройках.

Данные отправляются на сервер?

Нет. Разбирают данные встроенные средства браузера: XML — DOMParser, JSON — JSON.parse, — а запись делает JSON.stringify в одну сторону и сборка строки в другую; всё это выполняется в самой странице: файл не передаётся по сети, не сохраняется и не попадает в логи. Отключите интернет и продолжите работу: результат останется на месте. Обратная сторона в том, что при обновлении вкладки вставленный текст пропадёт — историю сайт не ведёт, поэтому готовый JSON или XML лучше сразу скачать файлом.