SimpleXML remove nodes

2019-01-26 01:34发布

I've got a foreach loop that is only running once and it has me stumped.

1: I load an array of status values (either "request", "delete", or "purchased")

2: I then load an xml file and need to loop through the "code" nodes and update their status, BUT if the new code is "delete" I want to remove it before moving onto the next one

XML structure is....

<content>
.... lots of stuff
<codes>
<code date="xxx" status="request">xxxxx</code>
.. repeat ...
</codes>
</content>

and the php code is ...

$newstatus = $_POST['updates'];
$file = '../apps/templates/'.$folder.'/layout.xml';
$xml2 = simplexml_load_file($file);
foreach($xml2->codes->code as $code){
    if($code['status'] == "delete") {
        $dom=dom_import_simplexml($code);
        $dom->parentNode->removeChild($dom);
    }
}
$xml2->asXml($file);

I've temporarily removed the updating so I can debug the delete check. This all works BUT it only removes the 1st delete and leaves all the other deletes even though it's a foreach loop??. Any help greatly appreciated.

1条回答
对你真心纯属浪费
2楼-- · 2019-01-26 02:19

Deleting multiple times in the same iteration is unstable. E.g. if you remove the second element, the third becomes the second and so on.

You can prevent that by storing the elements to delete into an array first:

$elementsToRemove = array();
foreach ($xml2->codes->code as $code) {
    if ($code['status'] == "delete") {
        $elementsToRemove[] = $code;
    }
}

And then you remove the element based on the array which is stable while you iterate over it:

foreach ($elementsToRemove as $code) {
    unset($code[0]);
}

You could also put the if-condition into an xpath query which does return the array directly (see the duplicate question for an example) or by making use of iterator_to_array().

查看更多
登录 后发表回答