1

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

Community
  • 1
  • 1
Nikita240
  • 1,377
  • 2
  • 14
  • 29

1 Answers1

1

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.

Nikita240
  • 1,377
  • 2
  • 14
  • 29