[ACCEPTED]-How can I change the name of an element in DOM?-dom

Accepted answer
Score: 18

Could you use importNode() to copy the childNodes of 6 your <identity> element to a newly created <person> element?

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

Perhaps 5 something like that would work, or you could 4 try using cloneChild().

Edit: Actually, I just realized 3 that the original function would lose the 2 placement of the node. As per the question 1 thomasrutter linked to, replaceChild() should be used.

Score: 12

Thanks to your post, I could quickly solve 14 the same issue for me. However, I had a 13 DOM_NOT_FOUND exception. This is probably 12 a PHP Version issue, since the original 11 post is 5 years old.

According to the PHP 10 Documentation (Feb 2014)

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

So, I have replaced

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

with

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

Here 9 is the complete function (tested):

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

It is 8 also worth mentioning that when you want 7 to use this function, you should traverse 6 the DOM Tree in reversed order as explained 5 in other posts.

UPDATE: After months of using 4 and updating to PHP Version 5.5.15 on windows, I 3 had an error saying $attr could not be converted 2 to a string. So I updated third for-each 1 loop above.

Score: 1

NOTE: I tried Calvin's code and it sort 13 of worked for me but not quite. If the tag 12 I was replacing had nested tags, some child 11 tags would sometimes get lost.

The reason 10 is that childNodes is a live DOMNodeList of a node's children, and 9 appendChild moves the nodes around in the DOM, thus 8 affecting the list ordering. If you just 7 do foreach on a childNodes the loop can skip some 6 children.

My solution was to use a while 5 loop. This way you don't have to copy any 4 nodes to an array.

I have packaged everything 3 in a convenient function that takes a string 2 and returns a string and should work with 1 utf-8. The following is tested in 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');

Prints:

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

More Related questions