
本文详解如何使用 php 的 domdocument + domxpath 高效解析含 cdata 的 xml(如 sitemap),绕过 `#cdata-section` 节点干扰,直接获取纯净文本值,并提供可落地的代码示例与关键注意事项。
在 PHP 中处理 XML 时,DOMDocument 是最常用且可靠的原生方案。但当 XML 中包含 片段(如 Sitemap 中的
根本原因在于:CDATA 并非独立“值容器”,而是 DOM 树中的一个特殊节点类型;它常与前后空白文本节点并存(例如换行与缩进)。手动遍历子节点时,若未过滤空白或未合并相邻文本/CData 内容,就会丢失实际数据。
✅ 推荐方案:弃用通用递归转数组,改用 DOMXPath 精准定位 + string() 函数提取
DOMXPath 的 string() 函数会自动合并目标节点下所有文本类子节点(包括 XML_TEXT_NODE 和 XML_CDATA_SECTION_NODE)的内容,并去除首尾空白,返回纯净字符串——这正是我们所需。
立即学习“PHP免费学习笔记(深入)”;
以下为完整、健壮的实现:
XML; $document = new DOMDocument(); $document->loadXML($xml); // 关键:注册命名空间前缀(因 XML 使用默认命名空间) $xpath = new DOMXPath($document); $xpath->registerNamespace('map', 'http://www.sitemaps.org/schemas/sitemap/0.9'); $sitemaps = []; // 使用 XPath 定位所有 sitemap 元素(支持多条目) foreach ($xpath->evaluate('//map:sitemap') as $sitemap) { $sitemaps[] = [ 'loc' => trim($xpath->evaluate('string(map:loc)', $sitemap)), 'lastmod' => trim($xpath->evaluate('string(map:lastmod)', $sitemap)) ]; } var_dump($sitemaps); // 输出: // array(1) { // [0] => array(2) { // ["loc"] => string(39) "https://www.blablal.id/news/sitemap.xml" // ["lastmod"] => string(25) "2022-02-02T12:21:02+07:00" // } // } https://www.blablal.id/news/sitemap.xml
? 关键要点说明:
- 必须注册命名空间:XML 中 xmlns="..." 是默认命名空间,XPath 查询时需显式绑定前缀(如 'map'),否则 //sitemap 将匹配失败;
-
string() 函数是核心:string(map:lastmod) 自动提取
下所有文本内容(含 CDATA),无需手动判断节点类型; - trim() 不可省略:CDATA 内部可能含空格/换行,string() 不自动裁剪,需显式 trim() 保证格式统一;
- 避免 preserveWhiteSpace = false 的陷阱:虽可减少空白节点,但无法解决 CDATA 解析逻辑缺陷,且可能误删有意义的空白,故不推荐作为主方案。
? 延伸建议:
- 若需处理大量 XML 或复杂结构,可封装为复用函数,支持自定义命名空间映射与字段映射规则;
- 对于无命名空间的简单 XML,XPath 表达式可简化为 //sitemap 和 ./loc;
- 生产环境务必添加错误处理:检查 $document->loadXML() 返回值、$xpath->evaluate() 是否返回有效节点列表。
此方法简洁、高效、符合 XML 处理最佳实践,彻底规避了手工遍历 DOM 树时对节点类型和空白处理的繁琐逻辑,是解析含 CDATA 的标准 XML(如 Sitemap、RSS、SOAP 响应)的首选方案。











