downloads | documentation | faq | getting help | mailing lists | licenses | wiki | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

DOMNode::replaceChild> <DOMNode::normalize
[edit] Last updated: Fri, 25 May 2012

view this page in

DOMNode::removeChild

(PHP 5)

DOMNode::removeChild 子要素群から子要素を削除する

説明

public DOMNode DOMNode::removeChild ( DOMNode $oldnode )

この関数は、子要素群から子要素を削除します。

パラメータ

oldnode

削除する子要素。

返り値

子要素の削除に成功した場合に、削除した要素を返します。

エラー / 例外

DOM_NO_MODIFICATION_ALLOWED_ERR

ノードが読み込み専用の場合に発生します。

DOM_NOT_FOUND

oldnode がこのノードの子要素でない場合に発生します。

以下の例は、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="iso-8859-1"?>
<!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>

例2 親ノードの名前空間 URI の保持

<?php

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

$book $doc->documentElement;

// chapter を取得し、それを book から削除します
$chapter $book->getElementsByTagName('chapter')->item(0);

// 名前空間 URI をコピーします
$nsuri $book->namespaceURI;

// 子ノードを削除します
$book->removeChild($chapter);

// 名前空間 URI を、親ノードにペーストします
$book->namespaceURI $nsuri;
?>

注意

注意:

このメソッドをコールすると、親ノードの DOMNode::$namespaceURI プロパティが NULL にリセットされます。上の例は、この問題の回避策を示すものです。

参考



DOMNode::replaceChild> <DOMNode::normalize
[edit] Last updated: Fri, 25 May 2012
 
add a note add a note User Contributed Notes DOMNode::removeChild
julien dot mulac at gmail dot com 13-Dec-2010 07:56
For the loop bug, you have to use the parent node of the node itself :

<?php
$nodeList
= $doc->getElementsByTagName('p');

for (
$i = 0; $i < $nodeList->length; $i++) {
    try {
       
$old_child = $nodeList->item($i)->parentNode->removeChild($nodeList->item($i));   
    } catch (
DOMException $e) {
        echo
$e->getMessage();
    }
}
?>
drimsun at gmail dot com 11-Feb-2010 08:37
If you try to remove children of a nested node (e.g. a <ul> list that contains another <ul>) and only remove the first level of child nodes, you'll get a messed-up node object.

Upon re-use of the messed-up node you'll get an error message that says: "Fatal error: Call to a member function blahblah() on a non-object".

To remove ALL child nodes, use this recursive function instead:
<?php
/**
 * Helper function that removes all child nodes of $node recursively
 * (i.e. including child nodes of the child nodes and so forth).
 */
function remove_children(&$node) {
  while (
$node->firstChild) {
    while (
$node->firstChild->firstChild) {
     
remove_children($node->firstChild);
    }
   
$node->removeChild($node->firstChild);
  }
}
?>
Justin Carlson 05-Nov-2009 04:46
Just a note, if you remove a node the whitespace it occupied will remain if you save the file.

To avoid this, use $document->preserveWhiteSpace = false;

For Example:

<?php
$document
= new DomDocument();
$document->preserveWhiteSpace = false;
?>
crazy888s at hotmail dot com 14-Apr-2009 07:50
You can't remove DOMNodes from a DOMNodeList as you're iterating over them in a foreach loop. For example...

<?php
$domNodeList
= $domDocument->getElementsByTagname('p');
foreach (
$domNodeList as $domElement ) {
 
//  ...do stuff with $domElement...
 
$domElement->parentNode->removeChild($domElement);
}
?>

... will seemingly leave the internal iterator on the foreach out of wack and results will be quite strange. Though, making a queue of items to remove seems to work. For example...

<?php
$domNodeList
= $domDocument->getElementsByTagname('p');
$domElemsToRemove = array();
foreach (
$domNodeList as $domElement ) {
 
// ...do stuff with $domElement...
 
$domElemsToRemove[] = $domElement;
}
foreach(
$domElemsToRemove as $domElement ){
 
$domElement->parentNode->removeChild($domElement);
}
?>
Justin Sheckler 30-Jan-2009 01:44
These two functions might be helpful to anyone trying to delete a node and all of its children:

<?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);
    }
}
?>
tim cameron ryan 19-Jul-2008 07:00
Or something like:

<?php

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

