DOMDocument->getElementsByTagName()

(no version information, might be only in CVS)

DOMDocument->getElementsByTagName() -- Searches for all elements with given tag name

说明

class DOMDocument {

DOMNodeList getElementsByTagName ( string name )

}

This function returns a new instance of class DOMNodeList containing the elements with a given tag name.

参数

name

The name of the tag to match on. The special value * matches all tags.

返回值

A new DOMNodeList object containing all the matched elements.


add a note add a note User Contributed Notes
captainbajoo at juno dot com
11-May-2006 01:39
Regarding the possibility of an infinite loop when altering the document tree while iterating:
We can see what really happens by investigating the keys of the NodeList. They are numeric indices starting at 0. Suppose we call getElementsByTagName('*') and receive a NodeList like this:

$nodes[0] = <root>
$nodes[1] = <first>

Iteration via foreach:

foreach ($nodes as $node)

can be re-written like this:

for ($i=0; $i < count($nodes); $i++)

On the first iteration, $nodes[$i] refers to <root>

If we happen to insert a new node immediately before the current node:

insertBefore(<infinite>, $nodes[$i])

$nodes[$i] stops referring to <root> and now refers to <infinite>; the new element takes the place of the old one (in the indexed ordering) and all subsequent nodes shift up by one.

On the next iteration, $i increments by one, so $nodes[$i] refers to <root> and the process repeats.

Here is PHP code to demonstrate:

<?php

$dom
= new DOMDocument();
$rootNode = $dom->createElement('root');
$dom->appendChild($rootNode);

$firstNode = $dom->createElement('first');
$rootNode->appendChild($firstNode);

$allnodes = $dom->getElementsByTagName('*');

for (
$i=0; ; $i++) {
 
$node = $allnodes->item($i);
  echo
"before: {$node->nodeName} ";

 
$newNode = $dom->createElement('infinite');
 
$node->parentNode->insertBefore($newNode, $node);
 
 
$node = $allnodes->item($i);
  echo
"after: {$node->nodeName} <br/>";
 
  if (
$i > 4) break; # break arbitrarily so we can see the output
}

?>

Thus, if you are able to know, within the scope of the loop, that a node has been inserted, and use for instead of foreach, you can explicitly increment the iterator once more and "skip" the node that you already visited (if that's what you want; at any rate, that's what I wanted).

"Can" doesn't mean "should," of course; this sounds like a kludge (violating the sanctity of the iterator), but use your best judgment.
captainbajoo at juno dot com
11-May-2006 09:19
(As of v5.0.5, Win32)
Altering the document structure while iterating the NodeList returned by getElementsByTagName() affects the NodeList you are iterating. Combined with the DOMNode->insertBefore() method, this is a good way to create an infinite loop!
Example:
<?php

$dom
= new DOMDocument();
$rootNode = $dom->createElement('root');
$dom->appendChild($rootNode);

$firstNode = $dom->createElement('first');
$rootNode->appendChild($firstNode);

$allnodes = $dom->getElementsByTagName('*');

foreach (
$allnodes as $node) {
 
$newNode = $dom->createElement('infinite');
 
$node->parentNode->insertBefore($newNode, $node);
}

# the loop never terminates; on the next iteration, $node <= $newNode, another 'infinite' node is created and inserted before it, and so on
?>
gem at rellim dot com
30-Sep-2004 07:20
Here is an example of getElementsByTagName():

<?php
$xml
=<<<EOT
<?xml version="1.0"?>
<config>
  <section id="section1">
   <param name="param1">value1</param>
   <param name="param2">value2</param>
  </section>
  <section id="section2">
   <param name="param3">value3</param>
  </section>
</config>
EOT;

$dom = new DomDocument;
$dom->preserveWhiteSpace = FALSE;
$dom->loadXML($xml);
$params = $dom->getElementsByTagName('param');

foreach (
$params as $param) {
       echo
$param -> getAttribute('name').'<br>';
}
?>

Expected result:
--------------
param1
param2
param3