我有一个只运行一次的foreach循环,它让我难住了。
1:我加载一组状态值(“请求”、“删除”或“已购买”)
2:然后我加载一个 XML 文件并需要遍历“代码”节点并更新它们的状态,但是如果新代码是“删除”我想在移动到下一个之前删除它
XML 结构是...
<content>
.... lots of stuff
<codes>
<code date="xxx" status="request">xxxxx</code>
.. repeat ...
</codes>
</content>
PHP 代码是...
$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);
我暂时去掉了updating,所以可以debug delete check
这一切都有效,但是它只删除第一个删除并保留所有其他删除,即使它是一个foreach循环??。
在同一次迭代中多次删除是不稳定的。例如。如果你删除第二个元素,第三个变成第二个,依此类推。
您可以通过先将要删除的元素存储到数组中来防止这种情况发生:
$elementsToRemove = array();
foreach ($xml2->codes->code as $code) {
if ($code['status'] == "delete") {
$elementsToRemove[] = $code;
}
}
然后你删除基于数组的元素,当你迭代它时它是稳定的:
foreach ($elementsToRemove as $code) {
unset($code[0]);
}
您还可以将 if 条件放入直接返回数组的 xpath 查询中(有关示例,请参见重复问题)或使用
iterator_to_array()
。
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);
}
}
当然,如果你的其他处理需要对元素进行正向迭代,那么使用数组是最好的。