Add Children with SimpleXML
I was very excited today while glancing through the code in ext/simplexml/simplexml.c to find some, as of yet, undocumented methods in PHP’s SimpleXMLElement class. This discovery came after I’ve spent several hours over the last couple of nights banging my head against the desk to figure out a way to create a class that extends SimpleXMLElement and adds a new method for adding a child, which would have to use DOM in order to work—or so I thought.
During this process, I’ve discovered two major limitations of SimpleXML:
- You cannot override the SimpleXMLElement constructor; it is a
finalmethod in the internals - You can extend SimpleXMLElement and add new methods, but looping through child nodes creates new SimpleXMLElement objects that do not use your class and, thus, cannot use your methods
Nevertheless, I can get over these limitations after discovering these new SimpleXMLElement methods in PHP 5.1.4. In particular, the last three are what interest me most (these are not yet documented in the PHP manual ):
bool SimpleXMLElement->registerXPathNamespace(string prefix, string uri) array SimpleXMLElement->getNamespaces([bool recursive]) array SimpleXMLElement->getDocNamespaces([bool recursive]) string SimpleXMLElement->getName() object SimpleXMLElement->addChild(string name [, string value [, string ns]]) void SimpleXMLElement->addAttribute(string name, string value [,string ns])
Previously, one of the biggest limitations of SimpleXML was that you could not add new child nodes to an XML document. Adding attributes to an element was no problem, but in order to add a child element, you had to go a round-about way through importing the SimpleXML object to DOM with dom_import_simplexml(), adding the child element, and importing the DOM object back to SimpleXML with simplexml_import_dom(). This was messy and anything but simple.
Now, it’s clean and simple, as SimpleXML should be:
$xml = <<<XML
<books>
<book title="Fahrenheit 451" author="Ray Bradbury"/>
<book title="Stranger in a Strange Land" author="Robert Heinlein"/>
</books>
XML;
$sxe = new SimpleXMLElement($xml);
$new_book = $sxe->addChild('book');
$new_book->addAttribute('title', '1984');
$new_book->addAttribute('author', 'George Orwell');
echo $sxe->as<abbr title="">XML</abbr>;
UPDATE: I’ve added all of these (except for registerXPathNamespace(), which I can’t seem to figure out) to the documentation for SimpleXML in the PHP Manual. The documentation for each new method will be available the next time the scripts run to update the manual.
6 Comments
fuckin A man! that's awesome!
The registerXPathNamespace() function allows you to associate a prefix with an XML Namespace URI. A prefix is necessary to make XPath queries against elements that live under a namespace. (e.g. "//xhtml:p" to find all "p" elements in the namespace bound to the "xhtml" prefix.)
Use this function when needing to access namespaced elements under a default namespace to create a prefix for that namespace. It's also helpful when you cannot control the XML document you're consuming and the provider may alter namespace prefixes without warning.
Thanks for the clarification on that, Adam. I think my problem was that I wasn't using a proper XPath query, so the function wasn't doing anything for me.
If only I had seen this a mere week ago!!! After some considerable work, I have managed to do this in the DOM - but it is such hard work. Many Many Thanks for this.
NB: It's worth re-iterating this requires at least PHP version 5.1.3
Please, im a very new to php and xml:
if i have books.xml that contains:
how do i use this code to add a book? everything i tried errored.
Could you please email me an example? thank you very much in advance, i am very grateful!