Matthew Price Matthew Price - 1 month ago 8
HTML Question

PHP DOM HTML table manipulation

I'm trying to figure out why this piece of code isn't working. It takes HTML from another part of the code, takes the table out of it, creates another column and tries to move a td element to the row above in the newly created column.

The table imported:

+-------------------+-------------------+-------------------+
| Existing column1 | Existing column2 | Existing column3 |
+-------------------+-------------------+-------------------+
| A | B | C |
| D | E | F |
| G |
+-------------------+-------------------+-------------------+


I want to try and make it look like this:

+-------------------+-------------------+-------------------+-------------+
| Existing column1 | Existing column2 | Existing column3 | New column1 |
+-------------------+-------------------+-------------------+-------------+
| A | B | C | |
| D | E | F | G |
+-------------------+-------------------+-------------------+-------------+


So whenever a
td
element has the class
text-info
, it moves it up a
tr
and appends it to the last
Comment
column

My code so far:

$dom = new DOMDocument();//Loads DOM document
$dom->loadHTML($str);//Loads HTML from a previously set variable
$xpath = new DOMXPath($dom);
$tables = $xpath->query('//table[@class="behaviourtable table"]');//Get only table from HTML
$commsTable = '';
foreach ($tables as $table) {
$commsTable .= $dom->saveXML($table);
}

$commsHTML = new DOMDocument();
$commsHTML->loadHTML($commsTable);

$tr = $commsHTML->getElementsByTagName('tr');


$th = $commsHTML->createElement('th', 'Comment');
$tr->item(0)->appendChild($th);

$xpathcomms = new DOMXPath($commsHTML);
$comments = $xpathcomms->query('//td[@class="text-info"]');
if($comments->length > 0){
echo "if running";
foreach($comments as $comment){
$parent = $comment->parentNode;
$parent->appendChild($comment);
$commsHTML->saveXML($parent);
}

}


echo $commsHTML->saveHTML();

Answer

In your code you append the td to it's original parent node (which does nothing), while what you are actually wanna do is get the parent (tr), go to it's previous sibling (prev tr) and append the td to that tr:

foreach($comments as $comment){
    $parent = $comment->parentNode;
    $parent->previousSibling->appendChild($comment);
}

Here is a complete working example:

$str = <<<END
<table class="behaviourtable table">
    <tr>
        <th>Existing column1</th>
        <th>Existing column2</th>
        <th>Existing column3</th>
    </tr><tr>
        <td>A</td>
        <td>B</td>
        <td>C</td>
    </tr><tr>
        <td>D</td>
        <td>E</td>
        <td>F</td>
    </tr><tr>
        <td class="text-info">G</td>
    </tr>
</table>
END;

$dom = new DOMDocument();//Loads DOM document
$dom->loadHTML($str);//Loads HTML from a previously set variable
$xpath = new DOMXPath($dom);
$tables = $xpath->query('//table[@class="behaviourtable table"]');//Get only table from HTML
$commsTable = '';
foreach ($tables as $table) {
    $commsTable .=  $dom->saveXML($table);
}

$commsHTML = new DOMDocument();
$commsHTML->loadHTML($commsTable);

$tr = $commsHTML->getElementsByTagName('tr');


$th = $commsHTML->createElement('th', 'Comment');
$tr->item(0)->appendChild($th);

$xpathcomms = new DOMXPath($commsHTML);
$comments = $xpathcomms->query('//td[@class="text-info"]');
if($comments->length > 0){
    foreach($comments as $comment){
        $parent = $comment->parentNode;
        $parent->previousSibling->appendChild($comment);
    }
}

echo $commsHTML->saveHTML();

Check this working example:
https://3v4l.org/FZkNE