Ошибка парсера XML: сущность не определена

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

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

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

Я понимаю, что XML поддерживает только несколько сущностей, и все, что за ним не распознается, – следовательно, ошибка парсера.

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

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

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

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

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

ОБНОВИТЬ

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

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

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

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

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

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

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

  2. Затем он закодировал его с помощью utf8_encode() .

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

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

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

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

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

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

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; 

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

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

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

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

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); 

Этот вопрос является общей проблемой для любого языка, который анализирует 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);