7

我遇到以下行为:

$xml_string1 = "<person><name><![CDATA[ Someone&#039;s Name ]]></name></person>";
$xml_string2 = "<person><name> Someone&#039;s Name </name></person>";

$person = new SimpleXMLElement($xml_string1);
print (string) $person->name; # Someone&#039;s Name

$person = new SimpleXMLElement($xml_string2);
print (string) $person->name; # Someone's Name

$person = new SimpleXMLElement($xml_string1, LIBXML_NOCDATA);
print (string) $person->name; # Someone&#039;s Name

php 文档说 NOCDATA “将 [s] CDATA 合并为文本节点”。对我来说,这意味着 CDATA 将被视为与文本节点相同 - 或者第三个示例的行为现在将与第二个示例相同。

我无法控制 XML(它是来自外部源的提要),否则我只会删除 CDATA 标记,因为它什么都不做并破坏了我想要的行为。

为什么上面的例子表现得如此呢?有没有办法让 SimpleXML 以与处理文本节点相同的方式处理 CDATA 节点?“将 CDATA 合并为文本节点”实际上做了什么,因为我似乎不理解该选项?

提取数据后,我目前正在解码,但上面的示例对我来说仍然没有意义。

4

1 回答 1

13

XML 中 CDATA 部分的目的是“按原样”封装文本块,否则需要对特殊字符(特别是>,<&)进行转义。包含字符的 CDATA 部分&与包含&amp;.

如果解析器提供忽略这一点,并假装所有 CDATA 节点实际上只是文本节点,那么一旦有人提到“P&O Cruises”,它就会立即中断——这&根本不可能单独存在(而不是&amp;,或&somethingElse;)。

LIBXML_NOCDATA实际上对 SimpleXML 毫无用处,因为它(string)$foo巧妙地将任何文本序列和 CDATA 节点组合成一个普通的 PHP 字符串。(人们经常没有注意到的事情,因为print_r没有。)对于更系统的访问方法(例如 DOM)不一定如此,在这些方法中,您可以将文本节点和 CDATA 节点作为自己的对象进行操作。

它有效地做的是遍历文档,无论它遇到 CDATA 部分,它都会获取内容,将其转义,然后将其作为普通文本节点放回,或者将其与任一侧的任何文本节点“合并”。表示的文本是相同的,只是存储在文档中的方式不同;如果您导出回 XML,您可以看到差异,如下例所示:

$xml_string = "<person><name>Welcome aboard this <![CDATA[P&O Cruises]]> voyage!</name></person>";

$person = new SimpleXMLElement($xml_string);
echo 'CDATA retained: ', $person->asXML();
// CDATA retained: <?xml version="1.0"?>
// <person><name>Welcome aboard this <![CDATA[P&O Cruises]]> voyage!</name></person>

$person = new SimpleXMLElement($xml_string, LIBXML_NOCDATA);
echo 'CDATA merged: ', $person->asXML();
// CDATA merged: <?xml version="1.0"?>
// <person><name>Welcome aboard this P&amp;O Cruises voyage!</name></person>

如果您正在解析的 XML 文档包含一个实际包含实体的 CDATA 部分,则您需要获取该字符串并完全独立于 XML 将其取消转义。这样做的一个常见原因(除了懒惰对理解程度不高的库之外)是将 HTML 中标记的内容视为 XML 文档中的任何旧字符串,如下所示:

<Comment>
<SubmittedBy>IMSoP</SubmittedBy>
<Text><![CDATA[I'm <em>really</em> bad at keeping my answers brief <tt>;)</tt>]]></Text>
</Comment>
于 2012-12-20T23:02:16.313 回答