Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you rename a tag in SimpleXML through a DOM object?

Tags:

dom

php

simplexml

The problem seems straightforward, but I'm having trouble getting access to the tag name of a SimpleXMLElement.

Let's say I have the follow XML structure:

<xml>
     <oldName>Stuff</oldName>
</xml>

And I want it to look like this:

<xml>
     <newName>Stuff</newName>
</xml>

Is this possible to do without doing a copy of the entire object?

I've started to realize the errors of the ways I am approaching this problem. It seems that I need to convert my SimpleXMLElement into a DOM object. Upon doing so I find it very hard to manipulate the object in the way I want (apparently renaming tags in a DOM isn't easy to do for a reason).

So... I am able to import my SimpleXMLElement into a DOM object with the import, but I am finding it difficult to do the clone.

Is the following the right thinking behind cloning a DOM object or am I still way off:

$old = $dom->getElementsByTagName('old')->item(0); // The tag is unique in my case
$new = $dom->createElement('new');

/* ... some recursive logic to copy attributes and children of the $old node ... */

$old->ownerDocument->appendChild($new);
$new->ownerDocument->removeChild($old);
like image 782
afuzzyllama Avatar asked Dec 21 '25 06:12

afuzzyllama


2 Answers

Here's what's probably the simplest way to copy a node's children and attributes without using XSLT:

function clonishNode(DOMNode $oldNode, $newName, $newNS = null)
{
    if (isset($newNS))
    {
        $newNode = $oldNode->ownerDocument->createElementNS($newNS, $newName);
    }
    else
    {
        $newNode = $oldNode->ownerDocument->createElement($newName);
    }

    foreach ($oldNode->attributes as $attr)
    {
        $newNode->appendChild($attr->cloneNode());
    }

    foreach ($oldNode->childNodes as $child)
    {
        $newNode->appendChild($child->cloneNode(true));
    }

    $oldNode->parentNode->replaceChild($newNode, $oldNode);
}

Which you can use this way:

$dom = new DOMDocument;
$dom->loadXML('<foo><bar x="1" y="2">x<baz/>y<quux/>z</bar></foo>');

$oldNode = $dom->getElementsByTagName('bar')->item(0);
clonishNode($oldNode, 'BXR');

// Same but with a new namespace
//clonishNode($oldNode, 'newns:BXR', 'http://newns');

die($dom->saveXML());

It will replace the old node with a clone with a new name.

Attention though, this is a copy of the original node's content. If you had any variable pointing to the old nodes, they are now invalid.

like image 137
Josh Davis Avatar answered Dec 22 '25 18:12

Josh Davis


Maybe easier way would be to replace the tags using preg functions for the XML source string?

Cleaner way

Create XSLT XML transformation file and use xsl PHP extension to translate it.

For this see this answer – Rename nodes with XSLT. PHP code part could be found in PHP documentation.

like image 28
Gedrox Avatar answered Dec 22 '25 18:12

Gedrox