【问题标题】:Creating a New Column in Existing HTML Table using DOMDocument使用 DOMDocument 在现有 HTML 表中创建新列
【发布时间】:2018-05-30 14:41:44
【问题描述】:

尝试使用 DOMDocument 和 DOMXpath 在现有表中创建新列

$doc = new DOMDocument();
$doc->loadHTMLFile("example.html");

以下是位于example.html 中的表的结构:

<table id="transactions" class="table">
    <thead>
        <tr>
            <th class="image"></th>
            <th class="title"><span>Title</span></th>
        </tr>
    </thead>
    <tbody>
        <tr id="tbody-tr">
            <td class="image">
                <img src="http://www.example.com/image.jpg">
            </td>
            <td class="title">Title
            </td>
            <td class="date">12/16/2017
            </td>
        </tr>
        <tr id="tbody-tr">
            <td class="image">
                <img src="http://www.example.com/image.jpg">
            </td>
            <td class="title">Title
            </td>
            <td class="date">12/16/2017
            </td>
        </tr>
    </tbody>
</table>

在这种情况下,表的 xpath 查询将是

$table =  $xpath->query('//*[@id="transactions"]');

对于&lt;tr id="tbody-tr"&gt; 元素

$tr = $xpath->query('/*[@id="tbody-tr"]');

对于&lt;td&gt; 行元素 -- /td[1] /td[2] /td[3]

$td = $xpath->query('//*[@id="tbody-tr"]/td[3]');

我正在尝试在&lt;td class="title"&gt;&lt;td class="date"&gt; 之间为&lt;tr id="tbody-tr"&gt; 的所有实例创建一个额外的列(&lt;td class="example"&gt;&lt;/td&gt;)(大约有50 个,但为了这个问题而缩小了)。

我是 DOMDocument 和 HTML 解析操作的新手,并且正在努力弄清楚如何做到这一点。

我假设我要么必须使用我的 xpath-&gt;query 循环它,比如

foreach ($ttrows as $row) {
    $td = $doc->createElement('td');
    $parent = $row->parentNode;
    $parent->appendChild($row);
    $td->setAttribute('class','example');
}

或使用 DOMDocuments getElementById 或类似的东西。

foreach ($table = $doc->getElementById('tbody-tr') as $table) {
    $td = $doc->createElement('td');
    $td->setAttribute('class', 'example');
    $td->appendChild($table);
    $table->insertBefore($td, $table);
}

正如我所说,我是 DOMDocument 的新手,所以这两个示例实际上都没有做任何事情。但我认为我正朝着正确的方向前进(我希望如此)。

我相信,该表的结构相当好,可以在 DOMDocument 中执行类似的操作。有人可以解释一下吗,我的尝试和错误让我没有什么结果。

解决方案:

foreach ($td as $row) {
    $td = $doc->createElement('td', 'text to be inserted');
    $td->setAttribute('class','example');
    $row->parentNode->insertBefore($td, $row);
}

请注意以上

$td = $xpath->query('//*[@id="tbody-tr"]/td[3]');

是第三个&lt;td&gt;date

【问题讨论】:

  • insertBefore 是正确的,但不需要appendChild。只需要在insertBefore 中的第二个参数上获得正确的引用...这是棘手的部分,因为您必须引用&lt;td class="date"&gt;。嗯……
  • 你是对的。我想到了!马上查看编辑。
  • 有趣的解决方案。如果我理解正确的话。 ...但是匹配id= 而不是class= 是否正确?无论如何,从长远来看,@Lawrence 的解决方案可能会更好地使用。我认为它更易于跟踪和编辑?

标签: php dom xpath domdocument domxpath


【解决方案1】:

请记住,您不能/不应该在同一页面上有多个 id。

那就用$tr-&gt;insertBefore($td, $tr-&gt;childNodes-&gt;item(3));

这意味着,当前节点在第三个 td 之前插入新的 dom 节点。

<?php
foreach ($doc->getElementsByTagName('tr') as $tr) {
    $td = $doc->createElement('td');
    $td->setAttribute('class', 'example');

    $tr->insertBefore($td, $tr->childNodes->item(3));
}

https://3v4l.org/TthE7

另外需要考虑的是添加thead &gt; th 否则会破坏表格的外观。

foreach ($doc->getElementsByTagName('tr') as $tr) {

    // insert into thead > th
    if ($tr->childNodes->item(0)->nodeName == 'th') {
        $th = $doc->createElement('th');
        $th->setAttribute('class', 'example');
        $th->nodeValue = 'Example';
        $tr->insertBefore($th, $tr->childNodes->item(3));
    } 
    // insert into body > td
    else {
        $td = $doc->createElement('td');
        $td->setAttribute('class', 'example');

        $tr->insertBefore($td, $tr->childNodes->item(3));
    }
}

https://3v4l.org/1sj7s

【讨论】: