如何使用PHP DOMXPath按元素类型与data属性查找子节点?
问题根源
你得到重复结果的核心是对DOMXPath的路径规则存在误解:
只要XPath表达式以
/开头(无论单斜杠还是双斜杠),就属于绝对路径查询,此时哪怕给query()方法传入了第二个上下文节点参数,DOMXPath也会完全忽略该参数,直接从整个HTML文档的根节点开始全局匹配。
你代码中写的$finder->query('//input/@data-check', $c)是典型的绝对路径写法,因此无论传入的上下文节点$c在DOM树的哪个位置,查询返回的永远是整个文档里第一个匹配input[data-check]的节点值(也就是第一个计算块对应的4),循环两次自然会得到两个4的结果。
修正后的可运行代码
完全不需要手动嵌套遍历childNodes逐层查找子元素,直接用XPath的相对路径做范围限定即可,逻辑更简洁也更准确:
// 直接定位所有带data-title属性的目标div节点,而非仅取出属性值 $q_titles = $finder->query('//div[@data-title]'); foreach($q_titles as $targetDiv) { $qtitle = $targetDiv->getAttribute('data-title'); $nr = $targetDiv->getAttribute('data-nr'); // 基于当前循环到的targetDiv作为上下文,用.//表示在当前节点的后代范围内匹配 $inputRes = $finder->query('.//input/@data-check', $targetDiv); if ($inputRes->length > 0) { $solution = $inputRes[0]->nodeValue; } }
关键注意事项
- XPath中的
.代表当前传入的上下文节点,.//的含义是“在当前节点的所有后代层级中查找匹配元素”,不会触发全局文档查询 - 只要XPath表达式以
/开头,传入的上下文参数就会失效,这是DOMXPath使用中非常常见的踩坑点 - 手动遍历
childNodes的写法不仅需要额外过滤文本节点、注释节点等无关DOM内容,执行效率也远低于XPath的范围查询,能通过XPath路径实现的逻辑,尽量不要手动嵌套循环遍历DOM树
内容的提问来源于stack exchange,提问作者Avatar
相关产品推荐
相关产品推荐

