SimpleXML 删除节点

问题描述 投票:0回答:2

我有一个只运行一次的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循环??。

php xml simplexml
2个回答
13
投票

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

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

$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()


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);
 }
}

当然,如果你的其他处理需要对元素进行正向迭代,那么使用数组是最好的。

© www.soinside.com 2019 - 2024. All rights reserved.