1

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.

4

2 回答 2

13

在同一迭代中多次删除是不稳定的。例如,如果您删除第二个元素,则第三个变为第二个,依此类推。

您可以通过首先将要删除的元素存储到数组中来防止这种情况发生:

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

然后根据在迭代时稳定的数组删除元素:

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

您还可以将 if-condition 放入 xpath 查询中,该查询确实直接返回数组(请参阅重复问题的示例)或使用iterator_to_array().

于 2013-06-22T08:32:06.650 回答
0

SimpleXML 节点列表是简单的引用数组,就像在向前迭代数组时删除任何项一样,数组位置指针可能会混淆,因为预期的下一项已经消失。

在不使用额外数组的情况下删除 SimpleXML 中的一堆子项的简单方法是反向迭代(=递减索引),将示例中的循环用于:

// FOR EACH NODE IN REVERSE
$elements=$xml2->xpath('codes/code');
$count=count($elements);
for($j=$count-1;$j>=0;$j--){
 // IF TO DELETE
 $code=$elements[$j];
 if($code['status']=="delete"){
  // DELETE ELEMENT
  $dom=dom_import_simplexml($code);
  $dom->parentNode->removeChild($dom);
 }
}

当然,如果您的其他处理需要前向迭代元素,那么使用数组是最好的。

于 2021-10-07T22:04:41.670 回答