I'm posting this solution in advance for the benefit of others who might trip over this SimpleXML issue.

Drupal 6 automatically passes cache_save and cache_get arguments through PHP's serialize/unserialize functions.

If you parse an XML string using SimpleXML, it creates an object with invisible properties that won't show up if you do a print_r().

This object is a built-in object in PHP terminology, and should not be serialized/unserialized. See the discussion here: http://us3.php.net/manual/en/function.serialize.php

In my case I was trying to store a string, but unknowingly I was storing an object. I had parsed an RSS feed using SimpleXML and extracted one element like so:

$status = $statusobject->channel->item[0]->title;

The resulting $status was printable as a string but actually, unbeknownst to me, was an object when passed through D6's cache functions. When D6 attempted to unserialize the stored value, PHP threw an error: "Node no longer exists."

A cast fixed the problem:

$status = (string) $statusobject->channel->item[0]->title;

Comments

yaph’s picture

Thanks for the information. I should have searched the Drupal forum first after running into this problem. So instead of trying to cache the simpexml object I cache the XML string I receive from an API request and now all works fine.

Greg Go’s picture

@yelvington - awesome troubleshooting! Thanks for writing this up. "Mysterious error" is a perfect description. :)

rfay’s picture

Thanks for saving the day with this post. I definitely spent several hours beating my head against this before finding your note.

An alternate way to deal with a SimpleXML object or a piece of one is to use the SimpleXML method asXML() to deserialize it before caching:

// $xmlobject is an object of type SimpleXML
$text = $xmlobject->asXML();
cache_set($key,$text);

// And later retrieve with:
$xmltext = cache_get($key);
$retrieved_object = new SimpleXMLElement($xmltext);

// And now $retrieved_object will be the same as $xmlobject
nzpunter’s picture

Hey,

so using
$status = $statusobject->channel->item[0]->title;
caught me out too..

but how do i get rid of the

Warning: unserialize() [function.unserialize]: Node no longer exists in /home/...../includes/bootstrap.inc on line 478

ive disabled and removed the module, cleared the cache, but the error persists..

mindbat’s picture

@nzpunter: Did you save the SimpleXMLObject to a variable (via variable_set())? If so, you'll need to delete the variable from the variable table in the db, as well.

chiddicks’s picture

This was what got me. Thank you for this reminder.

ajveach’s picture

I am attempting to extract an attribute using simpleXML, but I am running into the same error that you mentioned. This is the script I am using:

$buzz_media['type'] = (string)$entry->mediacontent->attributes()->type;

I have tried with and without the "(string)", but the results are the same in both cases. Am I misunderstanding the solution you provided?

andyceo’s picture

Thanx for the your message, it was very helpfull and informative. I have encountered this problem recently.

XiaN Vizjereij’s picture

Yeah, thanks a lot for posting an solution for that issue. Helped me a lot :)

yuriy.babenko’s picture

Interesting note. Good to know!

---
Yuriy Babenko | Technical Consultant & Senior Developer
http://yuriybabenko.com

sbefort’s picture

I was getting the same error in my logs after building a module which uses SimpleXML. Thank you yelvington and thank you Google for preventing my head from banging against the wall.

visum’s picture

Hopefully this prevents some more bruised heads.

While debugging, I had asked Watchdog to save a SimpleXMLElement to the log. Due to the reasons described above, it caused the error, and caused it again and again every time I looked at the log.

To solve the problem I looked through the watchdog table until I found a record with SimpleXMLElement in the variables field, deleted the record, and the error went away.

And that made me happy.

chandantyagi’s picture

hi yelvington,
thanks for this awesome info..............
it really works....
thanks once again

Morten Najbjerg’s picture

Thank you! I was just about to reinstall the site - Your post saved me several hours.

Pierco’s picture

Hi,

Thanks for this information.
You can also cache the full XML string and recreate the SimpleXMLElement:

cache_set('COUNTRIES', (string)$countries->asXML(), 'cache_field', CACHE_TEMPORARY);
$countries = cache_get('COUNTRIES', 'cache_field');
if ($countries) {
  $countries = new SimpleXMLElement($countries->data);
}

For me it works very well.

mustafa.ata’s picture

Thank you yelvington for solution, to get out of hell :) :P.

ericpugh’s picture

Casting didn't solve the problem for me when trying to set an attribute as a string. Seems that an empty object is always returned... just needed to check for existence first. For example:

$thumbUrl = "";
if($media->thumbnail && $media->thumbnail->attributes()){
	$thumb = $media->thumbnail->attributes();
	$thumbUrl = (string) $thumb['url'];
}