PHP 日本会议 2024

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 是 Element 的标量属性。

希望对您有所帮助。

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

此方法无效。请注意,在删除节点时,childNodes数组似乎会重建,因此只会删除第一个项目。为了正确删除所有要删除的子节点,您需要执行以下操作

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

我相信这实际上比第一段代码(如果有效)更有效,但我显然无法对其进行基准测试。
nggit@phpindonesia
5年前
只有当您使用临时数组或通过XPath查询时,才能使用foreach从DOMNodeList中删除多个元素。
如果不是,最简单的方法是

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