XML:使用simplexml_import_dom(PHP)删除父级

时间:2017-02-18 12:21:35

标签: php xml dom

我想删除标题与$titleArray匹配的条目。 我的XML文件如下:

<products>
<product>
    <title>Battlefield 1</title>
    <url>https://www.google.de/</url>
    <price>0.80</price>
</product>
<product>
    <title>Battlefield 2</title>
    <url>https://www.google.de/</url>
    <price>180</price>
</product>
</products>

这是我的代码,但我认为它不起作用,我的IDE在这里说$node->removeChild($product); - &gt; “期望的DOMNode,得到了DOMNodeList”

有什么问题,我该如何解决?

function removeProduct($dom, $productTag,  $pathXML, $titleArray){

$doc = simplexml_import_dom($dom);

$items = $doc->xpath($pathXML);
foreach ($items as $item) {
    $node = dom_import_simplexml($item);

    foreach ($titleArray as $title) {
        if (mb_stripos($node->textContent, $title) !== false) {
            $product = $node->parentNode->getElementsByTagName($productTag);
            $node->removeChild($product);
        }
    }
}
}

谢谢你和问候!

1 个答案:

答案 0 :(得分:0)

获取节点的大多数DOM方法都返回节点列表。您可以拥有多个具有相同名称的元素节点。因此结果将是一个列表(如果找不到任何内容,则为空列表)。您可以遍历列表并将逻辑应用于列表中的每个节点。

这个方法有两个问题。删除节点会修改文档。因此,您必须小心不要删除之后仍在使用的节点。它可能导致任何意想不到的结果。 DOMNode::getElementsByTagName()返回一个节点列表,它是一个“实时”结果。如果删除列表实际更改的第一个节点,而不仅仅是XML文档。

DOMXpath::evaluate()同时解决了两个问题。结果不是“实时”,因此您可以使用foreach()迭代结果并删除节点。 Xpath表达式允许条件,因此您可以筛选和获取特定节点。不幸的是,Xpath 1.0现在有小写方法,但你可以回调PHP。

function isTitleInArray($title) {
  $titles = [
    'battlefield 2'
  ];
  return in_array(mb_strtolower($title, 'UTF-8'), $titles);
}

$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
$xpath->registerNamespace("php", "http://php.net/xpath");
$xpath->registerPHPFunctions('isTitleInArray');

$expression = '//product[php:function("isTitleInArray", normalize-space(title))]';
foreach ($xpath->evaluate($expression) as $product) {  
  $product->parentNode->removeChild($product);
}

echo $document->saveXml();

输出:

<?xml version="1.0"?>
<products>
<product>
    <title>Battlefield 1</title>
    <url>https://www.google.de/</url>
    <price>0.80</price>
</product>

</products>