我正在尝试使用PHP中的PCRE库编写正则表达式。
我需要一个正则表达式来匹配任何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编写一个正则表达式来匹配这些字符,但我不知道如何使其工作。我的尝试(目前只尝试匹配&gt;符号):
/>(?=[^<]*<)/g
为了说清楚我正在尝试修复的XML来自第三方,他们似乎无法修复它的结束,因此我尝试修复它。
答案 0 :(得分:2)
垃圾输入,垃圾输出的经典例子。真正的解决方案是修复损坏的XML导出器,但显然这超出了您的问题范围。听起来您可能需要手动解析XML,对内容运行htmlentites(),然后重新放回XML标记。
答案 1 :(得分:2)
我有理由相信这根本不可能。你需要能够跟踪嵌套的东西,并且无法获得正则表达式来跟踪嵌套。您的选择是首先修复文本(当您可能使用RE时)或使用至少模糊地类似于XML解析器的内容,特别是在跟踪标记嵌套方式的程度。
有一个原因,XML要求这些字符被转义 - 没有它,你只能猜测某些东西是否真的是一个标签。例如,给出类似的东西:
<tag>Text containing < and > characters</tag>
你和我可能猜测结果应该是:...containing < and >...
但是我很确定XML规范允许额外的空格,所以正式“&lt;和&gt;”应该被视为标签。我想,你可以假设任何看起来像一个不匹配标签的东西真的不是一个标签,但这也需要一些工作。
答案 2 :(得分:2)
最后我选择在PHP中使用Tidy库。我使用的代码如下所示:
// 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实体。
答案 3 :(得分:0)
在尝试成为XML的一部分之前,是否可以拦截文本?几盎司的预防可能值得治愈。
答案 4 :(得分:0)
这应该用于&符号:
/(\s+)(&)(\s+)/gim
这意味着只有在两边都有空格字符时才会查找这些字符。
确保替换表达式为“$ 1 $ 2amp; $ 3”;
其他人会这样,他们的替换表达在右边
/(\s+)(>)(\s+)/gim "$1>$2"
/(\s+)(<)(\s+)/gim "$1<$2"
答案 5 :(得分:0)
正如其他人所说,正则表达式与分层数据不相符。此外,如果数据格式不正确,您无法保证您能做到正确。考虑:
<xml>
<tag>Something<br/>Something Else</tag>
</xml>
<br/>
是否应该阅读<br/>
?没有办法知道,因为它是有效格式化的XML。
如果您希望包含在XML树中的任意数据,请考虑使用<![CDATA[ ... ]]>
块。它被视为与文本节点相同,唯一不必转义的是字符序列]]>
。
答案 6 :(得分:0)
你所拥有的当然不是XML。在XML中,字符'&lt;'和'&amp;'可能不会在文本内部发生(未转义):仅在注释,CDATA部分或处理指令内。实际上,'&gt;'可以在文本中出现,但作为字符串']]&gt;'的一部分除外。在格式良好的XML中,文字'&lt;'和'&amp;'字符表示标记的开始:'&lt;'表示开始标记,结束标记或空元素标记的开始,以及'&amp;'发信号通知实体参考的开始。在这两种情况下,下一个字符可能不是空格。所以使用类似Robusto的建议会发现所有这些事件。您可能还需要捕获诸如'&lt;&lt;','&lt; \'或'&amp;&lt;'之类的极端情况。在这种情况下,您不需要尝试解析输入,RE将正常工作。
如果源包含像'&lt; something'这样的字符串,其中'something'与名称的制作匹配:
Name ::= NameStartChar (NameChar)*
那么你有更多的问题。您将不得不(尝试)解析您的输入,就像它是真正的XML一样,并检测格式错误的名称,不匹配的开始和错误的错误情况。结束标记,格式错误的属性和未定义的实体引用(仅举几例)。不幸的是,错误条件不能保证在错误的位置发生。
您最好的选择可能是使用RE来捕获90%的错误并手动修复其余部分。你需要找一个'&lt;'或'&amp;'其次是NameStartChar以外的任何东西