Не так давно пришлось столкнуться с парсингом XML на JS.
С виду всё просто:
- Берем парсер из браузера, либо ставим свой
- Создаем парсер: new DOMParser()
- Запускаем parseFromString(string)
В полной мере не получалось тестировать корректность парсинга и всех дальнейших преобразований. Зато замечал изредка ошибки в консоли браузера, что что-то с элементом не так.
Однажды решил залезть туда и перехватить содержимое XML, которое выглядело следующим образом
...
<m:r>
<w:rPr>
<w:Fonts w:ascii="Cambria Math" w:hAnsi="Cambria Math" />
<w:w w:val="105" />
</w:rPr>
<m:t {http://www.w3.org/XML/1998/namespace}space="preserve">,
</m:t>
</m:r>
...
Я не сразу увидел, но потом как увидел!
<m:t {http://www.w3.org/XML/1998/namespace}space="preserve">
Сначала я подумал, что это какой-то невалидный XML и с парсером всё ОК. Однако, попробовал другие документы и обнаружил, что баг всё-таки не в XML, а в парсере.
Такая запись называется Clark Notation, она представляет из себя "inline" неймспейма документа прямо в место использования этого атрибута/тега.
Вместо объявления xmlns, namespace пишется прямо в фигурных скобках: {http://example.com}element.
Если сделать обратное преобразование, то результат будет примерно такой:
<m:t xmlns:ns="http://www.w3.org/XML/1998/namespace" ns:space="preserve">
Т.е.:
- Мы вытащили содержимое в фигурных скобках в отдельное указание неймспейса
- xmlns=NS_NAME="NS_VALUE"
- И заменили эти символы на использование этого неймспейса
- NS_NAME:space
Такое преобразование можно делать в обе стороны и даже иметь несколько инлайнов в одном теге, либо даже неймспейс тега заинлайнить:
Например, было:
<cars:part xmlns:cars="http://www.cars.com/xml"/>
Стало:
<{http://www.cars.com/xml}part/>
Выглядит короче (иногда), но JS парсер с таким не справился!
А как же PHP?
PHP Warning: simplexml_load_string(): Entity: line 1: parser error : Couldn't find end of Start Tag tag line 1 in php shell code on line 1
Еще пыха сходит с ума и выводит эту ошибку раз 10!
А вот что получилось в Kotlin!
Element type "tag" must be followed by either attribute specifications, ">" or "/>".
В общем, стандартные средства не понимают этого Кларка.
Я сделал небольшую функцию на регулярке и циклах с заменой подстрок {...}attr на xmlns:nsN="..." nsN: и теперь всё работает как надо.
Кто-то сталкивался с этим Кларком? Как решали подобное?
——
Небольшая статья от того самого Кларка: http://www.jclark.com/xml/xmlns.htm
Вроде даже есть библиотека на PHP: https://sabre.io/xml/clark-notation/
——
@handle_topic