0

我用 SimpleXML 解析了一个 XML,并想截断它。这是方法:

public function truncate(SimpleXMLElement $xml)
{
    foreach ($xml->children() as $key => $value)
    {
        if ( !empty($key) && isset($xml->$key))
        {
            echo "unset $key";
            unset($xml->$key);
        }
    }

    echo $xml->asXML();
    exit;
}

在第一次取消设置后,它会抛出这个:

警告:pat\Persistence\File\Text\XML::truncate(): Node 不再存在于第 36 行的 pat/Persistence/File/Text/XML.php 中

好吧,我不想取消设置该方法。

4

2 回答 2

2

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 处理和输出,另一种是程序流。

于 2013-04-30T09:18:21.647 回答
0

您是 foreach-ing 孩子,但从父母中删除,如果您想删除空孩子,请尝试以下操作:

foreach ($xml->children() as $child)
{
    if (empty($child)) {
        unset($child[0]);
    }
}
echo $xml->asXML();
于 2013-04-30T08:24:57.190 回答