tags:

views:

1581

answers:

2

Hi, I'm a little confused as to how i can delete a parent node of something which i can find via an xpath search:

$xml = simplexml_load_file($filename);
$data = $xml->xpath('//items/info[item_id="' . $item_id . '"]');
$parent = $data[0]->xpath("parent::*");
unset($parent);

So, it finds the item id, no problems there - but the unset isnt getting rid of this <items> node. All i want to do is remove the <items>...</items> for this product. Obviously, there are loads of <items> nodes in the xml file so it cant do unset($xml->data->items) as that would delete everything.

Any ideas much appreciated :-)

A: 

I'd surely approach this problem as a filtering one - not a removing one.

Thus, copying needed nodes into another string or build up another XML document for that matter. You know what tools you use for such scenarios.

I think this not only solves your problem, but probably keeps your easier to read and understand. Not sure about performance hits, though. Tell us how many nodes you regularly work with.

pestaa
Yeah good points - but, this would result in a considerable performance hit. There can be up to 100,000 items, so filtering doesnt seem like the best option to me as i just want to get rid of one item. All i need to find is the array index of 'items' for the searched product. This way i could do unset($xml->data->items[x]); which would work
Peter John
+1  A: 
<?php
$xml = new SimpleXMLElement('<a><b/></a>');
unset($xml->b);
echo $xml->asxml();

this works as intended (removing the <b/> element fromt he document) because the __unset() method (or the equivalent in the modules code) is called.
But when you call unset($parent); it only removes the object reference stored in $parent, but it doesn't affect the object itself or the document stored in $xml. I'd revert to DOMDocument for this.

<?php
$doc = new DOMDOcument;
$doc->loadxml('<foo>
  <items>
    <info>
      <item_id>123</item_id>
    </info>
  </items>
  <items>
    <info>
      <item_id>456</item_id>
    </info>
  </items>
  <items>
    <info>
      <item_id>789</item_id>
    </info>
  </items>
</foo>');
$item_id = 456;

$xpath = new DOMXpath($doc);
foreach($xpath->query('//items[info/item_id="' . $item_id . '"]') as $node) {
  $node->parentNode->removeChild($node);
}
echo $doc->savexml();

prints

<?xml version="1.0"?>
<foo>
  <items>
    <info>
      <item_id>123</item_id>
    </info>
  </items>

  <items>
    <info>
      <item_id>789</item_id>
    </info>
  </items>
</foo>
VolkerK
Cool thanks :-) The thing is though, i have the equivalent of 100,000 <b> tags. I just want to delete the one which contains the product i have found via xpath.
Peter John
The example code only deletes one specific element, the one having item_id=456. What different behavior do you need?
VolkerK
Brilliant! This is exactly what i needed :-) Thanks mate!
Peter John