Ошибка синтаксического анализатора XML: объект не определен - PullRequest
30 голосов
/ 27 сентября 2010

Я искал stackoverflow по этой проблеме и нашел несколько тем, но мне кажется, что на самом деле для меня нет однозначного ответа.

У меня есть форма, которую пользователи отправляют, и значение поля сохраняется в файле XML. XML настроен на кодировку UTF-8.

Время от времени пользователь копирует / вставляет текст откуда-то, и вот тогда я получаю «ошибка сущности не определена».

Я понимаю, что XML поддерживает только несколько выбранных объектов, и все, кроме того, что не распознается - отсюда ошибка синтаксического анализатора.

Из того, что я понял, есть несколько вариантов, которые я видел:

  1. Я могу найти и заменить все   и заменить их на   или реальным пробелом.
  2. Я могу разместить соответствующий код в разделе CDATA.
  3. Я могу включить эти объекты в файл XML.

Что я делаю с XML-файлом, так это то, что пользователь может вводить контент в форму, он сохраняется в XML-файле, а затем этот контент отображается в виде XHTML на веб-странице (анализируется с помощью SimpleXML).

Из трех или любых других вариантов, о которых я не знаю, как лучше всего справиться с этими объектами?

Спасибо, Райан

UPDATE

Я хочу поблагодарить всех за отличную обратную связь. Я на самом деле определил, что вызвало ошибки моей сущности. Все предложения заставили меня глубже изучить это!

Некоторые текстовые поля, в которых были старые текстовые поля, но мои текстовые области были улучшены с помощью TinyMCE. При ближайшем рассмотрении оказывается, что предупреждения PHP всегда ссылаются на данные из расширенных текстовых областей TinyMCE. Позже я заметил на ПК, что все символы были удалены (потому что он не мог их прочитать), но на MAC вы могли видеть маленькие квадратные квадраты, указывающие номер юникода этого символа. Причина, по которой он появился в квадратах на MAC в первую очередь, заключается в том, что я использовал utf8_encode для кодирования данных, которых не было в UTF, чтобы предотвратить другие ошибки синтаксического анализа (что так или иначе связано с TinyMCE).

Решение всего этого было довольно простым:

Я добавил эту строку entity_encoding : "utf-8" в мой tinyMCE.init. Теперь все персонажи показывают, как они должны.

Полагаю, единственное, чего я не понимаю, - это почему символы по-прежнему отображаются при размещении в текстовых полях, потому что ничто не преобразует их в UTF, но с TinyMCE это было проблемой.

Ответы [ 5 ]

22 голосов
/ 30 ноября 2010

Я согласен, что это чисто проблема кодирования.В PHP я решил эту проблему следующим образом:

  1. Перед передачей html-фрагмента в конструктор SimpleXMLElement я расшифровал его, используя html_entity_decode.

  2. Затем дополнительно кодируем его, используя utf8_encode().

$headerDoc = '<temp>' . utf8_encode(html_entity_decode($headerFragment)) . '</temp>'; 
$xmlHeader = new SimpleXMLElement($headerDoc);

Теперь приведенный выше код не генерирует никаких неопределенных сущностей ошибок.

15 голосов
/ 27 сентября 2010

