在 SimpleXML for PHP 中删除具有特定属性的子级

2022-08-30 10:01:14

我有几个相同的元素,它们具有不同的属性,我使用SimpleXML访问它们:

<data>
    <seg id="A1"/>
    <seg id="A5"/>
    <seg id="A12"/>
    <seg id="A29"/>
    <seg id="A30"/>
</data>

我需要删除一个特定的seg元素,ID为“A12”,我该怎么做?我尝试过循环遍历 seg 元素并取消设置特定元素,但这不起作用,元素仍然存在。

foreach($doc->seg as $seg)
{
    if($seg['id'] == 'A12')
    {
        unset($seg);
    }
}

答案 1

虽然 SimpleXML 提供了一种删除 XML 节点的方法,但其修改功能受到一定限制。另一种解决方案是诉诸于使用 DOM 扩展。dom_import_simplexml() 将帮助您将 .SimpleXMLElementDOMElement

只是一些示例代码(使用 PHP 5.2.5 测试):

$data='<data>
    <seg id="A1"/>
    <seg id="A5"/>
    <seg id="A12"/>
    <seg id="A29"/>
    <seg id="A30"/>
</data>';
$doc=new SimpleXMLElement($data);
foreach($doc->seg as $seg)
{
    if($seg['id'] == 'A12') {
        $dom=dom_import_simplexml($seg);
        $dom->parentNode->removeChild($dom);
    }
}
echo $doc->asXml();

输出

<?xml version="1.0"?>
<data><seg id="A1"/><seg id="A5"/><seg id="A29"/><seg id="A30"/></data>

顺便说一句:当您使用XPath(SimpleXMLElement->xpath)时,选择特定节点要简单得多:

$segs=$doc->xpath('//seq[@id="A12"]');
if (count($segs)>=1) {
    $seg=$segs[0];
}
// same deletion procedure as above

答案 2

与对现有答案的普遍看法相反,每个Simplexml元素节点都可以单独从文档中删除。万一的要点是你需要了解SimpleXML的实际工作原理。unset()

首先找到要删除的元素:

list($element) = $doc->xpath('/*/seg[@id="A12"]');

然后删除在 unset 其自引用中表示的元素:$element

unset($element[0]);

这是有效的,因为任何元素的第一个元素都是Simplexml(自引用)中的元素本身。这与其神奇的性质有关,数字索引表示任何列表中的元素(例如父>子级),甚至单个子级也是这样的列表。

非数字字符串索引表示属性(在数组访问中)或子元素(在属性访问中)。

因此,属性访问中的数字猥亵,例如:

unset($element->{0});

也工作。

当然,对于这个xpath的例子,它是相当直接的(在PHP 5.4中):

unset($doc->xpath('/*/seg[@id="A12"]')[0][0]);

完整的示例代码(演示):

<?php
/**
 * Remove a child with a specific attribute, in SimpleXML for PHP
 * @link http://stackoverflow.com/a/16062633/367456
 */

$data=<<<DATA
<data>
    <seg id="A1"/>
    <seg id="A5"/>
    <seg id="A12"/>
    <seg id="A29"/>
    <seg id="A30"/>
</data>
DATA;


$doc = new SimpleXMLElement($data);

unset($doc->xpath('seg[@id="A12"]')[0]->{0});

$doc->asXml('php://output');

输出:

<?xml version="1.0"?>
<data>
    <seg id="A1"/>
    <seg id="A5"/>

    <seg id="A29"/>
    <seg id="A30"/>
</data>

推荐