You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用SimpleXML保存XML时如何为所有节点重新添加CDATA?

问题

我通过以下PHP代码加载了一个较大的嵌套XML文件:

$content = simplexml_load_string(
    $xmlString, null, LIBXML_NOCDATA
);

现在需要把XML导出/保存为字符串时,给所有节点重新添加CDATA转义。

我原本尝试了下面的方法:

$xmlIterator = new RecursiveIteratorIterator(
    new SimpleXMLIterator($xml_string), 
    RecursiveIteratorIterator::SELF_FIRST
);
foreach ($xmlIterator as $nodeName => &$node) {
  $node->textContent = sprintf('<![CDATA[%s]]>', $node->textContent);
}

但这种方法无法通过引用直接更新节点,没法直接在XML树里添加CDATA内容。

解决方案

SimpleXML本身对CDATA的支持有限——它会自动将CDATA解析为普通文本,且无法直接创建CDATA节点。推荐转用DOMDocument处理,DOM可以直接操作CDATA节点,结合遍历逻辑就能实现需求:

方法1:SimpleXML转DOMDocument处理

先把SimpleXML对象转为DOM对象,再递归遍历所有节点,将文本内容替换为CDATA节点:

// 将SimpleXML对象转为DOMElement
$dom = dom_import_simplexml($content)->ownerDocument;

// 递归处理所有节点的文本内容
function replaceTextWithCDATA(\DOMNode $node) {
    if ($node->nodeType === XML_TEXT_NODE && trim($node->nodeValue) !== '') {
        $cdata = $node->ownerDocument->createCDATASection($node->nodeValue);
        $node->parentNode->replaceChild($cdata, $node);
    } elseif ($node->hasChildNodes()) {
        foreach (iterator_to_array($node->childNodes) as $child) {
            replaceTextWithCDATA($child);
        }
    }
}

replaceTextWithCDATA($dom->documentElement);

// 导出为带CDATA的XML字符串
$xmlWithCDATA = $dom->saveXML();

方法2:直接用DOMDocument加载XML

如果不需要保留SimpleXML的操作逻辑,也可以直接用DOMDocument加载XML后处理:

$dom = new DOMDocument();
// 加载时遵循原逻辑忽略CDATA,直接解析为文本
$dom->loadXML($xmlString, LIBXML_NOCDATA);

// 调用同上面的递归处理函数
replaceTextWithCDATA($dom->documentElement);

$xmlWithCDATA = $dom->saveXML();

注意事项

  • 处理时跳过空文本节点,避免生成多余的CDATA块
  • 如果节点文本包含]]>,需要先做转义(比如替换为]]]]><![CDATA[>),否则会导致CDATA被意外截断

内容的提问来源于stack exchange,提问作者gherkins

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 20:05:33