Я пытаюсь написать регулярное выражение, используя библиотеку PCRE в PHP.
Мне нужно регулярное выражение, чтобы соответствовать только символам &
, >
и <
, которые существуют внутри строковой части любого узла 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>
I нужно, чтобы это выглядело так:
Правильный XML
<pnode>
<cnode>This string contains > and < and & chars.</cnode>
</pnode>
Я попытался написать регулярное выражение для сопоставления этих символов, используя look-ahaead, но я не не знаю достаточно, чтобы заставить это работать. Моя попытка (в настоящее время только пытается сопоставить> символы):
/>(?=[^<]*<)/g
Просто чтобы прояснить, что 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.
Я вполне уверен, что это просто невозможно. Вам нужно что-то, что отслеживает вложенность, и нет никакого способа получить регулярное выражение для отслеживания вложенности. Ваш выбор - сначала исправить текст (когда вы, вероятно, можете использовать RE) или использовать что-то, хотя бы отдаленно напоминающее синтаксический анализатор XML, в частности, для отслеживания того, как теги вложены.
Есть причина, по которой XML требует, чтобы эти символы были экранированы - без этого вы можете только догадываться о том, действительно ли что-то является тегом или нет. Например, учитывая что-то вроде:
<tag>Text containing < and > characters</tag>
мы с вами, вероятно, можем предположить, что результат должен быть: ... содержащий <и> ...
, но я почти уверен, что спецификация XML разрешает лишний пробел, поэтому официально "<и>" следует рассматривать как тег. Я полагаю, вы могли бы предположить, что все, что выглядит как несоответствующий тег, на самом деле не предназначено для использования в качестве тега, но это тоже потребует некоторой работы.
Можно ли перехватить текст, прежде чем он попытается стать частью вашего XML? Несколько унций профилактики могут стоить фунтов лечения.
Это должно сделать это для амперсандов:
/(\s+)(&)(\s+)/gim
Это означает, что вы ищете эти символы только тогда, когда они имеют пробелы с обеих сторон.
Просто убедитесь, что заменяющим выражением является "$ 1 $ 2amp; $ 3";
Остальные будут выглядеть так, с их заменяющими выражениями справа
/(\s+)(>)(\s+)/gim "$1>$2"
/(\s+)(<)(\s+)/gim "$1<$2"
То, что у вас есть, конечно, не XML. В XML символы «<» и «&» не могут встречаться (без экранирования) внутри текста: только внутри комментария, раздела CDATA или инструкции обработки. Фактически, '>' может встречаться в тексте, за исключением части строки ']]>'. В правильно сформированном XML буквальные символы '<' и '&' сигнализируют о начале разметки: '<' сигнализирует о начале начального тега, конечного тега или тега пустого элемента, а '&' сигнализирует о начале объекта. Справка. В обоих этих случаях следующий символ НЕ может быть пробелом. Таким образом, использование RE, такого как предложение Робусто, обнаружит все такие случаи. Вам также может потребоваться отловить угловые случаи, такие как '<<', '<\' или '& <'. В этом случае вам не нужно пытаться анализировать введенные вами данные, RE будет работать нормально.
Если источник содержит такие строки, как «
Name :: = NameStartChar (NameChar) *
, тогда у вас большая проблема. Вам придется (попытаться) проанализировать свой ввод, как если бы это был настоящий XML, и выявить случаи ошибок искаженных имен, несовпадающих начальных и конечных тегов, искаженных атрибутов и ссылок на неопределенные сущности (и это лишь некоторые из них). . К сожалению, не гарантируется, что состояние ошибки произойдет в месте возникновения ошибки. Лучше всего использовать RE, чтобы отловить 90% ошибок и исправить остальные вручную. Вам нужно искать '<' или '&', за которым следует что-либо, кроме NameStartChar
Как утверждали другие, регулярные выражения плохо справляются с иерархическими данными. Кроме того, если данные неправильно отформатированы, вы не можете гарантировать, что у вас все получится. Подумайте:
<xml>
<tag>Something<br/>Something Else</tag>
</xml>
Это
должно читать
? Нет никакого способа узнать, потому что это правильно отформатированный XML.
Если у вас есть произвольные данные, которые вы хотите включить в свое XML-дерево, рассмотрите возможность использования вместо этого блока
. Он обрабатывается так же, как текстовый узел, и единственное, что вам не нужно экранировать, - это последовательность символов ]]>
.
Классический пример мусора на входе и выходе. Реальное решение - исправить сломанный экспортер XML, но, очевидно, это выходит за рамки вашей проблемы. Похоже, вам, возможно, придется вручную проанализировать XML, запустить htmlentites () для содержимого, а затем вернуть теги XML.