Say I have the following html
$html = '
<div class="website">
<div>
<div id="old_div">
<p>some text</p>
<p>some text</p>
<p>some text</p>
<p>some text</p>
<div class="a class">
<p>some text</p>
<p>some text</p>
</div>
</div>
<div id="another_div"></div>
</div>
</div>
';
And I want to replace #old_div
with the following:
$replacement = '<div id="new_div">this is new</div>';
To give an end result of:
$html = '
<div class="website">
<div>
<div id="new_div">this is new</div>
<div id="another_div"></div>
</div>
</div>
';
Is there an easy cut-and-paste function for doing this with PHP?
Final working code thanks to all Gordon's help:
<?php
$html = <<< HTML
<div class="website">
<div>
<div id="old_div">
<p>some text</p>
<p>some text</p>
<p>some text</p>
<p>some text</p>
<div class="a class">
<p>some text</p>
<p>some text</p>
</div>
</div>
<div id="another_div"></div>
</div>
</div>
HTML;
$dom = new DOMDocument;
$dom->loadXml($html); // use loadHTML if it's invalid XHTML
//create replacement
$replacement = $dom->createDocumentFragment();
$replacement ->appendXML('<div id="new_div">this is new</div>');
//make replacement
$xp = new DOMXPath($dom);
$oldNode = $xp->query('//div[@id="old_div"]')->item(0);
$oldNode->parentNode->replaceChild($replacement , $oldNode);
//save html output
$new_html = $dom->saveXml($dom->documentElement);
echo $new_html;
?>
The XPath DOM extends the document order of the DOM Core to include the XPathNamespace nodes. Element nodes occur before their children. The attribute nodes and namespace nodes of an element occur before the children of the element. The namespace nodes are defined to occur before the attribute nodes.
DOM and XPath are different concepts. DOM (Document Object Model) is a representation of a document or document fragment consisting of XML nodes arranged as a tree. XPath is a syntax for expressing a navigation through a DOM to locate one or more nodes. The name DOMXPath in PHP is somewhat redundant.
In general, an XPath expression specifies a pattern that selects a set of XML nodes. XSLT templates then use those patterns when applying transformations. (XPointer, on the other hand, adds mechanisms for defining a point or a range so that XPath expressions can be used for addressing).
Since the answer in the linked duplicate is not that comprehensive, I'll give an example:
$dom = new DOMDocument;
$dom->loadXml($html); // use loadHTML if its invalid (X)HTML
// create the new element
$newNode = $dom->createElement('div', 'this is new');
$newNode->setAttribute('id', 'new_div');
// fetch and replace the old element
$oldNode = $dom->getElementById('old_div');
$oldNode->parentNode->replaceChild($newNode, $oldNode);
// print xml
echo $dom->saveXml($dom->documentElement);
Technically, you don't need XPath for this. However, it can happen that your version of libxml cannot do getElementById
for non-validated documents (id attributes are special in XML). In that case, replace the call to getElementById
with
$xp = new DOMXPath($dom);
$oldNode = $xp->query('//div[@id="old_div"]')->item(0);
Demo on codepad
To create a $newNode
with child nodes without having to to create and append elements one by one, you can do
$newNode = $dom->createDocumentFragment();
$newNode->appendXML('
<div id="new_div">
<p>some other text</p>
<p>some other text</p>
<p>some other text</p>
<p>some other text</p>
</div>
');
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With