
本文介绍使用 PHP 的 DOMDocument 和 DOMXPath 解析嵌套 XML,精准提取指定窗口(如 name="feedback")内 与 节点,并严格按文档顺序合并为单个结构化数组,解决 SimpleXML 无法保留节点顺序与混合类型的问题。
本文介绍使用 php 的 domdocument 和 domxpath 解析嵌套 xml,精准提取指定窗口(如 name="feedback")内 `
在处理类似教育平台导出的 TDX 格式 XML 时,常需解析 <window name="feedback"></window> 下 <rvxml><document></document></rvxml> 内交错出现的 <text></text> 和 <control></control> 节点,并保持其原始 DOM 顺序(例如:text → control → text → control…)。SimpleXML 因其扁平化设计,会将同名节点自动归组为数组(如 ['text' => [...], 'control' => [...]]),天然丢失节点间的相对位置关系,因此无法满足本需求。
正确方案是使用 DOMDocument + DOMXPath——它能精确遍历子节点树,按实际 XML 文档顺序逐个访问每个元素节点,不受标签名称影响。
✅ 推荐实现(完整可运行代码)
<?php $xmlDocument = '<?xml version="1.0" encoding="UTF-8"?><tdx version="1.0"><windows><window name="feedback"><step name="wrong1"><rvxml><document stringtags="0"><text>Usa enteros en una recta num</text><text>Use Impy</text><control>F3</control><text br="0">rica para representar la situaci</text><control>F1</control><text br="0">n. Decide qu</text><control>F3</control><text br="0"> quiere decir la palabra clave "gast</text><control>F1</control><text br="0">".</text></document></rvxml></step></window></windows></tdx>';
// 1. 加载 XML 并初始化 XPath
$dom = new DOMDocument();
$dom->loadXML($xmlDocument);
$xpath = new DOMXPath($dom);
// 2. 使用 XPath 精准定位:获取 feedback 窗口下 document 内所有子元素(text/control)
$nodes = $xpath->evaluate('//window[@name="feedback"]/step/rvxml/document/*');
// 3. 按文档顺序遍历,构建结构化数组
$result = [];
foreach ($nodes as $node) {
$result[] = [
'type' => $node->localName, // "text" 或 "control"
'value' => trim($node->textContent), // 自动解码 HTML 实体(如 " → ")
'raw' => $node->nodeName, // 可选:保留原始 nodeName(含命名空间前缀)
'attrs' => [] // 可扩展:遍历 $node->attributes 获取属性
];
}
// 输出结果(符合预期顺序)
print_r($result);
?>
? 输出示例(关键片段)
Array
(
[0] => Array ( [type] => text [value] => Usa enteros en una recta num )
[1] => Array ( [type] => text [value] => Use Impy )
[2] => Array ( [type] => control [value] => F3 )
[3] => Array ( [type] => text [value] => rica para representar la situaci )
[4] => Array ( [type] => control [value] => F1 )
// ... 后续严格按 XML 中出现顺序排列
)
⚠️ 注意事项与最佳实践
-
不要用
simplexml_load_string():它无法保证text/control的混排顺序,且对空文本、属性、HTML 实体处理较弱; -
XPath 表达式要精确:
//window[@name="feedback"]/step/rvxml/document/*中的*匹配任意子元素,确保不遗漏任何节点类型; -
textContent自动处理实体:DOM 会自动解码"、"等,无需额外html_entity_decode(); -
若需区分不同
<text></text>属性(如br="0"):可在循环中添加:'attrs' => array_map( fn($attr) => [$attr->name => $attr->value], iterator_to_array($node->attributes) ), -
性能提示:对于超大 XML,可结合
LIBXML_NOBLANKS提升加载效率:$dom->loadXML($xml, LIBXML_NOBLANKS);
✅ 总结
当 XML 结构包含同级混合标签且顺序敏感(如教学内容中的富文本流),DOM 是唯一可靠选择。通过 XPath 定位 + 节点遍历,你不仅能获得顺序正确的扁平化数组,还能灵活扩展字段(如属性、命名空间、父子上下文),为后续渲染、校验或转换提供坚实基础。










