1

I'm trying to remove multiple elements in php using DOM Document, but it does not work as i wanted it to work.

<iPhone>
<enAttentePush>
  <UDID>dd6fc8032f0bf4c4b3a9c60f523900c9ad463b620a83b6473eda9a12b2c9d47f</UDID>
  <Message>someDataHere</Message>
</enAttentePush>

<enAttentePush>
  <UDID>dd6fc8032f0bf4c4b3a9c60f523900c9ad463b620a83b6473eda9a12b2c9d47f</UDID>
  <Message>someDataHere</Message>
</enAttentePush>
</iPhone>

I want to loop into my xml document and then erase all element to get an empty file.

Here is what i do in php :

$doc = new DOMDocument;

$doc->load('$myFile'); 
$domNodeList = $doc->getElementsByTagName('enAttentePush'); 
$arraySeen = array(); 
$arrayBug = array(); 

foreach ($domNodeList as $domElement)
{
        //echo('loop / ');
  $tempArray = array(); 

  $aps = $domElement->getElementsByTagName('Message')->item(0)->nodeValue;
  $udid = $domElement->getElementsByTagName('UDID')->item(0)->nodeValue; 
  if (!in_array($udid, $arraySeen))
  {         
      $tempArray[]=$aps; 
      $tempArray[]=$udid; 
      $arrayBug[]=$tempArray;
     $arraySeen[]=$udid; 
   }

   echo("-- removed -- ");
   $domElement->parentNode->removeChild($domElement); 
  }

It only delete only one node, the last one in general.

How can i do to loop thought my node and remove it each time i see a node ?

Thank you very much.

2
  • If I recall vaguely, deleting a node upsets the node query, which means that you have to re-query the DOM until all nodes are deleted. So instead of foreach() { } you should consider using while() { }. Commented Jan 8, 2014 at 16:19
  • Well i do not know how to make a while loop with dom... Commented Jan 8, 2014 at 16:22

3 Answers 3

4

getElementsByTagName() returns "live" iterator, the list changes the moment you remove the elements from the list. You can convert the iterator into an array to get a copy of the list.

$xml = <<<'XML'
<iPhone>
<enAttentePush>
  <UDID>dd6fc8032f0bf4c4b3a9c60f523900c9ad463b620a83b6473eda9a12b2c9d47f</UDID>
  <Message>someDataHere</Message>
</enAttentePush>
<enAttentePush>
  <UDID>dd6fc8032f0bf4c4b3a9c60f523900c9ad463b620a83b6473eda9a12b2c9d47f</UDID>
  <Message>someDataHere</Message>
</enAttentePush>
</iPhone>
XML;

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

$nodes = iterator_to_array($dom->getElementsByTagName('enAttentePush'));
foreach ($nodes as $node) {
  $node->parentNode->removeChild($node);
}

echo $dom->saveXml();

Output:

<?xml version="1.0"?>
<iPhone>


</iPhone>

An easier way would be to copy the document element from the original document into a new one:

$xml = <<<'XML'
<iPhone>
<enAttentePush>
  <UDID>dd6fc8032f0bf4c4b3a9c60f523900c9ad463b620a83b6473eda9a12b2c9d47f</UDID>
  <Message>someDataHere</Message>
</enAttentePush>
<enAttentePush>
  <UDID>dd6fc8032f0bf4c4b3a9c60f523900c9ad463b620a83b6473eda9a12b2c9d47f</UDID>
  <Message>someDataHere</Message>
</enAttentePush>
</iPhone>
XML;

$source = new DOMDocument();
$source->loadXml($xml);

$target = new DOMDocument();
$target->appendChild(
  $target->importNode($source->documentElement, FALSE)
);

echo $target->saveXml();

Output:

<?xml version="1.0"?>
<iPhone/>

To remove specific nodes, select them with Xpath. This allows for complex conditions.

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

$nodes = $xpath->evaluate('/*/enAttentePush');
foreach ($nodes as $node) {
  $node->parentNode->removeChild($node);
}

echo $dom->saveXml();
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much ThW i'll use stckrboy solution which is more simple for a noob like me, nevertheless you answer helped me a lot, i'll take a look @ xPath. Thank you very much, really appreciated.
3

I had to do this just recently on my own site and found that you if you queue up your elements in an array, you can remove them all quite easily after that. Here is a little snippet that use, hopefully it helps you out:

$doc = new DOMDocument;

$doc->load('$myFile');
$domNodeList = $doc->getElementsByTagName('enAttentePush');

$domArray = array(); //set up an array to catch all our nodes

foreach($domNodeList as $dom) {
    $domArray[] = $dom;
}

// loop through the array and delete each node
foreach($domArray as $node){ 
    $doc->documentElement->removeChild($node);
}

$doc->save('$myFile');

Comments

1

As already mentioned in comment, use while instead of foreach to iterate the DOMNodeList:

$i = $domNodeList->length;
while ($i > 0) {
    $i--;
    $domElement = $domNodeList->item($i);
    $domElement->parentNode->removeChild($domElement); 
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.