Reputation: 722
I'm working with php 7.3 to write a function that loops over a set of nodes recieved in input and add them to a document.
public function appendChildren($nodes)
{
foreach ($nodes as $node){
$this->appendChild($node);
}
}
It works but when the input value is not an array but a DOMNodeList, it only loops over the first element.
To reproduce the problem:
<?php
$doc = new DOMDocument();
$doc->formatOutput=true;
$root = $doc->createElementNS('urn:oasis:names:tc:SAML:2.0:metadata', 'md:root');
$nodes[] = $doc->createElementNS('urn:oasis:names:tc:SAML:2.0:metadata', 'KeyInfo');
$nodes[] = $doc->createElementNS('urn:oasis:names:tc:SAML:2.0:metadata', 'KeyFile');
$nodes[] = $doc->createElementNS('urn:oasis:names:tc:SAML:2.0:metadata', 'KeyStory');
$nodes[] = $doc->createElementNS('urn:oasis:names:tc:SAML:2.0:metadata', 'KeyRole');
foreach($nodes as $node)
{
$root->appendChild($node);
}
$nlist = $root->childNodes;
$newroot = $doc->createElementNS('urn:oasis:names:tc:SAML:2.0:metadata', 'md:newroot');
foreach($nlist as $node)
{
$newroot->appendChild($node);
}
echo 'size of root: '.$root->childNodes->count()."\n";
echo 'size of newroot: '.$newroot->childNodes->count()."\n";
$doc->appendChild($newroot);
echo $doc->saveXML();
expected output:
size of root: 4
size of newroot: 4
<?xml version="1.0"?>
<md:newroot xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
<md:KeyInfo/>
<md:KeyFile/>
<md:KeyStory/>
<md:KeyRole/>
</md:root>
however i get:
size of root: 3
size of newroot: 1
<?xml version="1.0"?>
<md:newroot xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
<md:KeyInfo/>
</md:newroot>
The loop is incomplete, and somehow the reference of the first element is removed from the former list and added to the latter (hence the size 3). Moreover, if i comment
$newroot->appendChild($node);
the loop traverse the list as expected. How is it possible for the function appendChild() to stop the loop? And why does it happen after the first iteration?
Can someone shed some light on this behaviour ?
Upvotes: 1
Views: 137
Reputation: 9135
The $nlist
is changing while iterating due to appendChild. You are moving the content. You can see that with debugging
for($i = 0; $i < $nlist->length; $i++)
{
$newroot->appendChild($nlist->item($i));
}
So you need to rewrite like this
while($nlist->length)
{
$newroot->appendChild($nlist->item(0));
}
Upvotes: 1