DOMNode::replaceChild

(PHP 5, PHP 7, PHP 8)

DOMNode::replaceChild 替换子节点

描述

public DOMNode::replaceChild(DOMNode $node, DOMNode $child): DOMNode|false

此函数使用传递的新节点替换子节点 child。如果 node 已经是子节点,则不会再次添加。如果替换成功,将返回旧节点。

参数

node

新节点。它必须是目标文档的成员,即由 DOMDocument->createXXX() 方法之一创建或通过 DOMDocument::importNode 导入到文档中。

child

旧节点。

返回值

旧节点或 false 如果发生错误。

错误/异常

DOM_NO_MODIFICATION_ALLOWED_ERR

如果此节点为只读或要插入节点的先前父节点为只读,则引发此错误。

DOM_HIERARCHY_REQUEST_ERR

如果此节点的类型不允许 node 节点类型的子节点,或者要放入的节点是此节点的祖先节点或此节点本身,则引发此错误。

DOM_WRONG_DOCUMENT_ERR

如果 node 是从与创建此节点的文档不同的文档创建的,则引发此错误。

DOM_NOT_FOUND_ERR

如果 child 不是此节点的子节点,则引发此错误。

参见

添加备注

用户贡献备注 4 个备注

jb at jbpros dot com
19 年前
如果您尝试一次替换多个节点,您需要小心迭代 DOMNodeList。如果旧节点的名称与新节点的名称不同,则在替换后它将从列表中删除。使用回归循环

<?php

$xml
= new DOMDocument;
$xml->load('docfile.xml');

$elements = $xml->getElementsByTagNameNS('http://www.example.com/NS/', '*');
$i = $elements->length - 1;
while (
$i > -1) {
$element = $elements->item($i);
$ignore = false;

$newelement = $xml>createTextNode('Some new node!');
$element->parentNode->replaceChild($newelement, $element);
$i--;
}

?>

循环计数器 ($i) 将始终在列表的间隔内,因为已删除元素的索引高于计数器。
aidan at php dot net
19 年前
这是一个替换节点的简单示例

让我们这样定义 XML

<?php
$xml
= <<<XML
<?xml version="1.0"?>
<root>
<parent>
<child>bar</child>
<child>foo</child>
</parent>
</root>
XML;
?>

如果我们想替换整个 <parent> 节点,我们可以执行类似的操作

<?php
// 创建一个新的文档片段来保存新的 <parent> 节点
$parent = new DomDocument;
$parent_node = $parent ->createElement('parent');

// 添加一些子节点
$parent_node->appendChild($parent->createElement('child', 'somevalue'));
$parent_node->appendChild($parent->createElement('child', 'anothervalue'));

// 将关键字集添加到新文档中
// $parent 变量现在将新节点作为文档片段保存
$parent->appendChild($parent_node);
?>

接下来,我们需要找到旧节点

<?php
// 加载 XML
$dom = new DomDocument;
$dom->loadXML($xml);

// 定位旧的 parent 节点
$xpath = new DOMXpath($dom);
$nodelist = $xpath->query('/root/parent');
$oldnode = $nodelist->item(0);
?>

然后我们导入并替换新节点

<?php
// 将 $parent 文档片段加载到当前文档中
$newnode = $dom->importNode($parent->documentElement, true);

// 替换
$oldnode->parentNode->replaceChild($newnode, $oldnode);

// 显示
echo $dom->saveXML();
?>

我们的新节点已成功导入

<?xml version="1.0"?>
<root>
<parent><child>somevalue</child><child>anothervalue</child></parent>
</root>
franp at free dot fr
19 年前
1) 如果您的 XPath 查询返回的 NodeList 包含一个唯一的项目,或者您确定返回的项目的顺序,则可以使用 "item(n)" 语法而不是 "foreach" 语法。
这可以大大提高您的代码可读性。
正如方法名所暗示的那样,replaceChild 无法替换节点本身,而只能替换节点的子节点。
技巧是使用 `replaceChild` 方法在 XPath 查询结果的父节点上进行操作。

<?xml version="1.0" ?>
<action>
<actionGlobal>
<actionGlobalFR>sometext</actionGlobalFR>
<actionGlobal>
</action>

$frag = $doc->createElement("actionGlobalFR");
$fragA = $doc->createTextNode("anothertext");
$frag->appendChild($fragA);

$xpResult = $xp->query("/action/actionGlobal/actionGlobalFR");
$blipblip = $xpResult->item(0)->parentNode->replaceChild($ajout, $xpResult->item(0));

2) 此外,正如方法名所暗示的,`replaceChild` 不能替换节点本身,而只能替换节点的子节点。
尽管如此,仍然可以通过 XPath 指向的节点替换其子节点。
技巧是使用 `replaceChild` 方法在 XPath 查询结果的父节点上进行操作。

<?xml version="1.0" ?>
<action>
<FR>French Text</FR>
</action>

<?php
$frag
= $doc->createElement("EN");
$fragA = $doc->createTextNode("English Text");
$frag->appendChild($fragA);

$xpResult = $xp->query("/action/FR");
$blipblip = $xpResult->item(0)->parentNode->replaceChild($fragA, $xpResult->item(0));
?>

Et voil� !

这将产生
<?xml version="1.0" ?>
<action>
<EN>English Text</EN>
</action>

....................................................

3) 此外,请注意,你不能替换不存在的节点。
尽管这似乎显而易见,但很容易忘记。

考虑以下情况
<?xml version="1.0" ?>
<action>
<EN></EN>
</action>

你不能使用 `replaceChild()` 方法将其转换为
<?xml version="1.0" ?>
<action>
<EN>Some text</EN>
</action>

原因是 `<EN></EN>` 元素为空,它没有子节点(如果你考虑 `<EN></EN>` 可以写成 `<EN />`,这一点就更容易理解)。
你想要在 `<EN>` 和 `</EN>` 之间插入一些文本这一事实并不能改变它目前还没有文本,因此也没有子节点这一事实。
在处理 DOM 时,不要将你的想法当作现实。DOM 解析器并不关心你的想法。如果一个元素当前为空,那么它就没有子节点,无论你打算填充什么内容。

因此,解决问题的办法是使用 `appendChild` 而不是 `replaceChild`。

<?php
$fragA
= $doc->createTextNode("Some Text");
$xpResult = $xp->query("/action/EN");
$blipblip = $xpResult->item(0)->appendChild($fragA);
?>

这将产生预期的结果
<?xml version="1.0" ?>
<action>
<EN>Some Text</EN>
</action>

....................................................

4) 请注意,文档中对 `replaceChild` 的描述是错误的。参数颠倒了。
正确的描述应该是
object DOMNode->replaceChild (object newnode, object oldnode)
chealer at gmail dot com
5 years ago
截至 5.6 版本,PHP 的行为仍然与 jb at jbpros dot com 报告的一致。要在循环中使用 `replaceChild()`,可以使用以下示例中更标准的模式

for ($currentNode = 0; $currentNode < $link->childNodes->length; $currentNode++) {
$child = $link->childNodes[$currentNode];

// "删除" 链接,因为链接不能包含链接
if ($child instanceof DOMElement && $child->tagName == 'a') {
$replacement = $dom->createTextNode($child->textContent);
$link->replaceChild($replacement, $child);
}
}
To Top