Adding XML DocumentFragments with PHP

Intro

Sometimes one needs to add an XML DocumentFragment from a string to an XML Document. It's possible with the standard DOM methods, but quite a PITA, since you have to create a temporary DOMDocument, add a dummy root and then loop through the childNodes of the rootNode. Furthermore you don't have the context of the target document, in which you actually wanted to add the fragment.

But there's the object DocumentFragment in the DOM specs. The object is already implemented in the upcoming PHP 5.0.0, but there was no way to add an XML-Fragment string to that (but you can use all the Node methods on it, like appendChild() et al.).

Therefore I added the appendXML() method to the DocumentFragment class, which allows to add simple XML fragments in the context of the target document.

This approach is much easier to write, less error prone and much faster. See the following sections for further details.

What's an XML DocumentFragment

From the specs:

The children of a DocumentFragment node are zero or more nodes representing the tops of any sub-trees defining the structure of the document. DocumentFragment nodes do not need to be well-formed XML documents (although they do need to follow the rules imposed upon well-formed XML parsed entities, which can have multiple top nodes).

Patch

The appendXML() method is not available in 5.0, but it's in 5.1-dev (CVS only). The patch against 5.0.0 can be found at:
http://svn.bitflux.ch/repos/public/misc/dompatches/documentfragment_appendXML.patch

Examples

With domDocumentFragment->appendChild()

$doc = new domdocument();
$doc->loadXML("<root/>");
$f = $doc->createDocumentFragment();
$f->appendXML("<foo>text</foo><bar>text2</bar>");
$doc->documentElement->appendChild($f);
print $doc->saveXML();

With domDocument Methods (old way, works in PHP 5.0.0)

$doc = new domdocument();
$doc->loadXML("<root/>");
appendDocFrag($doc->documentElement,"<foo>text</foo><bar>text2</bar>");
print $doc->saveXML(); 

function appendDocFrag($node,$frag) {
{panel}
    $tmpdoc = new domdocument();
    $tmpdoc->loadXML("<dummyroot>".$frag."</dummyroot>");
    $newnode = $node->ownerDocument->importNode($tmpdoc->documentElement,true);
    $child = $newnode->firstChild;
    while ($child) {
        $nextChild = $child->nextSibling;
        $node->appendChild($child);
        $child = $nextChild;
    }
    unset($tmpdoc);
{panel}
}

Benchmarking

The new approach with documentfragment->appendChild is approx. twice as fast as the old approach. The loadXML() method being the slowest part of it (it has to set up the whole DomDocument structure, which seems quite expensive)

Category:Articles

Labels:

Enter labels to add to this page:
Wait Image 
Looking for a label? Just start typing.
These projects are supported by Liip AG