如何通过DOM对象在SimpleXML中重命名标记?

时间:2011-07-14 14:34:59

标签: php dom simplexml

问题似乎很简单,但我无法访问SimpleXMLElement的标记名称。

假设我有以下XML结构:

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

我希望它看起来像这样:

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

这可以不做整个对象的副本吗?

我已经开始意识到我正在接近这个问题的方式的错误。似乎我需要将我的SimpleXMLElement转换为DOM对象。这样做后,我发现以我想要的方式操作对象非常困难(显然在DOM中重命名标签并不容易做到这一点)。

所以......我能够通过导入将我的SimpleXMLElement导入到DOM对象中,但我发现很难进行克隆。

以下是克隆DOM对象背后的正确想法,还是我仍然离开:

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

4 个答案:

答案 0 :(得分:6)

这可能是在不使用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);
}

您可以这样使用:

$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());

它将使用具有新名称的克隆替换旧节点。

但请注意,这是原始节点内容的副本。如果您有任何指向旧节点的变量,它们现在无效。

答案 1 :(得分:3)

可能更简单的方法是使用XML源代码字符串的preg函数替换标签?

清洁方式

创建XSLT XML转换文件并使用xsl PHP扩展来翻译它。

为此,请参阅此答案 - Rename nodes with XSLT。 PHP代码部分可以在PHP文档中找到。

答案 2 :(得分:0)

  

这可以不做整个对象的副本吗?

不,不是。

你可以通过“身份转换”在XSLT中完成。如果您搜索“重命名标记”和“身份转换”,您应该找到一些示例,假设XSLT是一个选项。

答案 3 :(得分:0)

相当晚,但我通过替换xml中的地狱来想出了解决方案。我认为这可能对某些人有所帮助,因为我无法在网上找到任何好的解决方案而不会复制所有孩子。

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

旁注:此功能可以简化,但我很快重写了这个功能,以便在此发布。我使用的原始功能看起来有点不同