SimpleXML:处理节点值中存在的 CDATA 标记

SimpleXML: handle CDATA tag presence in node value

我在解析 XML 文档时需要保存 <![CDATA[]]> 标签。

比如我有节点:

<Dest><![CDATA[some text...]]></Dest>

在 xml 文件中可能存在没有 CDATA 的节点。

然后我循环处理所有节点:

$dom = simplexml_load_file($path);
foreach($dom->children() as $child) {
 $nodeValue = (string) $child;
}

因此,当我在上面的示例中处理节点时 - $nodeValue = some text...

但是我需要$nodeValue = <![CDATA[some text...]]>

有什么办法吗?

文件示例:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Root>
  <Params>
    <param>text</param>
    <anotherParam>text</anotherParam>
  </Params>
  <Content>
    <String>
      <Source>some another text</Source>
      <Dest>some another text 2</Dest>
    </String>
    <String>
      <Source>some another text 3</Source>
      <Dest><![CDATA[some text...]]></Dest>
    </String>
  </Content>
</Root>

如果您想将 CDATA 添加到所有没有 CDATA 的元素,您可以这样做:

$dom = simplexml_load_file($path);
foreach($dom->children() as $child) {
     if(strpos((string) $child,'CDATA')){
         $nodeValue = (string) $child)
     }
     else {
         $nodeValue = "<![CDATA[".((string) $child)."]]>";
     }
 }

这样你就可以 $nodeValue = '<![CDATA[some text...]]>'

如果你只想拥有有 CDATA 的元素,你可以这样做:

$dom = simplexml_load_file($path);
foreach($dom->children() as $child) {
     if(strpos((string) $child,'CDATA')){
         $nodeValue = (string) $child;
     }
 }

这样你就可以 $nodeValue = '<![CDATA[some text...]]>'

如果您想要没有 CDATA 的元素并添加它,您可以这样做:

$dom = simplexml_load_file($path);
foreach($dom->children() as $child) {
     if(!strpos((string) $child,'CDATA')){
         $notValue ="<![CDATA[".((string) $child)."]]>";
     }
 }

你将拥有 $nodeValue = '<![CDATA[some another text 3]]>'

就像 SimpleXML 这样的解析器而言,<![CDATA[ 不是 XML 元素的文本内容的一部分,它只是序列化的一部分内容。这里讨论了类似的混淆:PHP, SimpleXML, decoding entities in CDATA

您需要查看的是该元素的 "inner XML",这在 SimpleXML 中很棘手(->asXML() 会给您 "outer XML",例如 <Dest><![CDATA[some text...]]></Dest>).

这里最好的选择是使用 the DOM,这样您就可以更多地访问文档的详细 [​​=23=] 结构 ,而不是试图给您 content,所以区分"text nodes"和"CDATA nodes"。但是,值得仔细检查您是否确实需要它,对于 99.9% 的用例,您不应该关心是否有人向您发送 <foo>bar &amp; baz</foo><foo><![CDATA[bar & baz]]></foo>,因为根据定义它们代表相同字符串。