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 个说明

91
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);
}
?>
3
blaine (at) blainegarrett (dot com)
18 年前
这可能很明显,但也可能对某人有所帮助...

如果您只需要移除一个节点(也许来自 xpath)并且不了解父节点(示例似乎假设您在变量中拥有父节点),那么您可以执行类似以下的简单操作...

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

parentNode 是 Element 的一个标量属性。

希望有帮助。

--
Blaine Garrett
6
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) !!!
}
?>
16
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);
}
}
?>
7
Justin Carlson
14 年前
注意,如果您移除节点,则它所占用的空格将在您保存文件时保留。

要避免这种情况,请使用 $document->preserveWhiteSpace = false;

例如

<?php
$document
= new DomDocument();
$document->preserveWhiteSpace = false;
?>
2
Michael D (DigitalGemstones.com)
16 年前
请注意,遍历 childNodes 数组并移除这些子节点将停止迭代。

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

这将无法正常工作。请注意,在移除节点时,childNodes 数组似乎会重建,因此只会移除第一个元素。为了正确移除所有要移除的子节点,你需要执行以下操作。

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

我相信这种方法实际上比第一个代码片段(如果它能正常工作)效率更高,但我无法进行基准测试。
1
nggit@phpindonesia
5 年前
你可以使用 foreach 从 DOMNodeList 中移除多个元素,但前提是使用临时数组或 XPath 查询。
如果不是这种情况,最简单的方法是

<?php

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

?>
1
Kenney
11 年前
这种方法会移除所有子节点,但保留属性(和命名空间声明)。

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

$node = $n;
}
?>
1
Wala
16 年前
我使用以下方法通过子元素删除整个节点

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

如果没有所有参与此线程的人的帮助,我无法想到这一点。

谢谢!

(为了消除发布此笔记时出现的 wordwrap() 警告,我必须在 parentNode->removeChild 之间添加额外的空格)
0
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);
}
}
?>
0
tim cameron ryan
16 年前
或者类似以下代码

<?php

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

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

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

?>

当你移除 childNode 时,下一个节点将成为第一个节点!
-1
mytto at openxtrem dot com
18 年前
再次谈到移除子节点和迭代器的健壮性。

当你只想根据特定条件移除“一些”节点时,事情会变得更加复杂。然后你不能只是反复移除第一个节点。

诀窍是将节点列表的内容复制到比 DOMNodeList 更健壮的集合中,我称之为数组!

例如,以下代码片段将移除所有空子节点

<?php
// 复制 childNodes 数组
$childNodes = array();
foreach(
$node->childNodes as $childNode) {
$childNodes[] = $childNode;
}

// 使用副本进行浏览
foreach ($childNodes as $childNode) {
if (!
$childNode->hasChildNodes()); {
$childNode->parentNode->removeChild($childNode);
}
}
?>
-2
Vasil Rangelov
16 年前
在撰写本文时,我认为理所当然的是,removeChild() 只能移除选定的节点,但是当你移除一个元素时,它的子元素不会被移除。如果你想实现这一点,replaceChild() 是解决方案。

以下代码应移除 $node DOMNode 的所有后代,无论其名称是什么。
<?php
$node
->replaceChild(new DOMElement($node->nodeName), $node);
?>
如果你要替换根元素,你必须使用 $node->documentElement 作为第二个参数明确声明这一点。
To Top