php SimpleXML删除节点

5m1hhzi4  于 2023-02-28  发布在  PHP
关注(0)|答案(2)|浏览(117)

我有一个只运行一次的 foreach 循环,它把我难住了。
1:我加载一个状态值数组(“请求”、“删除”或“已购买”)
2:然后我加载一个XML文件,需要遍历“code”节点并更新它们的状态,* 但是 * 如果新代码是“delete”,我想在移动到下一个节点之前删除它
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);

我已经暂时删除了更新,所以我可以调试删除检查。
这一切工作,* 但 * 它只删除第一个删除,并留下所有其他删除,即使它是一个 foreach 循环?

oprakyz7

oprakyz71#

在同一迭代中多次删除是不稳定的。例如,如果删除第二个元素,第三个元素将变为第二个元素,依此类推。
可以通过先将要删除的元素存储到数组中来防止这种情况:

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

然后根据在迭代过程中保持稳定的数组删除元素:

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

您还可以将if条件放入XPath查询中,该查询直接返回数组(请参见the duplicate question中的示例)或使用iterator_to_array()

yeotifhr

yeotifhr2#

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

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

相关问题