Вы можете выполнить HTML-разбор текста и повторно экранировать его только с соответствующими числовыми объектами (например: &nbsp; & rarr; &#160;). В любом случае - просто с использованием необработанного пользовательского ввода - плохая идея.

Все числовые объекты разрешены в XML, не работают только именованные, известные из HTML (за исключением &amp;, &quot;, &lt;, &gt;, &apos;).

Однако в большинстве случаев вы можете просто записать фактический символ (&ouml; & rarr; ö) в файл XML, чтобы вообще не было необходимости использовать ссылку на сущность. Если вы используете DOM API для манипулирования вашим XML (и вам следует!), Это ваш самый безопасный выбор.

Наконец (это решение для ленивых разработчиков), вы можете создать поврежденный XML-файл (т.е. не правильно сформированный, с ошибками сущностей) и просто пропустить его через приборку для необходимых исправлений. Это может сработать или может не сработать, в зависимости от того, как все это сломано . По моему опыту, Tidy довольно умный, и позволяет вам многое сойти с рук.

4 голосов
/ 27 сентября 2010

1.Я могу найти и заменить все [&nbsp;?] И поменять их местами с [&#160;?] Или реальным пробелом.

Это надежный метод, но он требует наличиятаблица всех сущностей HTML (я предполагаю, что вставленный ввод происходит из HTML) и для анализа вставленного текста на предметные ссылки.

2.Я могу поместить соответствующий код в раздел CDATA.

Другими словами отключить разбор всего раздела?Тогда вам придется разобрать это другим способом.Может работать.

3.Я могу включить эти сущности в файл XML.

Вы имеете в виду включить определения сущностей?Я думаю, что это простой и надежный способ, если вы не против сделать XML-файл немного больше.У вас может быть «включенный» файл (найдите его в Интернете), который является внешней сущностью, на которую вы ссылаетесь в верхней части основного XML-файла.

Недостатком является то, что используемый анализатор XML долженбыть тем, который обрабатывает внешние объекты (что требуется не всем анализаторам).И он должен правильно разрешить (возможно, относительный) URL-адрес внешнего объекта к чему-то доступному.Это не так уж плохо, но может увеличить ограничения на ваши инструменты обработки.

4.Вы можете запретить не-XML в вставленном контенте.Среди прочего, это запретило бы ссылки на сущности, которые не предопределены в XML (те 5, которые упоминал Томалак) или не определены в самом контенте.Однако это может нарушать требования приложения, если пользователи должны иметь возможность вставлять туда HTML.

5.Вы можете проанализировать вставленный контент как HTML в дерево DOM, установив someDiv.innerHTML = thePastedContent;Другими словами, создайте где-нибудь div (вероятно, display = none, за исключением отладки).Скажем, у вас есть переменная javascript myDiv, которая содержит этот элемент div, и другая переменная myField, которая содержит элемент, являющийся вашим входным текстовым полем.Затем в javascript вы делаете

myDiv.innerHTML = myField.value;

, который берет непарсированный текст из myField, анализирует его в дереве HTML DOM и вставляет его в myDiv в качестве содержимого HTML.

Затем вы должны использовать некоторыеоснованный на браузере метод для сериализации (= "разбор") дерева DOM обратно в XML.См. Например этот вопрос .Затем вы отправляете результат на сервер в виде XML.

Если вы хотите сделать это исправление в браузере или на сервере (как предложено @Hannes), будет зависеть от размера данных, от того, насколько быстро откликнетсядолжно быть, насколько мощным является ваш сервер, и заботитесь ли вы о том, чтобы хакеры специально отправляли не правильно сформированный XML.

1 голос
/ 27 сентября 2010

Если вы хотите преобразовать все символы, это может вам помочь (я писал это некоторое время назад):

http://www.lautr.com/convert-all-applicable-characters-to-numeric-entities-for-use-in-xml

function _convertAlphaEntitysToNumericEntitys($entity) {
  return '&#'.ord(html_entity_decode($entity[0])).';';
}

$content = preg_replace_callback(
  '/&([\w\d]+);/i',
  '_convertAlphaEntitysToNumericEntitys',
  $content);

function _convertAsciOver127toNumericEntitys($entity) {
  if(($asciCode = ord($entity[0])) > 127)
    return '&#'.$asciCode.';';
  else
    return $entity[0];
}

$content = preg_replace_callback(
  '/[^\w\d ]/i',
  '_convertAsciOver127toNumericEntitys', $content);
0 голосов
/ 15 декабря 2017

Этот вопрос является общей проблемой для любого языка, который анализирует XML или JSON (так, в основном, для каждого языка).

Приведенные выше ответы относятся к PHP, но решение Perl было бы так же просто, как ...

my $excluderegex =
    '^\n\x20-\x20' .   # Don't Encode Spaces
       '\x30-\x39' .   # Don't Encode Numbers
       '\x41-\x5a' .   # Don't Encode Capitalized Letters
       '\x61-\x7a' ;   # Don't Encode Lowercase Letters

    # in case anything is already encoded
$value = HTML::Entities::decode_entities($value);

    # encode properly to numeric
$value = HTML::Entities::encode_numeric($value, $excluderegex);
...