PHP Conference Japan 2024

DOMNodeList::item

(PHP 5, PHP 7, PHP 8)

DOMNodeList::item 擷取由索引指定的節點

說明

public DOMNodeList::item(int $index): DOMElement|DOMNode|DOMNameSpaceNode|null

DOMNodeList 物件中擷取由 index 指定的節點。

提示

如果您需要知道集合中的節點數量,請使用 DOMNodeList 物件的 length 屬性。

參數

index

集合中節點的索引。

返回值

DOMNodeList 中位於 index 位置的節點,如果該索引無效,則返回 null

範例

範例 #1 遍歷表格中的所有項目

<?php

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

$items = $doc->getElementsByTagName('entry');

for (
$i = 0; $i < $items->length; $i++) {
echo
$items->item($i)->nodeValue . "\n";
}

?>

範例 #2 使用陣列語法存取項目

<?php

for ($i = 0; $i < $items->length; $i++) {
echo
$items[$i]->nodeValue . "\n";
}

?>

範例 #3 使用 foreach 遍歷項目

<?php

foreach ($items as $item) {
echo
$item->nodeValue . "\n";
}

?>

以上範例將輸出

Title
Author
Language
ISBN
The Grapes of Wrath
John Steinbeck
en
0140186409
The Pearl
John Steinbeck
en
014017737X
Samarcande
Amine Maalouf
fr
2253051209

新增註釋

使用者貢獻的註釋 9 則註釋

vinyanov at poczta dot onet dot pl
16 年前
SimpleXML 有它自己的 SPL 迭代器。參考 https://php.dev.org.tw/~helly/php/ext/spl/classSimpleXMLIterator.html。但我猜 DOM 節點沒有。順便一提,我在網路上找到的三個實作範例中有兩個不是遞迴的,所以我寫了自己的。以下是程式碼片段:

<?php

class DOMNodeListIterator implements RecursiveIterator
{
private
$nodes,
$offset;

function
__construct(DOMNodeList $nodes)
{
$this->nodes = $nodes;
return
$this;
}

function
rewind()
{
$this->offset = 0;
return;

}

function
current()
{
return
$this->nodes->item($this->offset);
}

function
key()
{
return
$this->current()->nodeName;
}

function
next()
{
$this->offset++;
return;

}

function
valid()
{
return
$this->offset < $this->nodes->length;
}

function
hasChildren()
{
return isset(
$this->current()->childNodes->length) && $this->current()->childNodes->length > 0;
}

function
getChildren()
{
return new
self($this->current()->childNodes);
}
}

?>
在建立迭代器時,記得使用 RecursiveIteratorIterator::SELF_FIRST 旗標。

<?php

$iterator
= new DOMNodeListIterator($document->childNodes);
$iterator = new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::SELF_FIRST);

?>
應該可以運作,雖然只測試了幾分鐘。 :)
Geoffrey Thubron
17 年前
@ tfg_allardyce at gmail dot com

你可以反向遍歷列表,這樣你每次都只會從列表中移除最後一個項目,因此不會打亂順序。
匿名
12 年前
以大於 domnodelist->length - 1 的索引 $i 呼叫 domnodelist->item($i) 時,會返回整個文件,不會產生錯誤,也不會循環回到列表的開頭。
Nagy Attila
13 年前
DOMNodeList::item 的回傳並非固定時間!

如果您需要迭代大型節點列表,最好使用標準導航方式。

您可以這樣做,而不是

<?php
foreach ($nodelist as $node) {
// 做一些事情
}
?>

您可以這樣做

<?php
$node
= $parentnode->firstChild;

do {
// 做一些事情
} while ($node = $node->nextSibling);
?>
jeffpuckett2 at gmail dot com
8 年前
DOMNodelist::item 可以返回一個繼承 DOMNode 類別的 DOMElement 物件。但它也可以返回一個 DOMText 物件。

<?php
$xml
= '
<root>
<node/>
<node>
<sub>更多</sub>
</node>
<node>
<sub>另一個</sub>
</node>
<node>值</node>
</root>
'
;

$doc = new DOMDocument();
$doc->loadXML($xml);

$items = $doc->documentElement->childNodes;
for (
$i = 0; $i < $items->length; $i++)
echo
get_class($items->item($i)).PHP_EOL;
?>

結果輸出如下

DOMText
DOMElement
DOMText
DOMElement
DOMText
DOMElement
DOMText
DOMElement
DOMText
Hayley Watson
17 年前
請記住,DOMNodelists 是「動態的」—— 對衍生 DOMNodelist 的文件或節點所做的更改將反映在 DOMNodelist 中。換句話說,如果您更改父節點的子節點,則父節點子節點的列表也會更改!
olivier dot berger at it-sudparis dot eu
16 年前
當 zend.ze1_compatibility_mode 啟用時,迭代 items 列表的唯一方法似乎是使用
for ($i = 0; $i < $nodeList->length; ++$i) {
$nodeName = $nodeList->item($i)->nodeName;
$nodeValue = $nodeList->item($i)->nodeValue;
}

因為其他嘗試都失敗了

for ($i = 0; $i < $nodeList->length; ++$i) {
$node = &$nodeList->item($i);
$nodeName = $node->nodeName;
$nodeValue = $node->nodeValue;
}

或者
foreach ($nodeList as $node) {
echo $node->nodeName;
echo $node->nodeValue;
}
james dot dunmore at gmai dot com
17 年前
tfg_allardyce@gmail.com

我遇到了完全相同的問題。

為了修正這個問題,我必須這樣做
<?php
$old_element
= $doc->getElementsByTagName('Element1')->item(0);
$new_element = $doc->createElement('NewElement1');

$old_element_childNodes = $old_element->childNodes;
$length = $old_element_childNodes->length;

for(
$i = 0; $i < $length; $i++)
{
$oldChildren_array[] = $old_element_childNodes->item($i);
}

foreach(
$oldChildren_array as $old_c)
{
$new_element->appendChild($old_c);
}
?>

而不是像這樣
(我會回報這個 bug)
<?php
$old_element
= $doc->getElementsByTagName('Element1')->item(0);
$new_element = $doc->createElement('NewElement1');

foreach(
$old_element->childNodes as $node)
{
$new_element->appendChild($node);
}

?>

使用後者的方法,會隨機移除子節點!
oliver.christen@camptocamp.com
17 年前
NodeList 很惱人,因為你無法用簡單的 print_r 輸出內容,所以我寫了一個小函式,將所有節點添加到一個新的空的 DOMDocument 中,並將其作為字串輸出。
祝使用愉快。

<?php

public function domNodeList_to_string($DomNodeList) {
$output = '';
$doc = new DOMDocument;
while (
$node = $DomNodeList->item($i) ) {
// 導入節點
$domNode = $doc->importNode($node, true);
// 附加節點
$doc->appendChild($domNode);
$i++;
}
$output = $doc->saveXML();
$output = print_r($output, 1);
// 我加了這行,因為 XML 輸出和 AJAX 不相容
$output = htmlspecialchars($output);
return
$output;
}

?>
To Top