解决问题:使用 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 />";
}

参考资料

posted @ 2025-02-19 20:41  半山听雨  阅读(14)  评论(0)    收藏  举报