如何通过 DOM 对象重命名 SimpleXML 中的标签?

发布于 2024-11-24 01:04:38 字数 873 浏览 0 评论 0原文

问题看起来很简单,但我无法访问 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);

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

抹茶夏天i‖ 2024-12-01 01:04:38

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

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

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

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.

秋风の叶未落 2024-12-01 01:04:38

也许更简单的方法是使用 XML 源字符串的 preg 函数替换标签?

更简洁的方法

创建 XSLT XML 转换文件并使用 xsl PHP 扩展对其进行转换。

为此,请参阅此答案 - 使用 XSLT 重命名节点
PHP 代码部分可以在 PHP 文档中找到。

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.

梦里人 2024-12-01 01:04:38

这是否可以在不复制整个对象的情况下完成?

不,不是。

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

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.

爱要勇敢去追 2024-12-01 01:04:38

相当晚了,但我通过替换 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);
}

旁注:这个函数可以简化,但我很快重写了这个函数,以便将其发布到这里。我使用的原始函数看起来有点不同

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文