Search code examples
phpxmlxpath

Removing nodes in XML with XPath and PHP


I have an XML:

<root>
   <level name="main">
      <level name="sub_1">
         <content id="abc123" />
      </level>
   </level>
</root>

I would like to search for the node with id that is abc123 and delete the <content> and its parent <level>

So the end result would be:

<root>
  <level name="main">
  </level> 
</root>

I have tried this in PHP without result, what am I doing wrong?

 $doc = new DOMDocument;
 $doc->loadxml($xml_from_file); 
 $xpath = new DOMXPath($doc);
 $node_list = $xpath->query("content[@id='abc123']/parent::*"); 
 $node = $node_list->item(0); 
 $doc->removeChild($node);

Solution

  • Here are two issues with your source.

    The expression does only match child nodes. You need to start it with // to match any node: //content[@id='abc123']/parent::*.

    The found node is not a child of the document so, you need to remove it from its own parent: $node->parentNode->removeChild($node);.

    I suggest using a foreach to avoid problems if the node doesn't exists.

    $document = new DOMDocument;
    $document->loadxml($xmlString); 
    $xpath = new DOMXPath($document);
    
    foreach ($xpath->evaluate("//content[@id='abc123']/parent::*") as $node) {
      $node->parentNode->removeChild($node);
    }
    
    echo $document->saveXml();
    

    Edit: PHP 8 got several new DOM standard methods. One of them is remove():

    $document = new DOMDocument;
    $document->loadxml($xmlString); 
    $xpath = new DOMXPath($document);
    
    foreach ($xpath->evaluate("//content[@id='abc123']/parent::*") as $node) {
      // new shortcut method
      $node->remove();
    }
    
    echo $document->saveXml();