Ok, so I had this neat little idea the other night to create a helper class for DOMDOCUMENT that mimics, to some extent, jQuery’s ability to manipulate the DOM of an HTML or XML-based string. Instead of css selectors, XPath is used. For example:
$Xml->load($source) ->path('//root/items') ->each(function($Context) { echo $Context->nodeValue; });
This would invoke a callback function on every resulting node. Unfortunately, PHP version < 5.3.x doesn’t support lambda functions or closures, so I’m forced to do something a bit more like this for the time being:
$Xml->load($source) ->path('//root/items') ->walk('printValue', 'param1', 'param2');
Everything is working great at the moment and I think this project would be useful to a lot of people, but I’m stuck with one of the functions. I am attempting to mimic jQuery’s ‘replace’ method. Using the following code, I can accomplish this quite easily by applying the following method:
$Xml->load($source) ->path('//root/items') ->replace($Xml->createElement('foo', 'bar')); // can be an object, string or XPath pattern
The code behind this method is:
public function replace($Content) { foreach($this->results as $Element) { $Element->parentNode->appendChild($Content->cloneNode(true)); $Element->parentNode->removeChild($Element); } return $this; }
Now, this works. It replaces every resulting element with a cloned version of $Content. The problem is that it adds them to the bottom of the parent node’s list of children. The question is, how do I clone this element to replace other elements, while still retaining the original position in the DOM?
I was thinking about reverse-engineering the node I was to replace. Basically, copying over values, attributes and element name from $Content, but I am unable to change the actual element name of the target element.
Reflection could be a possibility, but there’s gotta be an easier way to do this.
Anybody?
Use replaceChild instead of appendChild/removeChild.