Я пытаюсь написать регулярное выражение, используя библиотеку PCRE в PHP.
Мне нужно регулярное выражение для соответствия только &
, >
и <
chars, которые существуют внутри строки части любого узла XML, а не самого объявления тега.
Входной XML:
<pnode> <cnode>This string contains > and < and & chars.</cnode> </pnode>
Идея заключается в поиске и замене этих символов и преобразовании их в эквиваленты сущностей XML.
Если бы мне пришлось преобразовать весь XML в объекты XML, это выглядело бы так:
Весь XML, преобразованный в объекты
<pnode> <cnode>This string contains > and < and & chars.</cnode> </pnode>
Мне нужно, чтобы это выглядело так:
Правильный XML
<pnode> <cnode>This string contains > and < and & chars.</cnode> </pnode>
Я попытался написать регулярное выражение, чтобы соответствовать этим символам, используя look-ahaead, но я недостаточно знаю, чтобы это работало. Моя попытка (в настоящее время только попытка сопоставить> символы):
/>(?=[^<]*<)/g
Просто для того, чтобы было ясно, что XML, который я пытаюсь исправить, исходит от третьей стороны, и они, похоже, не могут исправить это, и поэтому я попытаюсь ее исправить.
Классический пример мусора, вывоз мусора. Реальное решение – исправить сломанный экспортер XML, но, очевидно, это выходит за рамки вашей проблемы. Похоже, вам, возможно, придется вручную разобрать XML, запустите htmlentites () в содержимом, а затем верните теги XML.
Я вполне уверен, что это просто невозможно. Вам нужно что-то, что отслеживает вложенность, и нет никакого способа получить регулярное выражение для отслеживания вложенности. Ваш выбор состоит в том, чтобы сначала исправить текст (когда вы, вероятно, можете использовать RE), или использовать что-то, что по крайней мере смутно похоже на синтаксический анализатор XML, в частности, до степени отслеживания того, как теги вложены.
Существует причина, по которой XML требует, чтобы эти символы были экранированы, но без этого вы можете только догадываться, действительно ли что-то является тегом или нет. Например, учитывая что-то вроде:
<tag>Text containing < and > characters</tag>
вы и я, вероятно, можем догадаться, что результат должен быть: ...containing < and >...
...containing < and >...
но я уверен, что спецификация XML допускает дополнительные пробелы, поэтому официально «<и>» следует рассматривать как тег. Вы могли бы, я полагаю, предположить, что все, что похоже на не совпадающий тег, действительно не предназначено для тега, но это тоже займет определенную работу.
В конце концов я решил использовать библиотеку Tidy в PHP. Код, который я использовал, показан ниже:
// Specify configuration $config = array( 'input-xml' => true, 'show-warnings' => false, 'numeric-entities' => true, 'output-xml' => true); $tidy = new tidy(); $tidy->parseFile('feed.xml', $config, 'latin1'); $tidy->cleanRepair()
Это прекрасно работает с исправлением всех ошибок кодирования и преобразованием недопустимых символов в объекты XML.
Можно ли перехватить текст, прежде чем он попытается стать частью вашего XML? Несколько унций профилактики могут стоить фунтов лечения.
Это должно сделать это для амперсандов:
/(\s+)(&)(\s+)/gim
Это означает, что вы ищете только тех персонажей, когда у них есть символы пробела с обеих сторон.
Просто убедитесь, что выражение для замены «$ 1 $ 2amp; $ 3»;
Остальные пошли бы так, с их заменяющими выражениями справа
/(\s+)(>)(\s+)/gim "$1>$2" /(\s+)(<)(\s+)/gim "$1<$2"
Как утверждают другие, регулярные выражения не соответствуют иерархическим данным. Кроме того, если данные некорректно отформатированы, вы не можете гарантировать, что вы это исправите. Рассматривать:
<xml> <tag>Something<br/>Something Else</tag> </xml>
Предполагается ли, что <br/>
читать <br/>
? Невозможно узнать, потому что это правильно отформатированный XML.
Если у вас есть произвольные данные, которые вы хотите включить в дерево XML, подумайте об использовании блока <![CDATA[ ... ]]>
. Он обрабатывается так же, как текстовый узел, и единственное, что вам не нужно избегать, это последовательность символов ]]>
.
Конечно, у вас там нет XML. В XML символы «<» и «&» могут не встречаться (неэкранированные) внутри текста: только внутри комментария, секции CDATA или инструкции обработки. Фактически, «>» может встречаться в тексте, кроме как как часть строки ']]>'. В хорошо сформированном XML символы буква «<» и «&» сигнализируют о начале разметки: «<» сигнализирует о начале начального тега, концевого тега или тега с пустыми элементами, а «&» сигнализирует о начале объекта Справка. В обоих случаях следующий символ НЕ может быть пробелом. Поэтому использование RE, подобного предложению Робусто, найдет все такие случаи. Вам также может потребоваться захватить такие угловые случаи, как «<<», «<\» или «& <». В этом случае вам не нужно пытаться разобрать ваш ввод, RE будет работать нормально.
Если источник содержит строки типа «<something», где «что-то» соответствует произведению для имени:
Имя :: = NameStartChar (NameChar) *
Тогда у вас больше проблемы. Вам нужно (попытаться) проанализировать ваш ввод, как если бы это был реальный XML, и обнаружить случаи ошибок неправильных имен, несоответствующих начальных и конечных тегов, искаженных атрибутов и неопределенных ссылок на сущности (чтобы назвать несколько) , К сожалению, условие ошибки не гарантируется в месте ошибки.
Лучше всего использовать RE, чтобы уловить 90% ошибки и исправить остальное вручную. Вам нужно искать «<» или «&», за которым следует нечто иное, кроме NameStartChar