Подтвердить что ты не робот

Как анализировать неверный (плохой/неправильно сформированный) XML?

В настоящее время я работаю над функцией, которая включает в себя синтаксический анализ XML, который мы получаем от другого продукта. Я решил провести некоторые тесты против некоторых фактических данных о клиентах, и похоже, что другой продукт позволяет вводить данные от пользователей, которые считаются недействительными. В любом случае, мне все еще нужно попытаться выяснить, как его разобрать. Мы используем javax.xml.parsers.DocumentBuilder, и я получаю сообщение об ошибке, которое выглядит следующим образом.

<xml>
  ...
  <description>Example:Description:<THIS-IS-PART-OF-DESCRIPTION></description>
  ...
</xml>

Как вы можете сказать, в описании есть то, что внутри него является недопустимым тегом (<THIS-IS-PART-OF-DESCRIPTION>). Теперь этот тег описания, как известно, является листовым тегом и не должен иметь внутри него вложенных тегов. Несмотря на это, это все еще проблема и дает исключение на DocumentBuilder.parse(...)

Я знаю, что это недопустимый XML, но он предсказуемо недействителен. Любые идеи о способе анализа такого ввода?

4b9b3361

Ответ 1

Этот "XML" хуже недействительного - он не корректен; см. Хорошо сформированный против действительного XML.

Неформальная оценка предсказуемости нарушений не помогает. Эти текстовые данные не являются XML. Никакие совместимые XML-инструменты или библиотеки не могут помочь вам в этом.

Варианты, наиболее желательные в первую очередь:

  1. Попросите поставщика решить проблему с их стороны. Требуйте правильно сформированный XML. (Технически фраза правильно сформированный XML избыточна, но может быть полезна для акцента.)
  2. Используйте допустимый синтаксический анализатор разметки, чтобы очистить проблему перед синтаксическим анализом как XML:

  3. Обработайте данные как текст вручную, используя текстовый редактор или программно, используя символьные/строковые функции. Выполнение этого программно может варьироваться от сложного до невозможного, поскольку то, что кажется предсказуемым, часто не бывает - нарушение правил редко связано правилами.

    • Для ошибок недопустимых символов используйте regex для удаления/замены недопустимых символов:
      • PHP: preg_replace('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $s);
      • Ruby: string.tr("^\u{0009}\u{000a}\u{000d}\u{0020}-\u{D7FF}\u{E000‌​}-\u{FFFD}", ' ')
      • JavaScript: inputStr.replace(/[^\x09\x0A\x0D\x20-\xFF\x85\xA0-\uD7FF\uE000-\uFDCF\uFDE0-\uFFFD]/gm, '')
    • Для амперсандов используйте регулярное выражение, чтобы заменить совпадения на &amp; : credit: blhsin, demo

      &(?!(?:#\d+|#x[0-9a-f]+|\w+);)
      

    Обратите внимание, что приведенные выше регулярные выражения не будут учитывать комментарии или разделы CDATA.

Ответ 2

Стандартный XML-синтаксический анализатор НИКОГДА не будет принимать недопустимый XML.

Ваш единственный вариант - предварительно обработать ввод, чтобы удалить "предсказуемо недействительный" контент или обернуть его в CDATA, прежде чем разбирать его.

Ответ 3

ИМО эти случаи должны быть решены с помощью JSoup.

Ниже приведен не совсем ответ для этого конкретного случая, но он был найден в Интернете (спасибо inuyasha82 на Coderwall). Этот фрагмент кода вдохновил меня на еще одну подобную проблему при работе с искаженными XML файлами, поэтому я поделюсь этим здесь.

Пожалуйста, не редактируйте то, что ниже, как на оригинальном веб-сайте.

Формат XML требует, чтобы действительным был уникальный корневой элемент, объявленный в документе. Так, например, действительный xml:

<root>
     <element>...</element>
     <element>...</element>
</root>

Но если у вас есть такой документ:

<element>...</element>
<element>...</element>
<element>...</element>
<element>...</element>

Это будет считаться неверно сформированным XML, поэтому многие парсеры xml просто генерируют исключение с жалобой на отсутствие корневого элемента. И т.п.

В этом примере есть решение о том, как решить эту проблему и успешно проанализировать неверно сформированный xml выше.

По сути, мы будем программно добавлять корневой элемент.

Итак, в первую очередь вы должны открыть ресурс, который содержит ваш "искаженный" xml (то есть файл):

File file = new File(pathtofile);

Затем откройте FileInputStream:

FileInputStream fis = new FileInputStream(file);

Если в этот момент мы попытаемся проанализировать этот поток с какой-либо библиотекой XML, мы выдадим исключение некорректного документа.

Теперь мы создаем список объектов InputStream с тремя элементами:

Элемент ByteIputStream, содержащий строку: "" Наш FileInputStream A ByteInputStream со строкой: "" Итак, код:

List<InputStream> streams = 
    Arrays.asList(
        new ByteArrayInputStream("<root>".getBytes()),
    fis,
    new ByteArrayInputStream("</root>".getBytes()));

Теперь, используя SequenceInputStream, мы создаем контейнер для списка, созданного выше:

InputStream cntr = 
new SequenceInputStream(Collections.enumeration(str));

Теперь мы можем использовать любую библиотеку XML Parser в cntr, и она будет проанализирована без каких-либо проблем. (Проверено с помощью библиотеки Stax);

Ответ 4

Принятый ответ - хороший совет и содержит очень полезные ссылки.

Я хотел бы добавить, что этот и многие другие случаи некорректного XML и/или недопустимого DTD XML можно исправить с помощью SGML, стандартизированного по ISO расширенного набора HTML и XML. В вашем случае лучше всего объявить фиктивный элемент THIS-IS-PART-OF-DESCRIPTION пустым элементом SGML, а затем использовать, например,. программа osx (часть пакета OpenSP/OpenJade SGML) для преобразования его в XML. Например, если вы поставите следующее для osx

<!DOCTYPE xml [
  <!ELEMENT xml - - ANY>
  <!ELEMENT description - - ANY>
  <!ELEMENT THIS-IS-PART-OF-DESCRIPTION -  - EMPTY>
]>
<xml>
  <description>blah blah
    <THIS-IS-PART-OF-DESCRIPTION>
  </description>
</xml>

он выведет правильно сформированный XML для дальнейшей обработки с помощью инструментов XML по вашему выбору.

Обратите внимание, однако, что у вашего примера фрагмента есть другая проблема в том, что имена элементов, начинающиеся с букв xml или XML или Xml и т.д., Зарезервированы в XML и не будут приняты соответствующими парсерами XML.