13

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 isn't 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 can't do unset($xml->data->items) as that would delete everything.

Any ideas much appreciated :-)

4 Answers 4

14
<?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>
Sign up to request clarification or add additional context in comments.

2 Comments

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.
The example code only deletes one specific element, the one having item_id=456. What different behavior do you need?
13

It works like this for me. Not unset($parent); but unset($parent[0]);:

$res    = $xml->xpath('//key/k[. = "string"]/parent::*');
$parent = $res[0];
unset($parent[0]);

This works by creating a self-reference to the simplexml-element in $parent (or $res[0]).

For a more detailed explanation please see a related answer in the related question Remove a child with a specific attribute, in SimpleXML for PHP.

Comments

2

One way is to import the SimpleXML node into DOMDocument and then remove within DOMDocument. Not really straight forward, but it works:

$xml = simplexml_load_file($filename);

$result = $xml->xpath("/cardsets/cardgroup");

foreach ($result as $el)
{
    if ($el['id'] == $id)
    {
        $domRef = dom_import_simplexml($el);
        $domRef->parentNode->removeChild($domRef);
        $dom = new DOMDocument('1.0');
        $dom->preserveWhiteSpace = false;
        $dom->formatOutput = true;
        $dom->loadXML($xml->asXML());
        $dom->save($filename);
        break;
    }
}

Comments

1

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.

1 Comment

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.