Регулярное выражение для совпадения символов ">", "<", "&", которые появляются внутри узлов XML - PullRequest
10 голосов
/ 17 февраля 2010

Я пытаюсь написать регулярное выражение, используя библиотеку PCRE в PHP.

Мне нужно регулярное выражение для сопоставления только с &, > и < символами, которые существуют в строковой части любого узла XML, а не с самим объявлением тега.

Входной XML:

<pnode>
  <cnode>This string contains > and < and & chars.</cnode>
</pnode>

Идея состоит в том, чтобы найти и заменить эти символы и преобразовать их в эквиваленты сущностей XML.

Если бы я преобразовал весь XML в сущности, XML бы выглядел так:

Весь XML преобразован в сущности

&lt;pnode&gt;
  &lt;cnode&gt;This string contains &gt; and &lt; and &amp; chars.&lt;/cnode&gt;
&lt;/pnode&gt;

Мне нужно, чтобы это выглядело так:

Правильный XML

<pnode>
  <cnode>This string contains &gt; and &lt and &amp; chars.</cnode>
</pnode>

Я пытался написать регулярное выражение для сопоставления этих символов, используя look-ahaead, но я не знаю достаточно, чтобы заставить это работать. Моя попытка (в настоящее время только пытается соответствовать> символам):

/>(?=[^<]*<)/g

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

Ответы [ 7 ]

2 голосов
/ 17 февраля 2010

Я вполне уверен, что это просто невозможно. Вам нужно что-то, что отслеживает вложение, и нет способа получить регулярное выражение для отслеживания вложения. Вы должны сначала исправить текст (когда вы, вероятно, можете использовать RE) или использовать что-то, по крайней мере смутное, похожее на XML-парсер, особенно в части отслеживания того, как теги вложены.

Существует причина, по которой XML требует экранирования этих символов - без этого вы можете только догадываться, является ли что-то тегом или нет. Например, что-то вроде:

    <tag>Text containing < and > characters</tag>

вы и я, вероятно, можем предположить, что результат должен быть: ...containing &lt; and &gt;..., но я вполне уверен, что спецификация XML допускает дополнительный пробел, поэтому официально "<и>" следует рассматривать как тег. Я полагаю, вы могли бы предположить, что все, что выглядит как несоответствующий тег, на самом деле не должно быть тегом, но это также потребует некоторой работы.

2 голосов
/ 18 февраля 2010

В конце концов я решил использовать библиотеку 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.

2 голосов
/ 17 февраля 2010

Классический пример мусора на входе, мусора на выходе. Реальное решение состоит в том, чтобы исправить поврежденный экспортер XML, но, очевидно, это выходит за рамки вашей проблемы. Похоже, вам, возможно, придется вручную проанализировать XML, запустить htmlentites () для содержимого, а затем вернуть теги XML обратно.

0 голосов
/ 17 февраля 2010

То, что у вас есть, это, конечно, не XML. В XML символы «<» и «&» могут не появляться (не экранироваться) внутри текста: только внутри комментария, раздела CDATA или инструкции по обработке. На самом деле, '>' может встречаться в тексте, кроме как как часть строки ']]>'. В правильно сформированном XML буквенные символы «<» и «&» обозначают начало разметки: «<» обозначает начало начального тега, конечного тега или пустого тега элемента, а «&» обозначает начало объекта ссылка. В обоих этих случаях следующий символ НЕ может быть пробелом. Таким образом, использование RE, подобного предложению Робусто, позволит найти все такие случаи. Вам также может понадобиться поймать угловые случаи, такие как «<<», «<\» или «& <». В этом случае вам не нужно пытаться проанализировать ваши данные, RE будет работать нормально. </p>

Если источник содержит строки типа «<что-то», где «что-то» соответствует продукции для Имени: <p> Имя :: = NameStartChar (NameChar) *

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

Лучше всего использовать RE, чтобы поймать 90% ошибки и исправить остальное вручную. Вам нужно искать '<' или '&', за которыми следует что-то кроме NameStartChar </p>

0 голосов
/ 17 февраля 2010

Как утверждают другие, регулярные выражения плохо работают с иерархическими данными. Кроме того, если данные неправильно отформатированы, вы не можете гарантировать, что вы все сделаете правильно. Рассмотрим:

<xml>
    <tag>Something<br/>Something Else</tag>
</xml>

Это <br/> должно читаться &lt;br/&gt;? Там нет никакого способа узнать, потому что это правильно отформатированный XML.

Если у вас есть произвольные данные, которые вы хотите включить в свое дерево XML, рассмотрите возможность использования блока <![CDATA[ ... ]]>. Он обрабатывается так же, как текстовый узел, и единственное, что вам не нужно избегать, это последовательность символов ]]>.

0 голосов
/ 17 февраля 2010

Это должно сделать это для амперсандов:

/(\s+)(&)(\s+)/gim

Это означает, что вы ищете эти символы только тогда, когда они имеют пробельные символы с обеих сторон.

Просто убедитесь, что выражение замены "$ 1 $ 2amp; $ 3";

Остальные пошли бы так, с их выражениями замены справа

/(\s+)(>)(\s+)/gim   "$1&gt;$2"
/(\s+)(<)(\s+)/gim   "$1&lt;$2"
0 голосов
/ 17 февраля 2010

Можно ли перехватить текст, прежде чем он попытается стать частью вашего XML?Несколько унций профилактики могут стоить лечения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...