正则表达式在使用php和simplexml_load_string解析失败时用xml标记冒号

问题描述:

在我的last question的后续内容中,如果您有一个xml文件格式错误的字符串,可以使用preg_replace_callback()提取内容以删除破坏的元素。正则表达式在使用php和simplexml_load_string解析失败时用xml标记冒号

此功能的点不与正则表达式解析XML(一坏主意 ),而是试图找到XML不解析和它失败,使我们能 标志物品在发送出 之前没有正确格式化。这是在发送 之前清除内容的一组工具中的一部分。我正在测试它在已知格式不正确的公开RSS网址上,以及 作为内部网址来查看它是否适合多种情况。该回调将为失败的节点返回一个整数。如果在此之后通过,我们可以报告文章的索引,然后尝试使用DOMDocument尝试更正html并重试。如果失败,我们将它作为一个重要的报告,否则,我们返回解析文章描述和内容回数据库,将其标记为分娩前进行修改。

然后,您可以取出损坏的元素,并通过DOMDocument运行它们以更好地格式化它们以返回到XML文件。

但是,我坚持就如何使下面false以外回报这个例子:

示例XML:

<item> 
    <content:encoded><![CDATA[ 
     This is the text with odd characters that are killing 
     simplexml_load_string() (doesn't recover) and breaking 
     (although recoverable) DOMDocument 
    ]]></content:encoded> 
</item> 

如果我用下面的PHP,我可以提取描述节点

<description><![CDATA[ 
    This is some description text with the same problem 
]]></description> 

<description>0</description> 
:从将其转换

PHP:

preg_replace_callback(
    '/<description>(.*)<\/description>/', **// add msU modifiers to fix below** 
    'node_tidy::callback_description', 
    $xml 
); 

...

private function callback_description($matches=false) { 
    if(false !== $matches) { 
     $this->arrDescriptions[] = $matches[1]; 
     return '<description>'.$this->indexDescriptions++.'</description>'; 
    } else { 
     return false; 
    } 
} 

然而,当我尝试做相同的content:encoded节点,则返回false。下面是相关的函数:

private function callback_content_encoded($matches=false) { 
    if(false !== $matches) { 
     $this->arrContentEncoded[] = $matches[1]; 
     return '<content:encoded>'.$this->indexContentEncoded++.'</content:encoded>'; 
    } else { 
     return false; 
    } 
} 

使用直正则表达式,以测试它的冒号,我用这个:

<?php 

$string = '<content:encoded>this is some text</content:encoded>'; 
preg_match('/<content\:encoded>(.*)<\/content\:encoded>/',$string,$matches); 

echo '<pre>'; 
print_r($matches); 
echo '</pre>'; 

?> 

然而,这并没有添加或不添加\:打印预期阵列。可能有人点我在这里认识误区正确的方向?

非常感谢!

UPDATE: 这里的失败,通过@Florent指示的真正的XML的示例代码段。

http://pastebin.com/7z0f3MJP

UPDATE: 此正则表达式所需的内容相匹配:

preg_match('/<content\:encoded>(.*)<\/content\:encoded>/msU',$string,$matches); 

的M和S和U修饰符解释的更好位置: http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php

我不想去考虑这些修饰语。

结果现在带回了这个正则表达式,包括原始问题,所以现在可以解决。

+0

第二次Downvote没有任何解释。谨慎解释为什么我可以相应地调整问题? – MyStream 2012-07-09 15:12:29

+0

为什么你说,_your正则表达式不打印预期array_?我试了一下,得到了节点内容。 – Florent 2012-07-09 15:18:25

+0

也许我的用例太窄了 - 我会发布我想要解析的确切字符串,也许答案就在那里。请再检查一次? – MyStream 2012-07-09 15:21:52

您应该添加以下标志您正则表达式:

  • m,使多串
  • u启用UTF8字符串(如有必要)
+0

谢谢:)) - 特别是,我发现m和u对于使用CDATA包装从畸形xml节点获取xml内容至关重要。发现。 – MyStream 2012-07-09 16:22:24

多行修饰符是不被使用,所以它不需要。只有/ s(点全部)修饰符是必要的。永远不要使用/ U(非贪婪)修饰符(在我看来)。应该使用/ u(unicode)修饰符。

如果您正在寻找解开CDATA结构内的html,最好使用w3c规范,即使您的xml使用其标记的命名空间名称。这只有在xml标签中唯一的元素是CDATA的时候,并且假定xml格式良好。

在现实世界中,评论可能包装CDATA,反之亦然,同时隐藏很多其他的东西。所以,现实是正则表达式可能能够通过错误的xml解析然后恢复,但是它不可靠,而且肯定更复杂。

这就是说,这将从您的示例中提取CDATA,并仅从字面意义上提取CDATA。

if (preg_match(
    '~<content:encoded\s*> 
     \s* 
     <!\[CDATA\[ (.*?) \]\]> 
     \s* 
    </content:encoded\s*>~xsu', 
    $string, 
    $matches)) 
{ 
print ($matches[1]); 
} 
+0

嗨,我们发现一些xml(没有内容编码和描述节点)格式良好,但不会与地方的那些节点解析,即使它正确包装了CDATA。通过删除那些元素(所有内容)然后尝试重新分析,我们可以继续。然后我们可以通过一些检查运行提取内容,包括首先使用DOMDocument清理html,并确保实体在这些内容中转义并将其放回。这远非理想,但似乎有助于纠正大部分问题。为什么你不使用/ U,具体? – MyStream 2012-07-11 19:25:33