Laguna Seca
Laguna Seca

Reputation: 33

Unable to remove all children from the XML document (PHP)

Unable to remove all children from the XML document

<?xml version="1.0" encoding="UTF-8"?>
    <routes>
      <route name="admin" />
      <!---->
      <route name="blog" bla bla/>
      <route name="blog" bla bla/>
      <route name="blog" bla bla/>
    </routes>

$xml = simplexml_load_file('routes.xml');

$dom_sxe = dom_import_simplexml($xml); $dom = new \DOMDocument('1.0'); $dom_sxe = $dom->importNode($dom_sxe, true); $dom_sxe = $dom->appendChild($dom_sxe); foreach ($dom->getElementsByTagName('route') as $route) { if($route->getAttribute('name') === 'blog') { $route->parentNode->removeChild($route); echo $route->getAttribute('name'); } } echo $dom->saveXML();

removes only 2 elements with the attribute blog

Upvotes: 1

Views: 74

Answers (1)

IMSoP
IMSoP

Reputation: 97718

The problem is that you are modifying the document while looping through it - a bit like modifying an array in the middle of a foreach loop.

Note that $dom->getElementsByTagName "returns a new instance of class DOMNodeList" not just an array. So as the loop goes round it is retrieving the elements as it goes; removing one will mess up its assumptions about what exists.

One solution to this is to copy the entire list of matches into a plain array before you loop over it. There is a built-in function iterator_to_array() which will do just that for you all in one go - basically, it runs a foreach over the iterable object, and collects the values into an array.

So the simplest (though not necessarily most readable etc) solution is to change this line:

foreach ($dom->getElementsByTagName('route') as $route)

to this:

foreach (iterator_to_array($dom->getElementsByTagName('route')) as $route)

Here's a live demo of the fixed code.

Upvotes: 1

Related Questions