Инструменты разработчика · Конвертеры синтаксиса
Сопоставление XML с JSON: атрибуты, текстовые узлы и проблема «один против многих»
· Как это работает
xml JSON форматы данных
Не существует единственно правильного способа превратить XML в JSON, поскольку XML имеет атрибуты, смешанный контент и упорядоченные дочерние элементы, которых нет у JSON. В этом посте объясняются общие соглашения по отображению и ловушки в каждом из них.
Почему один <item> стал объектом, а два — массивом — фид XML, форма JSON которого меняется в зависимости от количества записей в нем
Фид с `<item>one</item>` создает `"item": "one"`; добавление второго брата изменяет это свойство на `"item": ["one", "two"]`. Анализатор не может сделать вывод, что один элемент концептуально был списком из одного, поскольку оба значения имеют идентичный синтаксис XML. Поэтому код, построенный только на основе первого образца, может дать сбой, когда производство отправит второй.
ToolAcre не скрывает эту нестабильность за опцией всегда массива. Он записывает имя один раз как одно значение, а повторяющиеся братья и сестры — как массив. Это прямое сопоставление легко проверить, но потребители, нуждающиеся в стабильной форме коллекции, должны использовать знания схемы или самостоятельно нормализовать результат после преобразования.
Что есть у XML, чего нет у JSON — атрибуты, текст, смешанный с элементами, упорядоченные одноуровневые элементы, пространства имен, комментарии и инструкции по обработке.
XML отделяет атрибуты от дочерних элементов, сохраняет родственный порядок, допускает текст между элементами, содержит префиксы пространства имен и может содержать комментарии и инструкции по обработке. JSON предлагает объекты и массивы, но не имеет встроенных эквивалентов для этих категорий узлов. Любой результат от XML к JSON, следовательно, является выбранной проекцией, а не универсальным переводом.
Этот читатель удаляет декларацию, комментарии и инструкции по обработке. Префиксы пространства имен остаются дословными, а не разрешаются: `<ns:item>` становится ключом `ns:item`, а `xmlns:ns` становится `@xmlns:ns`. Смешанный текст объединяется под одним ключом, поэтому его исходное положение вокруг дочерних элементов теряется, и появляется предупреждение о том, что преобразование не может быть выполнено в обе стороны.
Соглашения об атрибутах — префиксы, такие как @ или $, почему они существуют и как конфликтуют атрибут и дочерний элемент с одинаковым именем.
Атрибуты используют префикс `@`. `<user id="7"><id>other</id></user>` становится объектом с `@id`, равным `"7"`, и дочерним объектом `id`, равным `"other"`. Префикс предотвращает столкновение двух разных конструкций XML в одном свойстве объекта. Он также становится частью контракта преобразователя, когда JSON записывается обратно в XML.
Другие библиотеки могут использовать `$`, объект атрибутов или другое соглашение. ToolAcre поддерживает только видимое сопоставление `@`. Изменение этого префикса в коде приложения без изменения средства записи превратило бы атрибуты в элементы, поэтому сохраните его при использовании преобразованного значения в качестве промежуточной формы проверки.
Соглашения о текстовых узлах — #text или _ для содержимого элемента и что происходит, когда элемент имеет и текст, и дочерние элементы.
Элемент, содержащий только текст, сворачивается в эту строку. Если также присутствуют атрибуты или дочерние элементы, текст находится под `#text`; CDATA хранится отдельно в `#cdata`. Самозакрывающийся тег становится пустой строкой. Эти зарезервированные ключи позволяют писателю отличать обычные дочерние имена от категорий контента, которые сам JSON не определяет.
Смешанный контент остается с потерями. В `<p>before<b>bold</b>after</p>` положение «до» и «после» относительно дочернего элемента не может быть восстановлено из присоединенного свойства `#text`. Инструмент обнаруживает эту структурную закономерность и предупреждает. Используйте сохраняющий узлы XML API, когда порядок документов является частью значения.
Проблема «один против многих»: повторяющиеся элементы становятся массивами только тогда, когда они повторяются, и почему потребители должны использовать защитный код
Повторяющиеся братья и сестры превращаются в массивы только после того, как наблюдается повторение. Одиночный `<book>` — это один объект; две книги представляют собой массив объектов. Иногда это называют проблемой «один против многих», но это не дефект синтаксического анализатора. Исходный документ просто не содержит объявления списка независимо от его вхождений.
Защитные потребители могут нормализовать известные пути, зная схему: оберните `catalogue.book`, если он еще не является массивом. Не применяйте это правило ко всем свойствам, поскольку обычный скаляр не должен становиться списком только из соображений симметрии. Конвертер намеренно избегает создания такой информации о домене.
Рабочий пример: преобразование небольшого документа в стиле RSS — атрибутов, повторяющегося элемента и пространства имен с результирующим аннотированием JSON.
Преобразуйте `<feed xmlns:m="https://example.invalid/meta"><item id="1"><m:title>One</m:title></item><item id="2"><m:title><![CDATA[Two & More]]></m:title></item></feed>`. Корень — `feed`; `@xmlns:m` сохраняет объявление пространства имен; `item` — массив; каждый `@id` представляет собой текст; а второй заголовок содержит `#cdata`.
По умолчанию вывод типа отключен, поэтому даже `id="2"` остается строкой `"2"`. Включение вывода позволяет синтаксическому анализатору читать числовой и логический текст как типы JavaScript, но XML не заявлял об этом намерении. Эта опция является предположением, контролируемым пользователем, а не доказательством, предоставленным документом.
Что здесь не распространяется — преобразование на основе схемы, которое знает, что элемент всегда является списком, для чего требуется XSD или сопоставление вручную.
Никакой XSD не загружен, и информация о списках, управляемых схемой, недоступна. Преобразователь не может знать, что элемент повторяется, когда появляется только один, проверять требуемые дочерние элементы, разрешать URI пространства имен в типы приложения или генерировать типизированный клиент. Успешный анализ устанавливает только правильно сформированный XML, принятый настроенным устройством чтения.
Объявления DOCTYPE отклоняются перед разбором, в том числе безобидные. Эта граница предотвращает запросы внешних сущностей, чтение локальных файлов и расширение сущностей. Удаление DOCTYPE также может привести к удалению объявлений, от которых зависел документ, поэтому делайте это только в том случае, если вы владеете данными и понимаете последствия.
Вывод: от XML до JSON — это сопоставление, а не перевод, и как панель преобразователей синтаксиса позволяет вам проверять это сопоставление в браузере.
Считайте результат документированным сопоставлением ToolAcre: `@` для атрибутов, `#text` для смешанного текста элемента, `#cdata` для CDATA, массивов после повторяющихся одноуровневых элементов и литеральных префиксов пространства имен. Эти правила делают вывод предсказуемым, не создавая иллюзий, что XML и JSON используют одну модель данных.
Для проверки эта проекция является быстрой и читаемой. Для надежной интеграции протестируйте одно или несколько вхождений, атрибуты, имена которых совпадают с дочерними элементами, пустые элементы, смешанный контент и пространства имен. Если порядок элементов или ограничения схемы имеют значение, анализируйте XML на основе этого контракта, а не в зависимости от универсальной преобразованной формы.
Держите необработанный фикстуру XML рядом с нормализованным ожиданием. Это сочетание сохраняет доказательства, если обновление зависимостей изменяет обработку массива, обрезку пробелов или декодирование объекта. Это также дает рецензентам возможность увидеть различия, которые представление JSON не может нести. Преобразованный объект сам по себе не может доказать, возникла ли пустая строка из самозакрывающегося элемента, парных тегов или другого соглашения в источнике.