You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP DOMDocument解析HTML时首个table闭合标签失效致嵌套问题

PHP DOMDocument处理多表格HTML的坑及解决办法

问题场景

做HTML转CSV工具时碰到个怪事:用DOMDocument解析多个独立表格的HTML,输出结果重复了后面两个表格的内容。

测试代码

$html = <<<HTML
<table>
<tr><td>A</td><td>Rose</td></tr>
</table>

<h1>Leave me behind</h1>

<table>
<tr><td>By</td><td>Any</td></tr>
</table>

<table>
<tr><td>Other</td><td>Name</td></tr>
</table>
HTML;

$dom = new \DOMDocument();
$dom->loadHTML($html, LIBXML_HTML_NODEFDTD | LIBXML_HTML_NOIMPLIED);

foreach ($dom->getElementsByTagName('table') as $table) {
    foreach ($table->getElementsByTagName('tr') as $row) {
        echo trim($row->nodeValue) . PHP_EOL;
    }
}

预期 vs 实际输出

预期输出:

ARose
ByAny
OtherName

实际输出:

ARose
ByAny
OtherName
ByAny
OtherName

哪怕把第一个<table>的闭合标签删掉,结果还是一样——明显DOMDocument把后面两个表格错误嵌套进第一个表格里了。

问题根源

  1. getElementsByTagName是递归查询:这个方法会把当前节点下所有层级的目标标签都找出来,不是只找直接子元素。当后面两个表格被嵌套进第一个后,遍历第一个表格时,会把三个表格的<tr>全捞出来。
  2. HTML解析的容错特性:LIBXML的HTML解析器为了兼容不规范HTML,会自动调整DOM结构,这里就出现了非预期的节点嵌套,把独立的表格塞到了第一个里面。

解决办法

用XPath精准查询当前表格的直接子元素<tr>,不要递归查所有后代。代码改成这样:

$xpath = new \DOMXPath($dom);

foreach ($dom->getElementsByTagName('table') as $table) {
    foreach ($xpath->query('./tr', $table) as $row) {
        echo trim($row->nodeValue) . PHP_EOL;
    }
}

XPath的./tr只找当前表格节点的直接子节点里的<tr>,不会管嵌套在后代表格里的行,完美避开解析器的结构错误,输出就正常了。


内容的提问来源于stack exchange,提问作者tvanc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 03:52:37