The other day I was testing and playing with SimpleXML to process some XML documents when I came to a problem — I realized that I needed to delete a node before dumping the XML object to text. However if you are familiar with SimpleXML, it doesn’t come with a down right way to remove nodes like DOMDocument does.
A few searches on Google neither helped — people were just saying how simple SimpleXML was and it simply could not fulfill a task like this.
You know what I did? Yes, just ‘unset‘ the node.
$str = <<<STR
<a>
<b>
<c>
</c>
</b>
</a>
STR;
$xml = simplexml_load_string($str);
unset($xml --> a --> b --> c); // this would remove node c
echo $xml --> asXML(); // xml document string without node c
There you go!
Oh so this is how to do it and it seems to be easy ïŠ Now I don’t need to bother our IT whenever I want to remove SimpleXML . Thanks for covering this topic dude ïŠ
The problem with this approach (and all the approaches I have seen) is that you need to know the the xml tree. What happens if you have multiple nodes of the same type?
You can use:
unset($xmlNode->file[$ix]);
but you still need to know the name of the node you want to delete (above it is “file”).
Still this approach does allow you to iterate through nodes deleting the ones you want to:
$ix = count($xmlNode->file);
for ($ix– ; $ix >= 0 ; $ix–)
{
$xmlSubNode = $xmlNode->file[$ix];
if (doYouWantToDeleteThisNode($xmlSubNode))
{
unset($xmlNode->file[$ix]);
}
}
The reason I count backwards is because deleting the nodes causes the later indices to change. You can count up – you just need to make sure that you do not increment your counter variable (ix above) when you delete the node.
@david, that’s some outstanding work! 😀
I have faced with the problem that David described, and found a simpler solution at php.net.
Steps are as follows:
* Get the node object in any ways (eg. via xpath())
* import the node as DOM object
* perform the removal.
As an example:
list($theNodeToBeDeleted) = $myXml->xpath($someXPathQuery);
$oNode = dom_import_simplexml($theNodeToBeDeleted);
$oNode->parentNode->removeChild($oNode);
Simple enaugh, huh?
I made a class extension based on the code in the last post. In my case I needed to remove nodes by specific attributes and values. So here’s my effort:
class SimpleXMLExtend extends SimpleXMLElement
{
public function addCData($nodename,$cdata_text)
{
$node = $this->addChild($nodename); //Added a nodename to create inside the function
$node = dom_import_simplexml($node);
$no = $node->ownerDocument;
$node->appendChild($no->createCDATASection($cdata_text));
}
public function removeNodeByAttrib($nodename,$attribute,$value){
foreach ($this->xpath($nodename) as $key => $node) {
foreach($node->attributes() as $attrib => $val){
if ($attrib == $attribute && $val == $value) {
$oNode = dom_import_simplexml($node);
}
}
}
$oNode->parentNode->removeChild($oNode);
}
}
Hope this may be helpful for anyone.
I’m using this class.
I always receive this error:
Fatal error: Call to a member function removeChild() on a non-object on line 20.
And this is line 20 : $oNode->parentNode->removeChild($oNode);
Thanks for the contribution, Peter!
Pingback: Deleting SimpleXmlElement Child (php) « Youkey
@Peter
thanks it worked very good here!
Hi,
I came across this solution to delete nodes from an xml document. This example explains how to delete a childnode from a childnode from… etc.
Now i have a xml document in the following structure:
foo
bar
baz
Now i want to delete the bar nodes, but unfortunately Unset doesn’t work here…
Anybody any suggestions??
+1 for Peter
Works great!
Thank you very much.
:)
😀
[code]Hi.[/code]
[b]Hi.[/b]
hey! thnx
But what if there are 5 node, and i want to delete, say the 3rd one ?
V.
@david stokes: You’re comment saved my day! Thanks you and Yang Yang for the info.
@Yang Yang: Maybe you should update the post with David’s comment
@Vishwas: unset($element->childtagname[2]); // indices start from 0, and 2 is the third element