PHP SimpleXML:在特定位置插入节点

14

假设我有一个XML:

<root>
  <nodeA />
  <nodeA />
  <nodeA />
  <nodeC />
  <nodeC />
  <nodeC />
</root>

我该如何在As和Cs之间插入"nodeB"呢?最好用PHP的SimpleXML方式实现。像这样:

<root>
  <nodeA />
  <nodeA />
  <nodeA />
  <nodeB />
  <nodeC />
  <nodeC />
  <nodeC />
</root>

2
我不确定你能不能做到。从文档上看,SimpleXML似乎只适用于非常简单的操作。 - MvanGeest
我能不能将 Cs 存储在其他地方,然后将它们删除,添加 B ,再从临时位置添加回 Cs?我只是对 PHP 不是很熟悉... - Theo Heikonnen
2个回答

20
下面是一个在某个SimpleXMLElement之后插入新的SimpleXMLElement的函数。由于SimpleXML不能直接实现这一功能,因此它在幕后使用了一些DOM类/方法来完成任务。
function simplexml_insert_after(SimpleXMLElement $insert, SimpleXMLElement $target)
{
    $target_dom = dom_import_simplexml($target);
    $insert_dom = $target_dom->ownerDocument->importNode(dom_import_simplexml($insert), true);
    if ($target_dom->nextSibling) {
        return $target_dom->parentNode->insertBefore($insert_dom, $target_dom->nextSibling);
    } else {
        return $target_dom->parentNode->appendChild($insert_dom);
    }
}

以下是一个与您的问题相关的示例,展示了如何使用它:

$sxe = new SimpleXMLElement('<root><nodeA/><nodeA/><nodeA/><nodeC/><nodeC/><nodeC/></root>');
// New element to be inserted
$insert = new SimpleXMLElement("<nodeB/>");
// Get the last nodeA element
$target = current($sxe->xpath('//nodeA[last()]'));
// Insert the new element after the last nodeA
simplexml_insert_after($insert, $target);
// Peek at the new XML
echo $sxe->asXML();

如果您需要对此工作原理的解释(代码相当简单,但可能包含外来概念),请提出要求。


是我还是simplexml_insert_after中的$sxe参数从未被使用? - GolezTrol
1
这不是你的问题,为什么不在回答问题时玩得开心呢? :) - salathe
好啊,为什么不呢。:) 顺便说一句,谢谢你的回答。我自己用它构建了我的程序库。 :) - GolezTrol

6

Salathe的回答确实对我有帮助,但由于我使用了SimpleXMLElement的addChild方法,因此我寻求一种使插入子元素作为第一个子元素更加透明的解决方案。解决方案是将基于DOM的功能隐藏在SimpleXMLElement的子类中:

class SimpleXMLElementEx extends SimpleXMLElement
{
    public function insertChildFirst($name, $value, $namespace)
    {
        // Convert ourselves to DOM.
        $targetDom = dom_import_simplexml($this);
        // Check for children
        $hasChildren = $targetDom->hasChildNodes();

        // Create the new childnode.
        $newNode = $this->addChild($name, $value, $namespace);

        // Put in the first position.
        if ($hasChildren)
        {
            $newNodeDom = $targetDom->ownerDocument->importNode(dom_import_simplexml($newNode), true);
            $targetDom->insertBefore($newNodeDom, $targetDom->firstChild);
        }

        // Return the new node.
        return $newNode;
    }
}

毕竟,SimpleXML允许指定要使用哪个元素类:
$xml = simplexml_load_file($inputFile, 'SimpleXMLElementEx');

现在您可以在任何元素上调用insertChildFirst来将新子元素插入为第一个子元素。该方法返回一个SimpleXML元素作为新元素,因此其用法类似于addChild。当然,很容易创建一个insertChild方法,允许在插入项目之前指定精确的元素,但由于我现在不需要,所以我决定不这样做。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接