2024 年日本 PHP 大會

DOMNode::removeChild

(PHP 5、PHP 7、PHP 8)

DOMNode::removeChild 從子節點列表中移除子節點

描述

public DOMNode::removeChild(DOMNode $child): DOMNode|false

此函式會從子節點列表中移除子節點。

參數

child

要移除的子節點。

回傳值

如果可以移除子節點,函式會傳回舊的子節點,否則在發生錯誤時傳回 false

錯誤/例外

DOM_NO_MODIFICATION_ALLOWED_ERR

如果此節點是唯讀的,則會引發此錯誤。

DOM_NOT_FOUND_ERR

如果 child 不是此節點的子節點,則會引發此錯誤。

範例

以下範例將刪除 XML 文件中的 chapter 元素。

範例 #1 移除子節點

<?php

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

$book = $doc->documentElement;

// 我們取得 chapter 並將其從 book 中移除
$chapter = $book->getElementsByTagName('chapter')->item(0);
$oldchapter = $book->removeChild($chapter);

echo
$doc->saveXML();
?>

上述範例將輸出

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" 
          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">
<book id="listing">
 <title>My lists</title>
 
</book>

參見

新增附註

使用者提供的附註 14 則附註

crazy888s at hotmail dot com
15 年前
當你在 foreach 迴圈中迭代 DOMNodeList 時,你不能從中移除 DOMNode。例如...

<?php
$domNodeList
= $domDocument->getElementsByTagname('p');
foreach (
$domNodeList as $domElement ) {
// ...對 $domElement 執行操作...
$domElement->parentNode->removeChild($domElement);
}
?>

... 會看起來讓 foreach 上的內部迭代器混亂,結果會很奇怪。不過,製作要移除的項目佇列似乎有效。例如...

<?php
$domNodeList
= $domDocument->getElementsByTagname('p');
$domElemsToRemove = array();
foreach (
$domNodeList as $domElement ) {
// ...對 $domElement 執行操作...
$domElemsToRemove[] = $domElement;
}
foreach(
$domElemsToRemove as $domElement ){
$domElement->parentNode->removeChild($domElement);
}
?>
blaine (at) blainegarrett (dot com)
19 年前
這可能很明顯,但可能也可以幫助到其他人...

如果你只是有一個你需要移除的節點(可能是從 xpath 中),而且你不知道父節點 (範例似乎假設你有變數中的父節點),那麼你可以簡單地這樣做...

$node->parentNode->removeChild($node);

parentNode 是元素的純量屬性。

希望對你有幫助。

--
Blaine Garrett
vsematika at centrum dot cz
19 年前
對於那些不了解 >sbeam at onsetcorps dot net on 02-Feb-2005 12:07< 的「hack」的人,這裡有一些討論

