PHP SimpleXML - Remove xpath node

2019-01-03 10:48发布

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 :-)

标签: php simplexml
4条回答
smile是对你的礼貌
2楼-- · 2019-01-03 11:30

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.

查看更多
家丑人穷心不美
3楼-- · 2019-01-03 11:40
<?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>
查看更多
Explosion°爆炸
4楼-- · 2019-01-03 11:44

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;
    }
}
查看更多
SAY GOODBYE
5楼-- · 2019-01-03 11:47

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.

查看更多
登录 后发表回答