使用DOMXPath替换节点,同时保持其位置

时间:2009-03-12 22:54:23

标签: php xml dom domdocument

好的,所以我在第二天晚上为DOMDOCUMENT创建了一个帮助类,这在某种程度上模仿了jQuery操纵HTML或基于XML的字符串的DOM的能力。而不是使用css选择器,使用XPath。例如:

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

这将在每个结果节点上调用回调函数。不幸的是,PHP版本< 5.3.x不支持lambda函数或闭包,所以我暂时不得不做这样的事情:

$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复制值,属性和元素名称,但我无法更改目标元素的实际元素名称。

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

任何人

2 个答案:

答案 0 :(得分:2)

使用replaceChild而不是appendChild / removeChild。

答案 1 :(得分:0)

查看$ element是否在删除之前有一个nextsibbling如果是这样的话,那么下一个兄弟只会附加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 我是如何错过那一刻的:)