第一個但*錯誤*的嘗試會是
<?php
foreach ($parent->childNodes as $child) {
$parent->removeChild($child);
?>
這不起作用,因為 DOM 樹會即時修改,這會讓 foreach 迴圈混亂。

sbeam 的技巧背後的想法是,在第一次迭代中移除第一個項目後,childNodes 節點清單中的第二個項目會立即變成第一個項目。這就是為什麼我們必須_始終_移除第一個子節點。這是另一個實作

<?php
$count
= $parent->childNodes->length;
for (
$i = 0; $i < $count; $i++) {
$oldNode = $parent->removeChild($parent->childNodes->item(0)); // !!! 不是 item($i) !!!
}
?>
Justin Sheckler
15 年前
這兩個函式可能對任何嘗試刪除節點及其所有子節點的人有幫助

<?php
function deleteNode($node) {
deleteChildren($node);
$parent = $node->parentNode;
$oldnode = $parent->removeChild($node);
}

function
deleteChildren($node) {
while (isset(
$node->firstChild)) {
deleteChildren($node->firstChild);
$node->removeChild($node->firstChild);
}
}
?>
Justin Carlson
15 年前
只是個注意事項,如果你移除節點,如果你儲存檔案,它所佔據的空白字元將會保留。

為了避免這種情況,請使用 $document->preserveWhiteSpace = false;

例如

<?php
$document
= new DomDocument();
$document->preserveWhiteSpace = false;
?>
Michael D (DigitalGemstones.com)
16 年前
請注意,迭代 childNodes 陣列並移除這些子節點會停止迭代。

例如
<?php
foreach($node->childNodes as $child)
{
if(
iWantToDeleteThisNode($child))
$child->parentNode->removeChild($child);
}
?>

不會work。請注意,在移除節點時,childNodes 陣列會被重建(看起來是這樣),因此只會移除第一個項目。為了正確移除所有您想要移除的子節點,您需要執行類似以下的操作

<?php
$nodesToDelete
= array();
foreach(
$node->childNodes as $child)
{
if(
iWantToDeleteThisNode($child))
$nodesToDelete[] = $child;
}
foreach(
$nodesToDelete as $node)
{
$node->parentNode->removeChild($node);
}
?>

我相信這實際上比第一個程式碼片段更有效率(如果它的確能work的話),但顯然我無法進行基準測試。
nggit@phpindonesia
5 年前
您可以使用 foreach 從 DOMNodeList 中移除多個元素,前提是您使用暫存陣列或透過 XPath 查詢。
如果不是,最簡單的方法將是

<?php

while ($element = $nodeList->item(0)) {
$element->parentNode->removeChild($element);
}

?>
Kenney
11 年前
此方法將移除所有子節點,但保留屬性(和命名空間宣告)不變。

<?php
function removeChildren( &$node )
{
$node->parentNode->replaceChild(
$n = $node->cloneNode( false ),
$node );

$node = $n;
}
?>
Wala
16 年前
我使用以下程式碼來刪除使用子元素的整個節點

<?php
$childElement
->parentNode->parentNode-> removeChild($childElement->parentNode);
?>

如果沒有所有參與這個討論串的人的幫助,我不可能想到這一點。

謝謝!

(我必須在 parentNode->removeChild 之間引入額外的空格,以擺脫在發布此筆記時的 wordwrap() 警告)
drimsun at gmail dot com
14 年前
如果您嘗試移除巢狀節點的子節點(例如,包含另一個 <ul> 的 <ul> 列表),並且只移除第一層的子節點,您將會得到一個混亂的節點物件。

在重新使用混亂的節點時,您會收到一則錯誤訊息,上面寫著:「致命錯誤:在非物件上呼叫成員函數 blahblah()」。

若要移除所有子節點,請改用此遞迴函數
<?php
/**
* 輔助函數,以遞迴方式移除 $node 的所有子節點
* (即,包含子節點的子節點等等)。
*/
function remove_children(&$node) {
while (
$node->firstChild) {
while (
$node->firstChild->firstChild) {
remove_children($node->firstChild);
}
$node->removeChild($node->firstChild);
}
}
?>
tim cameron ryan
16 年前
或是類似的東西

<?php

while ($node->childNodes->length)
$node->removeChild($node->firstChild);

?>
pedro at leb dot usp dot br
19 年前
您也可以使用 hasChild 函數
<?php

while($node->hasChildNodes()) {
$node->removeChild($node->childNodes->item(0));
}

?>

當您移除 childNode 時,下一個節點會變成第一個!
mytto at openxtrem dot com
19 年前
再次回到移除子節點和迭代器的強健性。

當您只想根據特定條件移除「某些」節點時,事情會變得更加複雜。那麼您就不能只是重複移除第一個節點。

訣竅是將節點清單的內容複製到比 DOMNodeList 更強健的集合中,我稱之為陣列!

例如,以下程式碼片段將移除所有空的子節點

<?php
// 複製 childNodes 陣列
$childNodes = array();
foreach(
$node->childNodes as $childNode) {
$childNodes[] = $childNode;
}

// 使用副本瀏覽
foreach ($childNodes as $childNode) {
if (!
$childNode->hasChildNodes()); {
$childNode->parentNode->removeChild($childNode);
}
}
?>
Vasil Rangelov
17 年前
在撰寫本文時,我認為理所當然的是,removeChild() 只會移除選定的節點,但當您移除一個元素時,它的子元素不會被移除。如果您想要實現這一點,replaceChild() 就是解決方案。

以下程式碼應移除 $node DOMNode 的所有後代,無論其名稱為何
<?php
$node
->replaceChild(new DOMElement($node->nodeName), $node);
?>
如果您要取代根元素,您必須明確地使用 $node->documentElement 作為第二個引數。
To Top