User Contributed Notes 24 notes

What makes SimpleXMLElement tricky to work with is that it feels and behaves like an object, but is actually a system RESOURCE, (specifically a libxml resource).

That's why you can't store a SimpleXMLElement to $_SESSION or perform straight comparison operations on node values without first casting them to some type of object. $_SESSION expects to store 'an object' and comparison operators expect to compare 2 'objects' and SimpleXMLElements are not objects.

When you echo or print a node's value, PHP converts the value (a resource) into a string object for you. It's a time saver for sure, but can fool you into thinking that your SimpleXMLElement is an object.

Warning to anyone trying to parse XML with a key name that includes a hyphen ie.)<subscribe> <callback-url>example url</callback-url></subscribe>

In order to access the callback-url you will need to do something like the following:<?php$xml = simplexml_load_string($input);$callback = $xml->{"callback-url"};?>If you attempt to do it without the curly braces and quotes you will find out that you are returned a 0 instead of what you want.

Here is a more namespace-aware version of the earlier function for attaching one SimpleXMLElement to another. I'm sure it could still be further improved (right now it generates some redundant xmlns definitions), but it seems to be working well enough for my purposes so far.

SimpleXML supports Array/Iteration-Methods. Therefore it is possible to

add attributesedit attributesremove attributes

add nodesedit nodesremove nodes

This is the reason why SimpleXML provides only add-methods not deleting- or editing-methods. We also need this methods because SimpleXML acts as a normal class andnew member will not converted to a new node.

Deleting a node seems not to be possible within a foreach-loop. The reason is simple. To do that we need a valid key, but the Iterator only gives us a "understandable feedback" on which node we are working on: the tag name.

Figuring out how to access the properties of a SimpleXmlElement object was a little tricky for me. In particular, it took a while to discover that I needed to cast my SimpleXmlElement properties to be of type "string" to print them or do comparisons on them. For instance, assuming you already have a string of xml in $xmlstr...

<?php$sxml= new SimpleXmlElement($xmlstr);

if ((string) $sxml->property== "somevalue") { echo (string) $sxml->property;}?>The properties of a SimpleXmlElement object are objects themselves, so you need to put "(string)" before them, which casts their values to a string instead of an object. I assume if you were doing a numeric comparison you'd want to cast to an (int) or something numeric instead.

here goes my contribution for those whom are struggling to understand how SimpleXMLElement works.

After some time trying to figure out how this works, I've came up to this small example:

<?php $xmlstr = "<?xml version='1.0' ?>\n".// optionally you can specify a xml-stylesheet for presenting the results. just uncoment the following line and change the stylesheet name. /* "<?xml-stylesheet type='text/xsl' href='xml_style.xsl' ?>\n". */"<book></book>";

// create the SimpleXMLElement object with an empty <book> element$xml = new SimpleXMLElement($xmlstr);

// add some child nodes$xml->addChild("title", "Title of my book");$xml->addChild("abstract", "My book is about learning to work with SimpleXMLElement");

See previous two parts to get better understanding of how these tricks works. Example shown here refers to part two. (Sorry, length limitation)

3. Tricks<?php// The real profit is in combination of property and array accesses and unset($someNode->{0}) trick - // it allows you to remove whatever node you want:unset($rootNode->{'div'}[2]); // remove node with * mark (text*)

$rootNode->{'type_one'} = $childNode2; // Note that the property name is 'type_one'$rootNode->{'type_two'} = $childNode3; // Note that the property name is 'type_two'var_dump($rootNode);/* object(SimpleXMLElement)#68 (2) { ["type_one"]=> string(6) "node 2" ["type_two"]=> string(6) "node 3" } */ // We see that "node 1" disappeared, that's because assigning one node to some property of another in not a magic. // To be clear, the real calls looks like:$rootNode->{'type_one'}[0] = (string) $childNode2;$rootNode->{'type_two'}[0] = (string) $childNode3;// Explanation: // A: (string) // It means that you can't assign node itself, only its string representation because assigned node will be casted to string anyway. // It also means that tag name of assigned node doesn't matter - its name will be whatever name you specified in {} braces. // B: [0] // The array access operator ([0]) means that each tag name (type_one and type_two) has its own collection with integer indexes. // If you want to add another tag with same name, you should increment index:$rootNode->{'type_one'}[1] = $childNode2;var_dump($rootNode);/* object(SimpleXMLElement)#68 (2) { ["type_one"]=> array(2) { [0]=> string(6) "node 2" [1]=> string(6) "node 2" } ["type_two"]=> string(6) "node 3" } */

// Note 1. The value of $childNode1 has been changed to "node 1" - that's because the child node, returned from addChild() method // is referenced with parent node. If you change its content in one side - it changes in other side too:$childNode1->{0} = 'renewed node 1';// But it won't happen with $childNode2 - it is single and has no reference with parent node:$childNode2->{0} = 'renewed node 2';var_dump($rootNode);/* object(SimpleXMLElement)#68 (2) { ["type_one"]=> array(2) { [0]=> string(14) "renewed node 1" [1]=> string(6) "node 2" } ["type_two"]=> string(6) "node 3" } */

// Note 2. When you added child nodes, the parent node's string content is still alive, var_dump doesn't show it, // but you can see through echoing XML:echo "--1--\n".$rootNode->asXML();/* <xml_root>complex node <--------- here! <type_one>renewed node 1</type_one> <type_two>node 3</type_two> <type_one>node 2</type_one> </xml_root> */ // See 'complex node'? Bad news that you can't change string content anymore, if we try to call `$rootNode->{0} = 'something'` - // it overrides all content - both string and child nodes! I don't know how to write to string content only in that case. // But still you can read string content and remove entire node as described above.

I'm using SimpleXML for, ofcourse, it's simplicity, however I did wanted to manipulate the xml and combining one SimpleXMLElement with any other, so I wrote this function to add a SimpleXMLElement-child.