Remove a child with a specific attribute, in SimpleXML for PHP
Contrary to popular belief in the existing answers, each Simplexml element node can be removed from the document just by itself and unset()
. The point in case is just that you need to understand how SimpleXML actually works.
First locate the element you want to remove:
list($element) = $doc->xpath('/*/seg[@id="A12"]');
Then remove the element represented in $element
you unset its self-reference:
unset($element[0]);
This works because the first element of any element is the element itself in Simplexml (self-reference). This has to do with its magic nature, numeric indices are representing the elements in any list (e.g. parent->children), and even the single child is such a list.
Non-numeric string indices represent attributes (in array-access) or child-element(s) (in property-access).
Therefore numeric indecies in property-access like:
unset($element->{0});
work as well.
Naturally with that xpath example, it is rather straight forward (in PHP 5.4):
unset($doc->xpath('/*/seg[@id="A12"]')[0][0]);
The full example code (Demo):
<?php/** * Remove a child with a specific attribute, in SimpleXML for PHP * @link http://stackoverflow.com/a/16062633/367456 */$data=<<<DATA<data> <seg id="A1"/> <seg id="A5"/> <seg id="A12"/> <seg id="A29"/> <seg id="A30"/></data>DATA;$doc = new SimpleXMLElement($data);unset($doc->xpath('seg[@id="A12"]')[0]->{0});$doc->asXml('php://output');
Output:
<?xml version="1.0"?><data> <seg id="A1"/> <seg id="A5"/> <seg id="A29"/> <seg id="A30"/></data>
While SimpleXML provides a way to remove XML nodes, its modification capabilities are somewhat limited. One other solution is to resort to using the DOM extension. dom_import_simplexml() will help you with converting your SimpleXMLElement
into a DOMElement
.
Just some example code (tested with PHP 5.2.5):
$data='<data> <seg id="A1"/> <seg id="A5"/> <seg id="A12"/> <seg id="A29"/> <seg id="A30"/></data>';$doc=new SimpleXMLElement($data);foreach($doc->seg as $seg){ if($seg['id'] == 'A12') { $dom=dom_import_simplexml($seg); $dom->parentNode->removeChild($dom); }}echo $doc->asXml();
outputs
<?xml version="1.0"?><data><seg id="A1"/><seg id="A5"/><seg id="A29"/><seg id="A30"/></data>
By the way: selecting specific nodes is much more simple when you use XPath (SimpleXMLElement->xpath):
$segs=$doc->xpath('//seq[@id="A12"]');if (count($segs)>=1) { $seg=$segs[0];}// same deletion procedure as above
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 cecho $xml –> asXML(); // xml document string without node c
This code was taken from How to delete / remove nodes in SimpleXML.