开发者

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

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->开发者_如何学PythoncreateElement('new');

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

$old->ownerDocument->appendChild($new);
$new->ownerDocument->removeChild($old);


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.


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.


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

Nope, it's not.

You could do it in XSLT via an "identity transform". If you search around for "rename tag" and "identity transform" you should find a few examples, assuming XSLT is an option.


Rather late but I came up with the fallowing solution by replacing the hell out of the xml. I thought this might help some people as I couldnt find any good solution on the web without copying all children.

function RenameNode(SimpleXMLElement $Entire_XML, SimpleXMLElement $Node, $New_Title) 
{    
    $Full_XML   = $Entire_XML->asXML();
    $Old_Title  = $Node->getName();
    $XML_String = $Node->asXML();
    $Replaced   = preg_replace("/$Old_Title/", $New_Title, $XML_String, 1);

    if (count($Node->children())>0) 
    {
        $Replaced = strrev(
            preg_replace(
                strrev("/$Old_Title/"), 
                strrev($New_Title), 
                strrev($Replaced), 
                1
            )
        );    
    }

    $Full_XML = str_replace($XML_String, $Replaced, $Full_XML);

    return simplexml_load_string($Full_XML);
}

Sidenote: This function can be simplified but I quickly rewrote this function in order to post this here. The original function I use looks a little bit different

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