0

在我上一个问题的后续步骤中,如果您的 xml 文件中有一个格式错误的字符串,您可以使用 preg_replace_callback() 提取内容以删除中断的元素。

这个函数的重点不是用正则表达式解析 xml(一个坏主意),而是试图找到不解析的 xml 以及它失败的地方,以便我们可以在发送之前标记格式不正确的文章出去。这是在交付前清理内容的一组工具的一部分。我正在对已知的格式错误的公共 RSS url 以及内部 URL 进行测试,以查看它是否适合多种情况。回调将为失败的节点返回一个整数。如果之后通过,我们可以报告文章的索引,然后尝试使用 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>';

?>

但是,无论是否添加\:. 有人可以为这里的误解指出正确的方向吗?

非常感谢!

更新:这是失败的真实 xml 的示例片段,如@Florent 所示。

http://pastebin.com/7z0f3MJP

更新:这个正则表达式匹配所需的内容:

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

m 和 s 和 U 修饰符在这里解释得更好: http ://www.php.net/manual/en/reference.pcre.pattern.modifiers.php

我忽略了考虑这些修饰符。

结果现在由这个正则表达式返回,包括原来的问题,所以现在可以解决这个问题。

4

2 回答 2

1

您应该将以下标志添加到您的正则表达式中:

  • m启用多行字符串
  • u启用 UTF8 字符串(如有必要)
于 2012-07-09T16:01:44.767 回答
0

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

如果您希望在 CDATA 结构中解包 html,最好使用 w3c 规范,即,即使您的 xml 对其标签使用命名空间名称。仅当 xml 标记中的唯一元素是 CDATA 时,并且假定 xml 格式正确。

在现实世界中,评论可以包装 CDATA,反之亦然,以及隐藏许多其他内容。因此,现实情况是,正则表达式可能能够解析格式错误的 xml,然后恢复,但它并不可靠,而且肯定更复杂。

话虽如此,这将从您的示例中提取 CDATA,并且仅在字面意义上。

if (preg_match(
   '~<content:encoded\s*>
       \s*
       <!\[CDATA\[ (.*?) \]\]>
       \s*
     </content:encoded\s*>~xsu',
    $string,
    $matches) )
{
 print ( $matches[1] );
}
于 2012-07-09T18:17:05.613 回答