Milos Cuculovic
Milos Cuculovic

Reputation: 20223

PHP DomDocument - How to replace a text from a Node with another node

I have a node:

<p>
    This is a test node with Figure 1.
</p>

My goal is to replace "Figure 1" with a child node:

<xref>Figure 1</xref>

So that the final result will be:

<p>
    This is a test node with <xref>Figure 1</xref>.
</p>

Thank you in advance.

Upvotes: 0

Views: 1656

Answers (2)

ThW
ThW

Reputation: 19492

Xpath allows you to fetch the text nodes containing the string from the document. Then you have to split it into a list of text and element (xref) nodes and insert that nodes before the text node. Last remove the original text node.

$xml = <<<'XML'
<p>
    This is a test node with Figure 1.
</p>
XML;
$string = 'Figure 1';

$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXpath($dom);

// find text nodes that contain the string
$nodes = $xpath->evaluate('//text()[contains(., "'.$string.'")]');
foreach ($nodes as $node) {
  // explode the text at the string
  $parts = explode($string, $node->nodeValue);
  // add a new text node with the first part
  $node->parentNode->insertBefore(
    $dom->createTextNode(
      // fetch and remove the first part from the list
      array_shift($parts)
    ),
    $node
  );
  // if here are more then one part
  foreach ($parts as $part) {
    // add a xref before it
    $node->parentNode->insertBefore(
      $xref = $dom->createElement('xref'),
      $node
    );
    // with the string that we used to split the text
    $xref->appendChild($dom->createTextNode($string));
    // add the part from the list as new text node
    $node->parentNode->insertBefore(
      $dom->createTextNode($part), 
      $node
    );
  }
  // remove the old text node
  $node->parentNode->removeChild($node);
} 

echo $dom->saveXml($dom->documentElement);

Output:

<p>
    This is a test node with <xref>Figure 1</xref>.
</p>

Upvotes: 2

Amal Murali
Amal Murali

Reputation: 76656

You can first use getElementsByTagName() to find the node you're looking for and remove the search text from the nodeValue of that node. Now, create the new node, set the nodeValue as the search text and append the new node to the main node:

<?php

$dom = new DOMDocument;
$dom->loadHTML('<p>This is a test node with Figure 1</p>');

$searchFor = 'Figure 1';

// replace the searchterm in given paragraph node
$p_node = $dom->getElementsByTagName("p")->item(0);
$p_node->nodeValue = str_replace($searchFor, '', $p_node->nodeValue);

// create the new element
$new_node = $dom->createElement("xref");
$new_node->nodeValue = $searchFor;

// append the child element to paragraph node
$p_node->appendChild($new_node);

echo $dom->saveHTML();

Output:

<p>This is a test node with <xref>Figure 1</xref></p>

Demo.

Upvotes: 1

Related Questions