?>
Michael D (DigitalGemstones.com) 05-Jul-2008 10:15
Note that iterating through the childNodes array and removing those children will stop the iteration.

For example:
foreach($node->childNodes as $child)
{
  if(iWantToDeleteThisNode($child))
     $child->parentNode->removeChild($child);
}

Will not work.  Note that in removing the node, the childNodes array gets rebuilt (it seems) and so only the first item will be removed.  In order to properly remove all the children you want to remove, you will need to do something like the following:

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

I believe this is actually more efficient than the first snippet would be (if it worked) but obviously I cannot benchmark it.
Wala 04-Apr-2008 04:57
I used the following to delete an entire node using the child element:

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

I could not have thought of it without the help of everyone who contributed to this thread.

Thanks!

(I had to introduce the extra space between parentNode->removeChild to get rid of the wordwrap() warning while posting this note)
Vasil Rangelov 06-Oct-2007 04:14
At the time of writing, I suppose rightfully, removeChild() removes only the selected node, but when you remove an element, it's child elements are not removed. If you want to achieve that, replaceChild() is the solution.

The following should remove all descendants of the $node DOMNode, regardless of it's name:
<?php
$node
->replaceChild(new DOMElement($node->nodeName), $node);
?>
If you're replacing the root element, you must explicitly state that with $node->documentElement as the second argument.
lsoethout at hotmail dot com 11-Mar-2007 03:08
The previous example is not correct; it only works when the tags are direct childs of the top-level node.
Better is:

while($elem = $dom->getElementsByTagName("name")->item(0)) {
   $elem->parentNode->removeChild($elem);
}
dave at dgx dot cz 27-Aug-2006 12:10
remove all children of a given node (simple way):

$node->nodeValue = '';
mytto at openxtrem dot com 06-Sep-2005 08:20
Back again on removing childs and iterators robustness.

Things get a bit more complicated when you only want to remove 'some' nodes according to a certain condition. Then you can't just remove the first one repeatedly.

The trick is to copy the content of the node list into a more robust collection than DOMNodeList, I name array!

The following piece of code will, for instance, remove all empty child nodes:

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

// Browse with the copy    
foreach ($childNodes as $childNode) {
  if (!
$childNode->hasChildNodes()); {
   
$childNode->parentNode->removeChild($childNode);
  }
}
?>
karan 27-Aug-2005 08:48
can we directly remove a node which has some children or do we need to remove the children first.

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

echo $j;//this shows correct no of children

echo $mytn->childNodes->length;//after removing it
                                         // shows 0..correct
   
$dom->save(net.xml);

but the changes r not reflected in the xml file
blaine (at) blainegarrett (dot com) 23-Aug-2005 04:10
This might be obvious, but might help someone as well...

If you simply have a node that you need to remove (perhaps from an xpath) and don't know the parent node offhand (the examples seem to assume you have the parent in a variable), then you can do something easy like this...

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

parentNode is a scalar property of the Element.

Hope that helps.

--
Blaine Garrett
Executive Director of the Art Attack
http://theartattack.org
pedro at leb dot usp dot br 29-May-2005 10:24
You may also use the hasChild function:
<?php

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

?>

When you remove a childNode, the next node becomes the first one!
vsematika at centrum dot cz 12-Feb-2005 08:35
For those who don't understand >sbeam at onsetcorps dot net on 02-Feb-2005 12:07< 'hack', here's a little discussion:

First but *wrong* try would be:
<?php
foreach ($parent->childNodes as $child) {
  
$parent->removeChild($child);
?>
This doesn't work because DOM tree id modified on-the-fly and this confuses foreach loop.

The idea behind sbeam's trick is that after removing the first item in the first iteration, the second item in childNodes nodelist immediately becomes the first item. That's why we must _always_ remove the first child. Here's another implementation:

<?php
$count
= $parent->childNodes->length;
for (
$i = 0; $i < $count; $i++) {
  
$oldNode = $parent->removeChild($parent->childNodes->item(0)); // !!! not item($i) !!!
}
?>
sbeam at onsetcorps dot net 02-Feb-2005 02:07
remove all children of a given node:
       
while ($parent->childNodes->length) {
      $parent->removeChild($parent->childNodes->item(0));
}

 
show source | credits | stats | sitemap | contact | advertising | mirror sites