【问题标题】:How can I change the name of an element in DOM?如何更改 DOM 中元素的名称?
【发布时间】:2010-10-21 00:38:38
【问题描述】:

在带有 DOM 的 PHP 中,我有一个代表 元素的 DomElement 对象。

我有一种情况需要更改它,使其元素名称为 ,但保持相同的子元素和属性。

更改 DomElement 的元素名称并保留其子元素和属性的最简单方法是什么?

编辑:我刚刚找到了very similar question(虽然它没有很好的答案)。

【问题讨论】:

    标签: php xml dom


    【解决方案1】:

    您能否使用importNode() 将您的<identity> 元素的childNodes 复制到新创建的<person> 元素?

    function changeName($node, $name) {
        $newnode = $node->ownerDocument->createElement($name);
        foreach ($node->childNodes as $child){
            $child = $node->ownerDocument->importNode($child, true);
            $newnode->appendChild($child, true);
        }
        foreach ($node->attributes as $attrName => $attrNode) {
            $newnode->setAttribute($attrName, $attrNode);
        }
        $newnode->ownerDocument->replaceChild($newnode, $node);
        return $newnode;
    }
    
    $domElement = changeName($domElement, 'person');
    

    也许类似的方法会起作用,或者您可以尝试使用cloneChild()。

    编辑:实际上,我刚刚意识到原来的函数会丢失节点的位置。根据 thomasrutter 链接到的问题,应该使用 replaceChild()。

    【讨论】:

    • 谢谢。我最终使用了与此非常相似的解决方案。
    【解决方案2】:

    感谢您的帖子,我可以快速为我解决同样的问题。但是,我有一个 DOM_NOT_FOUND 异常。这可能是 PHP 版本的问题,因为原始帖子已有 5 年历史了。

    根据 PHP 文档(2014 年 2 月)

    DOM_NOT_FOUND
      Raised if oldnode is not a child of this node. 
    

    所以,我换了

    $newnode->ownerDocument->replaceChild($newnode, $node);
    

    与

    $node->parentNode->replaceChild($newnode, $node);
    

    这是完整的功能(已测试):

    public static function changeTagName($node, $name) {
        $childnodes = array();
        foreach ($node->childNodes as $child){
            $childnodes[] = $child;
        }
        $newnode = $node->ownerDocument->createElement($name);
        foreach ($childnodes as $child){
            $child2 = $node->ownerDocument->importNode($child, true);
            $newnode->appendChild($child2);
        }
        foreach ($node->attributes as $attrName => $attrNode) {
            $attrName = $attrNode->nodeName;
            $attrValue = $attrNode->nodeValue;
            $newnode->setAttribute($attrName, $attrValue);
        }
        $node->parentNode->replaceChild($newnode, $node);
        return $newnode;
    }
    

    另外值得一提的是,当你想使用这个功能时,你应该按照其他帖子中解释的相反顺序遍历DOM树。

    更新:在 Windows 上使用并更新到 PHP 5.5.15 版数月后,我收到一条错误消息,提示无法将 $attr 转换为字符串。所以我更新了上面的第三个 for-each 循环。

    【讨论】:

    • 谢谢,我遇到了同样的异常。此外,$node 不一定有父元素,尤其是当您导入格式不正确的 html 字符串(如<div>Partial HTML</div>)时。在这种情况下,应该在之前调用DOMDocument 上的normalize() 方法。
    【解决方案3】:

    注意:我尝试了 Calvin 的代码,它对我有用,但并不完全。如果我要替换的标签有嵌套标签,一些子标签有时会丢失。

    原因是 childNodes 是一个节点的子节点的 live DOMNodeList,appendChild 在 DOM 中移动节点,从而影响列表排序。如果您只是在 childNodes 上执行 foreach,则循环可以跳过一些子节点。

    我的解决方案是使用 while 循环。这样您就不必将任何节点复制到数组中。

    我已将所有内容打包在一个方便的函数中,该函数接受一个字符串并返回一个字符串,并且应该可以使用 utf-8。以下是在 PHP 5.5.9 中测试的。

    function renameTags($html, $oldname, $name) {
        $dom = new DOMDocument( '1.0', 'utf-8' );
        $fragment = $dom->createDocumentFragment();
        if ( $fragment->appendXML( $html ) ) {
            $dom->appendChild( $fragment );
    
            $nodesToAlter = $dom->getElementsByTagName( $oldname );
    
            while ($nodesToAlter->length) {
                $node = $nodesToAlter->item(0);
    
                $newnode = $node->ownerDocument->createElement($name);
    
                while ($node->hasChildNodes()) {
                    $child = $node->childNodes->item(0);
                    $child = $node->ownerDocument->importNode($child, true);
                    $newnode->appendChild($child);
                }
                foreach ($node->attributes as $attr) {
                    $attrName = $attr->nodeName;
                    $attrValue = $attr->nodeValue;
                    $newnode->setAttribute($attrName, $attrValue);
                }
                $newnode->ownerDocument->replaceChild($newnode, $node);
    
            }
            return $dom->saveHTML();
        } else {
            //error
        }
    }
    
    
    $html = 'Testing <b foo="bar" baz="foo">nested tags in <i lol="cat"> html strings</i></b> and <b>stuff</b>';
    
    echo renameTags($html, 'b', 'strong');
    

    打印:

    Testing <strong foo="bar" baz="foo">nested tags in <i lol="cat"> html strings</i></strong> and <strong>stuff</strong>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多