tags:

views:

1453

answers:

5

I need to delete elements of an XML file using PHP. It will be done via ajax and I need to find the XML element via an attribute.

This is my XML file

<?xml version="1.0" encoding="utf-8"?>
<messages>
    <message time="1248083538">
     <name>Ben</name>
     <email>Ben's Email</email>
     <msg>Bens message</msg>
    </message>
    <message time="1248083838">
     <name>John Smith</name>
     <email>[email protected]</email>
     <msg>Can you do this for me?</msg>
    </message>
</messages>

So what I would say is something like delete the element where the time equals 1248083838.

Ive been using Simple XML up until now and I've just realised it can do everything except delete elements.

So how would I do this?

+1  A: 

You can use the DOM classes in PHP. ( http://us3.php.net/manual/en/intro.dom.php ).

You will need to read the XML document into memory, use the DOM classes to do manipulation, and then you can save out the XML as needed (to http or to file).

DOMNode is an object in there that has remove features (to address your question).

It's a little more complicated than SimpleXML but once you get used to it, it's much more powerful

(semi-taken from a code example at php.net)

<?php

$doc = new DOMDocument; 
$doc->load('theFile.xml');

$thedocument = $doc->documentElement;

//this gives you a list of the messages
$list = $thedocument->getElementsByTagName('message');

//figure out which ones you want -- assign it to a variable (ie: $nodeToRemove )
$nodeToRemove = null;
foreach ($list as $domElement){
  $attrValue = $domElement->getAttribute('time');
  if ($attrValue == 'VALUEYOUCAREABOUT') {
    $nodeToRemove = $domElement; //will only remember last one- but this is just an example :)
  }
}

//Now remove it.
if ($nodeToRemove != null)
$thedocument->removeChild($nodeToRemove);

echo $doc->saveXML(); 
?>

This should give you a little bit of an idea on how to remove the element. It will print out the XML without that node. If you wanted to send it to file, just write the string to file.

Dave Morgan
Hmm...I'm a bit overwhelmed by everything there. Could you explain a bit more?
Ben Shelock
Sure. I'll Edit.
Dave Morgan
I didn't have a chance to check for minor syntax errors - but that should give you something like what you need. I recommend not removing the child in the forloop itself because it messes with the internal counter of the foreach.
Dave Morgan
+1  A: 

you should be able to remove nodes through the DOM functions.

http://www.w3schools.com/Dom/dom_nodes_remove.asp

Jeremy Petzold
Still not sure how to delete depending on the attribute though
Ben Shelock
Just make the attribute part of your search algorithm. Keep it simple.
Jeremy Petzold
+3  A: 

Dave Morgan is correct in that DOM classes are more powerful, but in case you want to stick with SimpleXML, try using the unset() function on any node. E.g. unset($simpleXMLDoc->node1->child1), and that will be removed from the XML.

Salty
I have not tried doing that, but logic dictates that it should work fine. Sounds like a quick-n-dirty, but proper work around to me.
Dave Morgan
A: 

Even though SimpleXML doesn't have a detailed way to remove elements, you can remove elements from SimpleXML by using PHP's unset(). The key to doing this is managing to target the desired element. At least one way to do the targeting is using the order of the elements. First find out the order number of the element you want to remove (for example with a loop), then remove the element:

$target = false;
$i = 0;
foreach ($xml->message as $m) {
  if ($m['time']=='1248083838') { $target = $i; break; }
  $i++;
}
if ($target !== false) {
  unset($xml->message[$target]);
}

You can even remove multiple elements with this, by storing the order number of target items in an array. Just remember to do the removal in a reverse order (array_reverse($targets)), because removing an item naturally reduces the order number of the items that come after it.

Admittedly, it's a bit of a hackaround, but it seems to work fine.

Ilari Kajaste