6

考虑以下 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 />";
  }
  ?>

如果我删除此代码最后一行的注释并访问 childNodes DOM 对象数组,我的 foreach 循环只会执行一次。但是,如果我使用 firstChild 和 lastChild 访问相同的元素,如上所示,我可以成功地遍历所有存在的“li”标签。

我完全无法理解这一点。这是PHP中的错误吗?

4

2 回答 2

1

我尝试使用以下代码重现您的问题(在 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>并且脚本崩溃了。

于 2013-01-29T23:03:03.747 回答
1

如果您不禁止错误报告,您会看到有一个致命错误会破坏您的脚本。

为了使用item方法:

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 />";
}

仅抛出通知:尝试获取 non-object 的属性,但脚本继续。

与方法 item() 一样,它会引发致命错误。(致命错误:在非对象上调用成员函数 item())。这会杀死你的脚本。

有关如何迭代这些节点列表(foreach 与 for)的更多详细信息,请阅读这些页面的评论

<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>';
于 2013-02-04T15:49:44.953 回答