PHP DOMDocument 忽略第一个表的结束标记

问题描述 投票:0回答:1

我正在编写一个将 HTML 表格转换为 CSV 的工具,我注意到一些奇怪的行为。鉴于此代码

$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();
\libxml_use_internal_errors(true);
$dom->loadHTML($html, LIBXML_HTML_NODEFDTD | LIBXML_HTML_NOIMPLIED);
\libxml_clear_errors();

$tables = $dom->getElementsByTagName('table');
$stream = \fopen('php://output', 'w+');

for ($i = 0; $i < $tables->length; ++$i) {
    $rows = $tables->item($i)->getElementsByTagName('tr');

    for ($j = 0; $j < $rows->length; ++$j) {
        echo trim($rows->item($j)->nodeValue) . PHP_EOL;
    }
}

\fclose($stream);

我期望这样的输出:

ARose
ByAny
OtherName

但是我得到的是这样的:

ARose
ByAny
OtherName
ByAny
OtherName

如果省略第一个结束标签,我会得到相同的结果。看来 DOMDocument 将第二个和第三个

<table>
嵌套在第一个中。

事实上,如果我使用 xpath 仅从每个表中获取直接子项,我会得到正确的输出:

$xpath = new \DOMXPath($dom);

for ($i = 0; $i < $tables->length; ++$i) {
    $rows = $xpath->query('./tr', $tables->item($i));

    for ($j = 0; $j < $rows->length; ++$j) {
        echo trim($rows->item($j)->nodeValue) . PHP_EOL;
    }
}
php xml xpath domdocument
1个回答
0
投票

您发布的第一个代码中的 DOMDocument 没有任何问题,它已经忠实地处理了您的 $html

请注意,您将循环遍历所有表,然后为每个表显示节点值

因此,如果您想知道实际发生了什么,请使用以下内容

<?php
$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();
\libxml_use_internal_errors(true);
$dom->loadHTML($html, LIBXML_HTML_NODEFDTD | LIBXML_HTML_NOIMPLIED);
\libxml_clear_errors();

$tables = $dom->getElementsByTagName('table');
$stream = \fopen('php://output', 'w+');

for ($i = 0; $i < $tables->length; ++$i) {
    $rows = $tables->item($i)->getElementsByTagName('tr');

echo "Now for table " . $i ."<br>" ; 
    for ($j = 0; $j < $rows->length; ++$j) {
        echo trim($rows->item($j)->nodeValue) . "<br>";
    }
echo "<hr>";
}

fclose($stream);

?>
© www.soinside.com 2019 - 2024. All rights reserved.