解决问题:使用 PHP DOM 类库时,DOMNodeList 对象的 length 值不准确
问题
使用 PHP DOM 解析 html,明明一个 div 下面只有 4 个子级 div,通过 $nodeList->length 获取子级元素的个数,返回值却是 9!
通过 $nodeList->item(0) 获取到的也不是想要的第一个 div 元素。
原因
在 DOM 中,「空格」和「换行符号」会被解析成「空白节点」。两个 div 中间插入一个空格或者换行,$nodeList->length 的值就会变成3,首尾各自再加一个换行,就会变成5.
示例代码
注意,这里用到了 PHP 8.4 中新增的方法 querySelector() 获取目标节点。低版本中,需要使用其他方法,比如 DOMXPath 类中的方法 query()。
<?php
// -----------------------------------------------------------------------------
use DOM\HTMLDocument;
// -----------------------------------------------------------------------------
$htmlStrOne = <<<BBB
<html>
<body>
<ul>
<li>line one</li>
<li>line two</li>
<li>line three</li>
<li>line four</li>
</ul>
</body>
</html>
BBB;
$htmlStrTwo = <<<BBB
<html>
<body>
<ul><li>line one</li><li>line two</li><li>line three</li><li>line four</li></ul>
</body>
</html>
BBB;
// -----------------------------------------------------------------------------
@$domOne = HTMLDocument::createFromString($htmlStrOne);
@$domTwo = HTMLDocument::createFromString($htmlStrTwo);
// -----------------------------------------------------------------------------
$ulOne = $domOne->querySelector('ul'); // return a DOMElement
$ulTwo = $domTwo->querySelector('ul'); // return a DOMElement
echo $ulOne->childNodes->length; // return 9
echo "<br />";
echo $ulTwo->childNodes->length; // return 4
解决办法
写一个函数,移除 DOMNodeList 中的空白节点。
什么样的节点是空白节点呢?经过测试,结论是,nodeType 的值为 XML_TEXT_NODE。
以下这个函数,可以移除 DOMNodeList 中的空白节点:
/**
* @param $nodeList
* @return $nodeList
*/
function removeEmptyNodeInNodeList($nodeList)
{
foreach ($nodeList as $node) {
if ($node->nodeType == XML_TEXT_NODE) {
$node->parentNode->removeChild($node);
}
}
return $nodeList;
}
使用方法:
$ulOne = $domOne->querySelector('ul'); // return a DOMElement
$nodes = removeEmptyNodeInNodeList($ulOne->childNodes); // 调用的时候要注意,不能直接传入 DOMElement
foreach ($nodes as $node) {
echo $node->nodeType;
echo "<br />";
}

浙公网安备 33010602011771号