Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use XPath and DOM to replace a node/element in php?

Tags:

dom

php

xpath

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;

?>
like image 722
Haroldo Avatar asked Jan 06 '11 11:01

Haroldo


People also ask

Does XPath use DOM?

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.

What is a DOM XPath?

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.

How does XPath expression work?

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).


1 Answers

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>
');
like image 88
Gordon Avatar answered Sep 18 '22 17:09

Gordon