Php only adds 3 out of 5 child nodes

This code only adds 3 out of 5 name nodes. Why is this? Here is the original XML: It has 5 name nodes.

<?xml version='1.0'?> <products> <product> <itemId>531670</itemId> <modelNumber>METRA ELECTRONICS/MOBILE AUDIO</modelNumber> <categoryPath> <category><name>Buy</name></category> <category><name>Car, Marine &amp; GPS</name></category> <category><name>Car Installation Parts</name></category> <category><name>Deck Installation Parts</name></category> <category><name>Antennas &amp; Adapters</name></category> </categoryPath> </product> </products> 

Then run this PHP code. which supposedly adds ALL name nodes to the node product.

 <?php // load up your XML $xml = new DOMDocument; $xml->load('book.xml'); // Find all elements you want to replace. Since your data is really simple, // you can do this without much ado. Otherwise you could read up on XPath. // See http://www.php.net/manual/en/class.domxpath.php //$elements = $xml->getElementsByTagName('category'); // WARNING: $elements is a "live" list -- it going to reflect the structure // of the document even as we are modifying it! For this reason, it's // important to write the loop in a way that makes it work correctly in the // presence of such "live updates". foreach ($xml->getElementsByTagName('product') as $product ) { foreach($product->getElementsByTagName('name') as $name ) { $product->appendChild($name ); } $product->removeChild($xml->getElementsByTagName('categoryPath')->item(0)); } // final result: $result = $xml->saveXML(); echo $result; ?> 

The end result is this, and it adds only 3 name nodes:

 <?xml version="1.0"?> <products> <product> <itemId>531670</itemId> <modelNumber>METRA ELECTRONICS/MOBILE AUDIO</modelNumber> <name>Buy</name> <name>Antennas &amp; Adapters</name> <name>Car Installation Parts</name> </product> </products> 

Why is it just adding 3 name nodes?

+4
source share
4 answers

You can temporarily add name elements to the array before adding them, due to the fact that you are modifying the DOM in real time. The node list generated by getElementsByTagName() may change as nodes move around (and indeed, this is similar to what is happening).

 <?php // load up your XML $xml = new DOMDocument; $xml->load('book.xml'); // Array to store them $append = array(); foreach ($xml->getElementsByTagName('product') as $product ) { foreach($product->getElementsByTagName('name') as $name ) { // Stick $name onto the array $append[] = $name; } // Now append all of them to product foreach ($append as $a) { $product->appendChild($a); } $product->removeChild($xml->getElementsByTagName('categoryPath')->item(0)); } // final result: $result = $xml->saveXML(); echo $result; ?> 

Output with all values ​​added:

 <?xml version="1.0"?> <products> <product> <ItemId>531670</ItemId> <modelNumber>METRA ELECTRONICS/MOBILE AUDIO</modelNumber> <name>Buy</name><name>Car, Marine &amp; GPS</name><name>Car Installation Parts</name><name>Deck Installation Parts</name><name>Antennas &amp; Adapters</name></product> </products> 
+1
source

You modify the DOM tree when you extract results from it. Any changes in the tree that span the results of a previous query operation (your name getElementsByTagName) invalidate these results, so you get undefined results. This is especially true for operations that add / remove nodes.

+1
source

You move nodes when you repeat them, so 2 are skipped. I am not a php guy, so I can’t give you the code for this, but you need to put together a collection of name nodes and iterate this collection in reverse order.

+1
source

A less complicated way to do this is to manipulate nodes with insertBefore

 foreach($xml->getElementsByTagName('name') as $node){ $gp = $node->parentNode->parentNode; $ggp = $gp->parentNode; // move the node above gp without removing gp or parent $ggp->insertBefore($node,$gp); } // remove the empty categoryPath node $ggp->removeChild($gp); 
0
source

Source: https://habr.com/ru/post/1385044/


All Articles