【问题标题】:Using DOMXPath to replace a node while maintaining its position使用 DOMXPath 替换节点,同时保持其位置
【发布时间】:2010-10-13 01:16:04
【问题描述】:

好的,所以那天晚上我有了一个巧妙的小想法,为 DOMDOCUMENT 创建一个帮助类,它在某种程度上模仿 jQuery 操作 HTML 或基于 XML 的字符串的 DOM 的能力。使用 XPath 代替 css 选择器。例如:

$Xml->load($source)
    ->path('//root/items')
    ->each(function($Context)
    {
        echo $Context->nodeValue;
    });

这将在每个结果节点上调用一个回调函数。不幸的是,PHP 版本

$Xml->load($source)
    ->path('//root/items')
    ->walk('printValue', 'param1', 'param2');

目前一切都很好,我认为这个项目对很多人都有用,但我坚持使用其中一个功能。我正在尝试模仿 jQuery 的“替换”方法。使用以下代码,我可以通过以下方法轻松完成此操作:

$Xml->load($source)
    ->path('//root/items')
    ->replace($Xml->createElement('foo', 'bar')); // can be an object, string or XPath pattern

这个方法背后的代码是:

public function replace($Content)
{
    foreach($this->results as $Element)
    {
        $Element->parentNode->appendChild($Content->cloneNode(true));
        $Element->parentNode->removeChild($Element);
    }

    return $this;
}

现在,这行得通。它将每个结果元素替换为 $Content 的克隆版本。问题在于它将它们添加到父节点的子节点列表的底部。问题是,我如何克隆这个元素来替换其他元素,同时仍然保留在 DOM 中的原始位置?

我正在考虑对要替换的节点进行逆向工程。基本上,从 $Content 复制值、属性和元素名称,但我无法更改目标元素的实际元素名称。

反思是可能的,但必须有更简单的方法来做到这一点。

有人吗?

【问题讨论】:

    标签: php xml dom domdocument


    【解决方案1】:

    使用 replaceChild 而不是 appendChild/removeChild。

    【讨论】:

    • 您的建议非常有效。虽然,我不得不将“importNode”与“appendChild”和“cloneNode”结合使用。工作精美!干杯!
    • 如果您使用 importNode,您也不需要克隆它,importNode 有必要克隆节点。
    【解决方案2】:

    查找 $element 在删除之前是否有下一个兄弟,如果有,则在下一个兄弟之前插入一个 insertBefore 否则只需追加。

    public function replace($Content)
    {
            foreach($this->results as $Element)
            {
                    if ($Element->nextSibling) {
                        $NextSiblingReference = $Element->nextSibling;
                        $Element->parentNode->insertBefore($Content->cloneNode(true),$NextSiblingReference);
                    }
                    else {
                        $Element->parentNode->appendChild($Content->cloneNode(true));   
                    }
                    $Element->parentNode->removeChild($Element);
            }
    
            return $this;
    }
    

    虽然完全未经测试。

    或者正如 AnthonyWJones 所建议的 replaceChild ,大 oomph 我怎么会错过那个时刻 :)

    【讨论】:

    • 嗯,我会试一试。谢谢!
    猜你喜欢
    • 2018-07-01
    • 2013-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-21
    • 2017-09-02
    • 1970-01-01
    相关资源
    最近更新 更多