简体   繁体   中英

PHP SimpleXML - Node no longer exists when unsetting nodes in a foreach loop

I have SimpleXML objects containing items, which have non-unique ID's and versions to accompany them. What I am trying to do is remove old versions of the same ID's.

Here is a rough XML mockup:

<results>
    <result>
        <guid></guid>
        <version></version>
    </result>
    <result>
        <guid></guid>
        <version></version>
    </result>
</results>

Here is my code:

$items_iterator = $items;

foreach($items_iterator->xpath("result") as $i_indx=>$i_item)
{
    foreach($items->xpath("result") as $k_item) 
    {    
        if((string)$k_item->guid == (string)$i_item->guid && 
            ((string)$i_item->version > (string)$k_item->version))
        {
            //reffer to: https://stackoverflow.com/a/16062633
            unset($k_item[0]);
        }

    }
}

However, when I run this code, I get a bunch of "Node no longer exists" on the line containing the if statement. I can't figure out why that is. I've tried unsetting it every way, by key, or by value, but that didn't help.

Furthermore, I have found this thread , but the way he claims to be the right way for unsetting is exactly the same as mine. I do not understand why I get this error.

Any advice would be appreciated.

EDIT: Here is a PHPfiddle with some sample data: http://phpfiddle.org/main/code/b1f80276a7ce7336225b

I have figured out the problem.

Upon further investigation, I realized that the "Node no longer exists" error is referring to the $i_item, not the $k_item.

This happens because when I copied the $items SimpleXML object to $items_iterator...

$items_iterator = $items;

...instead of copying the object, it just copied the reference. But the new $items_iterator was still referencing to the old $items. It's basically an alias. This phenomenon is well documented here .

As a result, when I unset the $k_item, it also unsets the same $i_item, resulting in errors during the loop as keys that it is supposed to iterate are no longer there.

The solution is to invoke the " clone" method, which instead of just passing a reference, will duplicate every property to a new object.

$items_iterator = clone $items;

So that's all I had to do. Add one keyword. Hope this helps someone someday.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM