simplexml 中的错误消息“节点不再存在”意味着您正在尝试删除不再存在的节点。
正如您已经注意到的那样,这不会发生在第一次迭代的未设置中,而是发生在下一次迭代中。如果您现在想象SimpleXMLElement::children()
返回一个以子元素的从零开始的索引为键、子元素节点为值的数组,请考虑以下内容以更好地理解:
你有一个有两个孩子的元素。因此,该children()
函数返回一个包含两个的数组。
$children = [ 0 => <child1>, 1 => <child2> ]
^ unset($xml->{0});
`-----------------^
$xml->children() = [ 0 => <child1>, 1 => <child2> ]
您现在删除第一个子元素,索引 0。
第二个孩子还在:
$xml->children() = [ 0 => <child2> ]
但是因为您通过孩子的编号访问孩子,并且第一个孩子已被删除,所以第二个孩子获得了一个新索引:从以前的 1 现在为 0。但是您在索引 1 处取消设置孩子:
$children = [ 0 => <child1>, 1 => <child2> ]
^ unset($xml->{1});
`-----------------^
$xml->children() = [ 0 => <child2> ]
不再存在:
节点不再存在
看到错误信息了吗?那么如何解决呢?SimpleXML 中的一种常见方法是使用hakre 在该问题中概述的simplexml 自引用:
unset($value[0]);
如您所见,它不需要使用任何密钥。另一种选择是反转children 数组并从末尾而不是开头取消设置。这样您就不会将索引拉到脚下:
$children = array_reverse($xml->children());
foreach ($children as $key => $value) {
...
unset($xml->$key);
}
}
但是自引用可能更容易使用,因为它也适用于您想在 simplexml 中取消设置某些内容的其他情况,因此值得您在那里阅读解释清楚的内容。
完整示例一目了然:
public function truncate()
{
$xml = $this->_xml;
$children = $xml->children();
foreach ($children as $index => $child)
{
if ($index) {
unset($child[0]);
}
}
$xml->asXML('php://output');
exit;
}
我还要说不exit
属于那种方法,但我把它留在里面,这样你就可以更好地定位。相反,该方法应该只完成输出截断的 XML 的工作,而不是另外关心结束脚本。而是在调用方法后将其移出并放置,因为这是两种不同的任务:一种是 XML 处理和输出,另一种是程序流。