Как выполнить итерацию по дочерним узлам с помощью цикла 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?

Author: kenorb, 2013-01-27

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(), он выдает фатальную ошибку. (Неустранимая ошибка: Вызов элемента функции-члена() на не-объект). который убивает ваш скрипт.

Для получения более подробной информации о том, как вы должны выполнять итерации в этих списках узлов (для каждого или для), прочитайте комментарии с этих страниц

И у вас особенно есть эта проблема из-за конечного пробела после тегов <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>';
 1
Author: alex.dominte, 2013-02-04 16:15:09

Я попытался воспроизвести вашу проблему (на 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>, и сценарий потерпел крах.

 1
Author: Fabian Schmengler, 2013-01-29 23:03:03