Remove a Child With a Specific Attribute, in Simplexml For PHP

Remove a child with a specific attribute, in SimpleXML for PHP

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

Delete a node with simplexml in php

Load the file using simplexml_load_file(), loop through the <server> nodes and check if the IP is equal to the given IP.

If it is, use unset() on the self-reference of the SimpleXMLElement node to remove it:

$xml = simplexml_load_file('file.xml');
foreach ($xml as $key => $server) {
if ( $server->ip != '192.168.0.1') {
continue;
}
unset($server[0]);
}

Demo.

Delete attribute in XML

I get no errors but it does not delete the size attribute. Why?

There are mulitple reasons why it does not delete the size attribute. The one that popped first into my mind was that attributes are no child nodes. Using a method to remove a child does just not fit to remove an attribute.

Each element node has an associated set of attribute nodes; the element is the parent of each of these attribute nodes; however, an attribute node is not a child of its parent element.

From: Attribute Nodes - XML Path Language (XPath), bold by me.

However, you don't see an error here, because the $result you have is an empty array. You just don't select any nodes to remove - neither elements nor attributes - with your xpath. That is because there is no such element you look for:

//door[@size='1']

You're searching for the id in the size attribute: No match.

These are the reasons why you get no errors and it does not delete any size attribute: 1.) you don't delete attributes here, 2.) you don't query any elements to delete attributes from.

How to delete attributes in SimpleXML queried by Xpath?

You can remove the attribute nodes by selecting them with an Xpath query and then unset the SimpleXMLElement self-reference:

// all size attributes of all doors
$result = $xml->xpath("//door/@size");
foreach ($result as $node) {
unset($node[0]);
}

In this example, all attribute nodes are queried by the Xpath expressions that are size attributes of door elements (which is what you ask for in your question) and then those are removed from the XML.

//door/@size

(see Abbreviated Syntax)

Now here the full example:

<?php
/**
* @link https://eval.in/215817
*/

$buffer = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<doors>
<door id="1" entry="3249" size="30"/>
<door id="1041" entry="6523" size="3094"/>
-- and 1000 more....
</doors>
XML;

$xml = new SimpleXMLElement($buffer);

// all size attributes of all doors
$result = $xml->xpath("//door/@size");
foreach ($result as $node) {
unset($node[0]);
}

$xml->saveXml("php://output");

Output (Online Demo):

<?xml version="1.0" encoding="UTF-8"?>
<doors>
<door id="1" entry="3249"/>
<door id="1041" entry="6523"/>
-- and 1000 more....
</doors>

Removing parent nodes based on child in XML

Nobody answered, so i will. Please, read the comments.

// First, your XML must be wraped with some root tag.
$data = '<root>
<search-params>
<date>2013-05-20</date>
</search-params>
<results>
<date>2013-05-21 14:31:00</date>
<prices>
<for>
<players>1</players>
</for>
<amount>20</amount>
</prices>
<prices>
<for>
<players>2</players>
</for>
<amount>35</amount>
</prices>
<prices>
<for>
<players>3</players>
</for>
<amount>49.5</amount>
</prices>
<prices>
<for>
<players>4</players>
</for>
<amount>60</amount>
</prices>
</results>
<results>
<date>2013-05-21T14:40:00</date>
<prices>
<for>
<players>1</players>
</for>
<amount>20</amount>
</prices>
</results>
</root>';

// Instancing the SimpleXMLElement within the XML(obviously)
$xml = new SimpleXMLElement($data);

// XPath
$xpath = $xml->xpath("results[prices/for[contains(players,'4')]]");
/**
* eXplained XPath:
* <results> that
* <prices>/<for>
* contains <players> that content is equal 4
*/

foreach($xpath as $node){
// just for fun echoes the <results> node
echo $node->asXml();
}

PHP Simple XML remove all Children

Here is one possible solution (online demo):

$xml = <<< XML
<?xml version='1.0' encoding='utf-8'?>
<concerts>
<concert>
<artist></artist>
<date></date>
</concert>
</concerts>
XML;

$concerts = simplexml_load_string($xml);

foreach ($concerts->xpath('/*/concert/*') as $child)
{
unset($child[0]);
}

echo $concerts->asXML();

Marking this CW because how to delete elements is given in my supplied closevote and this answer only expands on this. And this now has been edited showing the self-reference method to delete a SimpleXML element node as outlined in an answer of the question "Remove a child with a specific attribute, in SimpleXML for PHP" which is also a possible duplicate.

How to remove XML tag based on child attribute using php?

You need to use DOMDocument class to parse string to XML document. Then use DOMXpath class to find target element in document and use DOMNode::removeChild() to remove selected element from document.

$doc = new DOMDocument(); 
$doc->loadXML($xml);
$xpath = new DOMXpath($doc);
// select target entry tag
$entry = $xpath->query("//entry[title[@lang='fr']]")->item(0);
// remove selected element
$entry->parentNode->removeChild($entry);
$xml = $doc->savexml();

You can check result in demo

Deleting simplexmlelement node

Use unset(): Remove a child with a specific attribute, in SimpleXML for PHP



Related Topics



Leave a reply



Submit