使用PHP SimpleXML判断XML节点文本与子节点的先后顺序
问题原因
SimpleXML 原生设计没有保留混合内容(文本+子元素并存)的节点排列顺序,它会将父节点的直接文本内容和子元素分开存储,因此无法通过 SimpleXMLElement 的原生属性判断二者的先后顺序。
实现方案
你可以配合 PHP 内置的 DOM 扩展实现需求,DOM 扩展完整保留了 XML 节点的实际排列顺序,且可以通过 dom_import_simplexml() 方法和 SimpleXMLElement 无缝转换,无需重写已有逻辑。
完整顺序输出示例代码
<?php $xml = <<<XML <?xml version='1.0' standalone='yes'?> <data> <p> Hello <em>World!</em> </p> <p> <em>Hello </em> World! </p> </data> XML; $sx = new SimpleXMLElement($xml); foreach($sx->children() as $p) { // 转换SimpleXML节点为DOM节点 $domP = dom_import_simplexml($p); $content = ''; // 按XML中的实际顺序遍历所有子节点 foreach ($domP->childNodes as $node) { if ($node->nodeType === XML_TEXT_NODE) { // 处理文本节点,过滤空白内容 $text = trim($node->nodeValue); $content .= $text ? $text : ''; } elseif ($node->nodeType === XML_ELEMENT_NODE) { // 处理子元素节点 $content .= trim($node->nodeValue); } } echo $content . PHP_EOL; }
运行输出:
HelloWorld! HelloWorld!
先后顺序判断示例代码
如果仅需要判断自身文本和子节点的先后关系,可使用如下逻辑:
foreach($sx->children() as $idx => $p) { $domP = dom_import_simplexml($p); $firstNodeType = null; foreach ($domP->childNodes as $node) { // 跳过无意义的空白文本节点 if ($node->nodeType === XML_TEXT_NODE && trim($node->nodeValue) === '') { continue; } $firstNodeType = $node->nodeType; break; } if ($firstNodeType === XML_TEXT_NODE) { echo "第{$idx}个p节点:自身文本在子节点之前" . PHP_EOL; } elseif ($firstNodeType === XML_ELEMENT_NODE) { echo "第{$idx}个p节点:子节点在自身文本之前" . PHP_EOL; } }
运行输出:
第0个p节点:自身文本在子节点之前 第1个p节点:子节点在自身文本之前
内容的提问来源于stack exchange,提问作者T-Regex
相关产品推荐
相关产品推荐

