Как выполнить итерацию по дочерним узлам с помощью цикла foreach?
Рассмотрим следующий PHP-код
<?php
$html_data =
'<html><body>
<ol>
<li><strong>Question 1</strong> Answer1</li>
<li><strong>Question 2</strong> Answer2</li>
</ol></body></html>';
$doc = new DOMDocument();
$doc->loadHTML($html_data);
$xpath = new DOMXPath($doc);
$ols = $xpath->query('//ol');
$ol = $ols->item(0);
$lis = $ol->childNodes;
foreach ($lis as $li) {
echo $li->firstChild->nodeValue."<br />";
echo $li->lastChild->nodeValue."<br />";
//echo $li->childNodes->item(0)->nodeValue."<br />";
}
?>
Если я удалю комментарий к последней строке этого кода и получу доступ к массиву объектов DOM childNodes, мой цикл foreach будет выполняться только один раз. Однако, если я получу доступ к тем же элементам, используя firstChild и lastChild, как показано выше, я смогу успешно выполнить итерацию по всем присутствующим тегам "li".
Я вообще не могу в этом разобраться. Это ошибка в PHP?
2 answers
Если бы вы не подавляли свои отчеты об ошибках, вы бы увидели, что у вас есть фатальная ошибка, которая нарушает ваш сценарий.
Для работы с элементом метод:
foreach ($lis as $li) {
if (method_exists($li->childNodes, 'item')) {
echo $li->childNodes->item(0)->nodeValue."<br />";
// To reproduce the exact output you need this line also.
// You need to display the second child (Answer)
echo $li->childNodes->item(1)->nodeValue."<br />";
}
}
Единственная разница заключалась в том, что первый сценарий
foreach ($lis as $li) {
echo $li->firstChild->nodeValue."<br />";
echo $li->lastChild->nodeValue."<br />";
//echo $li->childNodes->item(0)->nodeValue."<br />";
}
Только выбрасывает Примечание: Попытка получить свойство не-объекта, но сценарии продолжаются.
Как и в случае с методом item(), он выдает фатальную ошибку. (Неустранимая ошибка: Вызов элемента функции-члена() на не-объект). который убивает ваш скрипт.
Для получения более подробной информации о том, как вы должны выполнять итерации в этих списках узлов (для каждого или для), прочитайте комментарии с этих страниц
- http://www.php.net/manual/en/class.domnodelist.php
- http://www.php.net/manual/en/domnodelist.item.php
И у вас особенно есть эта проблема из-за конечного пробела после тегов <li>
.
Это выглядит так: сначала <li>
тег, затем пробел ' ' DOMText
элемент, затем второй тег <li>
, затем второй элемент ' ' DOMText
.
В элементе DOMText происходит сбой. Вы могли бы расчистить места, и это сработало бы.
$html_data = '<html><body><ol><li><strong>Question 1</strong> Answer1</li><li><strong>Question 2</strong> Answer2</li></ol></body></html>';
Я попытался воспроизвести вашу проблему (на PHP 5.3.14) со следующим кодом:
Interactive shell
php > $xml = <<<XML
<<< > <root>
<<< > <ol>
<<< > <li><strong>Question 1</strong> Answer1</li>
<<< > <li><strong>Question 2</strong> Answer2</li>
<<< > </ol>
<<< > </root>
<<< > XML;
php > $doc = new DOMDocument();
php > $doc->loadXML($xml);
php > $xpath = new DOMXPath($doc);
php > $ols = $xpath->query('//ol');
php > $ol = $ols->item(0);
php > $lis = $xpath->query('//li', $ol);
php > foreach ($lis as $li) {
php { echo $li->firstChild->nodeValue."<br />";
php { echo $li->lastChild->nodeValue."<br />";
php { echo $li->childNodes->item(0)->nodeValue."<br />";
php { }
Question 1<br /> Answer1<br />
Question 1<br />
Question 2<br /> Answer2<br />
Question 2<br />
Как видите, у меня ничего не получилось, все работает нормально. Единственное, что я изменил, это $lis = $ol->childNodes;
на $lis = $xpath->query('//li', $ol);
, потому что в противном случае я получил текстовые узлы с пробелами между узлами <li>
, и сценарий потерпел крах.