Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to insert new element after specific element in html using php?

I'm really struggling to get my head around DOMDocument parsing. I'm trying to solve the following problem. Given the following HTML

<h1>Title</h1>
<p>Some Content</p>
<p>Some More Content</p>
<p>Other Content</p>
<p>Last Bit of Content</p>

I want to add in a div with something else after the second paragraph tag. Essentially the outcome needs to be something like the following

<h1>Title</h1>
<p>Some Content</p>
<p>Some More Content</p>
<div>Something different</div> <!-- new tag -->
<p>Other Content</p>
<p>Last Bit of Content</p>

Having looked at a few post on here I'm now getting bored of scratching my head now.

like image 693
Shane Jones Avatar asked Oct 11 '16 18:10

Shane Jones


2 Answers

You need to use DOMDocument class to parsing string to html. After parsing html, select third p element and use DOMNode::insertBefore to insert new element after it.

$doc = new DOMDocument();
$doc->loadHTML($html);
// find 3th p tag
$p = $doc->getElementsByTagName("p")->item(2);
// create new div tag
$div = $doc->createElement("div", "Something different"); 
// insert created element after 3th p
$p->parentNode->insertBefore($div, $p); 
$html = $doc->saveHTML();
like image 79
Mohammad Avatar answered Oct 18 '22 08:10

Mohammad


In complement to @Mohammad answer (that is perfectly correct), if you want to find precisely the second p tag after an h1 tag and at the same level, you can use the XPath query //h1/following-sibling::p[2]. Example:

$html = <<<'EOD'
<h1>Title</h1>
<p>Some Content</p>
<p>Some More Content</p>
<p>Other Content</p>
<p>Last Bit of Content</p>
EOD;

libxml_use_internal_errors(true);

$dom = new DOMDocument;
$dom->loadHTML('<div>' . $html . '</div>', LIBXML_HTML_NOIMPLIED);

libxml_clear_errors();

$xp = new DOMXPath($dom);

$targetNode = $xp->query('//h1/following-sibling::p[2]');

if ($targetNode->length) {
    $targetNode = $targetNode->item(0);
    $newNode = $dom->createElement('div', 'something different');
    $targetNode->parentNode->insertBefore($newNode, $targetNode->nextSibling);
    $targetNode->parentNode->insertBefore($dom->createTextNode("\n"), $targetNode->nextSibling);
}

$result = '';
foreach ($dom->documentElement->childNodes as $childNode) {
    $result .= $dom->saveHTML($childNode);
}
echo $result;
like image 36
Casimir et Hippolyte Avatar answered Oct 18 '22 08:10

Casimir et Hippolyte