2024 年日本 PHP 研討會

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('新的節點!');
$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
20 年前
1) 如果您的 XPath 查詢返回一個只包含唯一項目的 NodeList,或者如果您確定返回項目的順序,則可以使用 "item(n)" 語法代替 "foreach" 語法。
這可以大大提高程式碼的可讀性。
顧名思義,replaceChild 無法取代節點本身,而只能取代節點的子節點。
訣竅是在 XPath 查詢結果的父節點上使用 replaceChild。

<?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 指向的節點本身,而不是它的子節點。
訣竅是在 XPath 查詢結果的父節點上使用 replaceChild。

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

瞧!

這會產生
<?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
6 年前
截至 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