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 Object Arrayにアクセスすると、foreachループは1回だけ実行されます。ただし、上記のようにfirstChildとlastChildを使用して同じ要素にアクセスすると、存在するすべての「li」タグを正常に反復できます。

私はこれをまったく理解できません。これはPHPのバグですか?

4

2 に答える 2

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

注意: 非オブジェクトのプロパティを取得しようとしていますが、スクリプトは続行されます。

メソッド item() と同様に、致命的なエラーをスローします。(致命的なエラー: 非オブジェクトでのメンバー関数 item() の呼び出し)。これはあなたのスクリプトを殺します。

これらの nodesList (foreach と for) を反復処理する方法の詳細については、これらのページのコメントをお読みください。

<li>また、タグの後の末尾のスペースが原因で、特にこの問題が発生します。

次のようにループします: 最初の<li>タグ、次にスペース' ' DOMText要素、2 番目の<li>タグ、2 番目の' ' 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 に答える
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 に答える