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

发布于 2024-09-12 07:06:23 字数 415 浏览 9 评论 0原文

假设我有 XML:

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

如何在 As 和 Cs 之间插入“nodeB”?在 PHP 中,最好通过 SimpleXML?喜欢:

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

say I have XML:

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

How do I insert "nodeB" between As and Cs? In PHP, preferably via SimpleXML? Like:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

流年里的时光 2024-09-19 07:06:23

以下是在其他 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();

如果您想要/需要解释其工作原理(代码相当简单,但可能包含外来概念),请询问。

The following is a function to insert a new SimpleXMLElement after some other SimpleXMLElement. Since this isn't directly possible with SimpleXML, it uses some DOM classes/methods behind-the-scenes to get the job done.

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);
    }
}

And an example of how it might be used (specific to your question):

$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();

If you want/need an explanation of how this works (the code is fairly simple but might include foreign concepts), just ask.

久夏青 2024-09-19 07:06:23

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 方法,该方法允许指定一个精确的元素来插入之前的项目,但由于我现在不需要它,所以我决定不这样做。

Salathe's answer did help me, but since I used the addChild method of SimpleXMLElement, I sought a solution to make inserting children as a first child more transparent. The solution is to take that DOM based functionality and hide it in a subclass of 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;
    }
}

After all, SimpleXML allows to specify which element class to use:

$xml = simplexml_load_file($inputFile, 'SimpleXMLElementEx');

Now you can call insertChildFirst on any element to insert the new child as a first child. The method returns the new element as an SimpleXML element, so it's use is similar to addChild. Of course it would be easily possible to create an insertChild method that allows to specify an exact element to insert the item before, but since I don't need that right now, I decided not to.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文