simple_html_dom.phpを使った構文で、質問を2つさせてください。

1.ulタグの右側の文字を表示させたいのですが。
 find( 'ul' )だと、ulの中のliを表示させてしまいます。
 find( 'ul' )->text だとnon-objectと言われる。
 *test26.phpの17,18,19行目(//はコメント)
どうすればulの右側の文字が表示されますか。

2.test26.phpの21,22,23行目(//はコメント)ulタグの中にliタグがあるので、
if (!empty( $a->value))が正しいように思いますが、
!だと何も表示されません。逆のような気がしてしょうがありません。
ヒントとなる説明のようなものをいただけると助かります。

ソースプログラムは以下2点を見てください。
PHPのプログラム:
http://1811way.com/work008/test026php.txt
ソースを表示させるために拡張子txtをつけています。
includeするhtml:
http://1811way.com/work008/sample05html.txt

私のやっているlocal開発環境
Windows8.0 
Apache2.4 
php5.6.2

以上、よろしくお願いします。

回答の条件
  • 1人1回まで
  • 登録:
  • 終了:2015/10/22 18:56:22
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:rouge_2008 No.1

回答回数595ベストアンサー獲得回数351

ポイント200pt

1.ulタグの右側の文字を表示させたいのですが。
 find( 'ul' )だと、ulの中のliを表示させてしまいます。

指定したHTMLタグ内にあるHTMLタグやテキストはすべて取得されます。
「ul」のように「li」が入れ子になっている場合、「ul」の内容として「li」の内容もすべて含まれます。

<div id="wrap">
    <div id="header">
    ヘッダー
    </div>
    <div id="content">
    コンテンツ
    </div>
    <div id="sidebar">
    サイドバー
    </div>
    <div id="footer">
    フッター
    </div>
</div>

※上記のように外側(※上の階層)のdiv要素(※id「wrap」のdiv)を取得した場合、idが「header」「content」「sidebar」「footer」のdiv要素もすべて含まれます。
※同じ階層にある要素は含まれませんので、idが「header」「content」「sidebar」「footer」のdiv要素の場合は、他の要素の内容は含まれません。(※任意で指定して取得した場合だけでなく、ループ処理時にも各々の要素の内容だけが含まれます。)

 find( 'ul' )->text だとnon-objectと言われる。
 *test26.phpの17,18,19行目(//はコメント)

※オブジェクトではないものに「->」を使っているので「non-object」のNOTICEメッセージが表示されています。(※「Notice: Trying to get property of non-object in /path/... on line **」は「/path/...の**行目で、オブジェクトではない物のプロパティを取得しようと試みました」という内容です。)
DOM、Element何れの場合も、「find()」でインデックスを指定しなかった場合はオブジェクトの配列を返しますので、「$a->find('ul')」の返り値は配列になります。
「->」(矢印演算子)はオブジェクトにアクセスする為の演算子ですので、配列にはアクセスできません。
オブジェクトへのアクセスについては、以下のページを参照してください。

・PHP: プロパティ - Manual
http://php.net/manual/ja/language.oop5.properties.php

※「Simple HTML DOM Parser」で使用できるプロパティとメソッドについては、マニュアルとAPI Referenceを参照してください。

・API Reference
http://simplehtmldom.sourceforge.net/manual_api.htm
※以下に「find()」について一部抜粋します。

DOM methods & properties
mixed find ( string $selector [, int $index] ) Find elements by the CSS selector. Returns the Nth element object if index is set, otherwise return an array of object.

Element methods & properties
mixed find ( string $selector [, int $index] ) Find children by the CSS selector. Returns the Nth element object if index is set, otherwise, return an array of object.

インデックスを指定した場合は任意の順番のHTML要素のオブジェクトを返しますが、それ以外の場合はオブジェクトの配列を返すとあります。

※「file_get_html()」および「str_get_html()」の結果は、DOM(※simple_html_dom)のオブジェクトが返りますので、この取得結果に対して使用できるプロパティとメソッドは「DOM methods & properties」の表を参照してください。
DOM、Element何れの場合も、「find()」の結果はElement(※simple_html_dom_node)が返りますので、この取得結果に対して使用できるプロパティとメソッドは「Element methods & properties」の表を参照してください。

※「find()」でインデックス指定しなかった場合はオブジェクトの配列になりますので、「foreach()」でループ処理する必要があります。
マニュアルで、ネストされた(入れ子になった)タグのアクセス例として、ちょうど「ul」「li」が例示されています。

・How to find HTML elements? > Nested selectors
http://simplehtmldom.sourceforge.net/manual.htm#frag_find_nested

// Find all <li> in <ul> 
foreach($html->find('ul') as $ul) 
{
    foreach($ul->find('li') as $li) 
    {
        // do something...
    }
}

// Find first <li> in first <ul> 
$e = $html->find('ul', 0)->find('li', 0);

指定した要素「$html->find('ul')」内のすべてのulおよびli要素にアクセスする場合は、前者のように「foreach()」を利用します。(※ループの中でさらにループさせます。)
任意の要素にアクセスする場合は、後者のようにインデックスを指定します。(※1番目は「0」です。)


W3CのHTMLの仕様に沿っていないHTMLでしたので、リストのコード例を以下のように修正します。(※処理の為のコードが複雑にならないためにも、仕様に沿ったHTMLで試してみてください。)

【HTML例】

<ul id="right">
  <li><h2>ul 1階層目のli その1 見出し用?</h2>
    <ul>
      <li><h3>ul 2階層目のli その1 見出し用?</h3>
        <ul>
          <li>ul 2階層目のli その2 項目1</li>
          <li><h4>ul 3階層目のli その1 見出し用?</h4>
            <ul>
              <li>ul 3階層目のli その2 項目1</li>
              <li>ul 3階層目のli その3 項目2</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

・ul 要素
https://developer.mozilla.org/ja/docs/Web/HTML/Element/ul
※「入れ子状に配置されたリスト」参照


【PHP例】(※任意に指定したidで取得します。)

foreach ($html->find('ul#right') as $ul) {
    echo "<h1>入れ子リスト elements.</h1>\n";
    $i = 1;
    echo "<h2>ブラウザ表示確認</h2>";
    echo "ulリストプレビュー表示" . $ul . "<br>\n";
    echo "以下、結果確認(li内テキスト)<br>\n";
    foreach ($ul->find('li') as $li) {
        if(preg_match('#^(.+?)(<ul>.+)?$#s', $li->innertext, $matches)) {
            $text = "<div style='border:1px dotted navy; padding: 6px;'>";
            echo $text . $i . " is " . $matches[1] . "</div>\n";
        }
        $i++;
    }
}

※入れ子になっているので、上の階層の「li」の内容として下層にある「ul」の「li」の内容も含まれる為、正規表現で検索して必要な部分だけ取得しています。
※「plaintext」プロパティの場合、HTMLタグが除外される為、検索の目印がなくなってしまいますから、「innertext」プロパティを使用します。

2.test26.phpの21,22,23行目(//はコメント)ulタグの中にliタグがあるので、
if (!empty( $a->value))が正しいように思いますが、
!だと何も表示されません。

存在しないプロパティ「value」を指定した為に「false」が返されたようです。(※リファレンスにも記載されていません。)
その為、 「$a->value」の結果は必ず「偽」になりますので、判定の内側の処理は行われません。(※指定したHTML要素が「input」等、「value」属性を持つHTMLタグの場合は、「value」に指定された値が返りますので、この場合は判定に利用できると思います。)
指定した要素の中身の有無判定には、適切な位置で「innertext」プロパティを使ってみてください。(※入れ子になっていなければ「plaintext」も使えます。)

※「text」は使用できるプロパティではありません。(※Element(simple_html_dom_node)のメソッド「text()」としては利用できるようですが、もしHTMLタグを除外した内容が必要な場合は「plaintext」プロパティを利用してみてください。

id:kohhi

>※上記のように外側(※上の階層)のdiv要素(※id「wrap」のdiv)を取得した場合、
>idが「header」「content」「sidebar」「footer」の
>div要素もすべて含まれます。

>指定した要素「$html->find('ul')」内のすべてのulおよびli要素にアクセスする場合は、
>前者のように「foreach()」を利用します。(※ループの中でさらにループさせます。)

かなり深い入れ子になっているul,liもループ処理で取り出せるんですね。
じっくりやってみます。
>「・How to find HTML elements? > Nested selectors」
の応用で、入れ子の深いものをやってみるつもりです。

「Notice: Trying to get property ・・」は、
いつも出てくるエラーメッセージで、
僕にとっては大きなヒントになり、勉強になりました。
「->」(矢印演算子)の実践的な意味がわかりかけてきたように思います。


「Simple HTML DOM Parser」で使用できるプロパティとメソッドについては、マニュアルとAPI Referenceを・・」
これが基本ですね。じっくり読みます。

>PHP例】(※任意に指定したidで取得します。)
>※入れ子になっているので、上の階層の「li」の内容として下層にある
>「ul」の「li」の内容も含まれる為、
>正規表現で検索して必要な部分だけ取得しています。
サンプル修正、プログラムまで書いていただいて、ありがとうございました。

2015/10/22 18:55:51
  • id:rouge_2008
    > 1.ulタグの右側の文字を表示させたいのですが。
    > find( 'ul' )だと、ulの中のliを表示させてしまいます。
    > find( 'ul' )->text だとnon-objectと言われる。
    > *test26.phpの17,18,19行目(//はコメント)

    指定したHTMLタグ内にあるHTMLタグやテキストは、「li」も含めてすべて取得される仕様です。
    「$a->find('ul')->plaintext」とした場合は、HTMLタグは除外されますが、テキストはすべて含まれます。
    ※「$a->find('ul')」は配列を返します。
    「->」(矢印演算子)はオブジェクトにアクセスする為の演算子ですので、配列にはアクセスできません。

    ・プロパティ
    http://php.net/manual/ja/language.oop5.properties.php

    ・API Reference
    http://simplehtmldom.sourceforge.net/manual_api.htm
    ------------------------------------------------------
    DOM methods & properties
    mixed find ( string $selector [, int $index] ) Find elements by the CSS selector. Returns the Nth element object if index is set, otherwise return an array of object.
    ------------------------------------------------------
    インデックスを指定した場合は任意の順番のHTML要素のオブジェクトを返しますが、それ以外の場合はオブジェクトの配列を返すとあります。

    ※利用できるのは「API Reference」にあるメソッドおよびプロパティのみだと思います。(「text」はありません。※[attribute]は「href」「src」「title」「alt」等、HTMLタグの属性です。)


    ※「ul」内に記述できるのは「<li>」だけですので、W3CのHTML仕様に沿っていません。
    リスト項目「<li>」内に「ul」を入れるか、別のHTMLタグで組みなおしてみてください。

    ・<ul> - 順序無しリスト
    http://www.tohoho-web.com/html/ul.htm

    以下は「ul」の場合の例です。(※任意の「ul」を取得する為にidを指定しました。)

    <!------------------------------------------------------->

    <ul id="right">
    <li><h2>ul 1階層目のli その1 見出し用?</h2>
    <ul>
    <li><h3>ul 2階層目のli その1 見出し用?</h3>
    <ul>
    <li>ul 2階層目のli その2 項目1</li>
    <li><h4>ul 3階層目のli その1 見出し用?</h4>
    <ul>
    <li>ul 3階層目のli その2 項目1</li>
    <li>ul 3階層目のli その3 項目2</li>
    </ul>
    </li>
    </ul>
    </li>
    </ul>
    </li>
    </ul>

    <!------------------------------------------------------->

    ・ul 要素
    https://developer.mozilla.org/ja/docs/Web/HTML/Element/ul
    ※「入れ子状に配置されたリスト」参照


    【PHP】(※任意に指定したidで取得します。)
    ※入れ子になっているので、正規表現で検索して必要な部分だけ取得します。

    //-------------------------------------------------------
    foreach ($html->find('ul#right') as $ul) {
    echo "<h1>入れ子リスト elements.</h1>\n";
    $i = 1;
    echo "<h2>ブラウザ表示確認</h2>" . $ul;
    foreach ($ul->find('li') as $li) {
    if(preg_match('#^(.+?)(<ul>.+)?$#s', $li->innertext, $matches)) {
    $text = "<div style='border:1px dotted navy; padding: 6px;'>";
    echo $text . $i . " is " . $matches[1] . "</div>\n";
    }
    $i++;
    }
    }
    //-------------------------------------------------------


    > 2.test26.phpの21,22,23行目(//はコメント)ulタグの中にliタグがあるので、
    > if (!empty( $a->value))が正しいように思いますが、
    > !だと何も表示されません。

    ネストされた(入れ子になった)タグのアクセス例として、ちょうど「ul」「li」が例示されています。

    http://simplehtmldom.sourceforge.net/manual.htm#frag_find_nested
    ---------------------------------------------------------
    // Find all <li> in <ul>
    foreach($html->find('ul') as $ul)
    {
    foreach($ul->find('li') as $li)
    {
    // do something...
    }
    }

    // Find first <li> in first <ul>
    $e = $html->find('ul', 0)->find('li', 0);
    ---------------------------------------------------------
    指定した要素「$html->find('ul')」内のすべてのulおよびli要素にアクセスする場合は、前者のように「foreach()」を利用します。(※ループの中でさらにループさせます。)
    任意の要素にアクセスする場合は、後者のようにインデックスを指定します。(※1番目は「0」です。)

    「value」はリファレンスに記載されていませんでしたので、どのようなデータが入るのか不明です(※ここでは返り値は「false」でした)ので、内包する要素の有無の判定には利用できないと思います。


    上記で抜粋した以外の箇所についても、一応すべて目を通してみてください。

    ・PHP Simple HTML DOM Parser Manual
    http://simplehtmldom.sourceforge.net/manual.htm
  • id:kohhi
    早速コメントありがとうございました。
    正確なプログラムとサンプル、ありがとうございました。

    >※「ul」内に記述できるのは「<li>」だけですので、
    >W3CのHTML仕様に沿っていません。
    >リスト項目「<li>」内に「ul」を入れるか、
    >別のHTMLタグで組みなおしてみてください。

    霧が晴れたようにスッキリわかりました。

    <h2>ブラウザ表示確認</h2> の
    プログラム、じっくり復習させていただきます。


    (empty( $a->value))
    そもそも、ulタグ直下に文字ないわけで(li以外ない)すね。
    これも、一緒に霧が晴れました。

    ありがとうございました。
    ベストアンサーにして、質問閉めたいので
    回答を入れてください。

    回答はお任せしますが、「コメントを参照してください。」
    とシンプルでもいいと思います。
  • id:rouge_2008
    > (empty( $a->value))
    > そもそも、ulタグ直下に文字ないわけで(li以外ない)すね。

    そういう問題だけではないんです。
    「PHP Simple HTML DOM Parser」は正しくないHTMLにも対応しているという事ですので、「ul」直下に直接記述された文字列も取得できていると思います。
    ※けれども、望んだ結果をスムーズに得る為にも、仕様に沿ったHTMLで作成する事をおすすめします。(普段からなるべく正しいHTMLで記述するようにした方が、他のツールを利用した時にも困らないと思います。)

    すみません。
    まとめるのにやや時間が掛かりますので、回答は明日以降になると思います。
  • id:kohhi
    >そういう問題だけではないんです。
    深いですね。深さもわからずすいません。
    >まとめるのにやや時間が掛かります
    お手数おかけしてすいません。
  • id:rouge_2008
    お待たせしてすみません。
    説明が上手な人なら早いのでしょうけど・・・(^^;
  • id:kohhi
    ありがとうございました。ホント、助かりました。説明お上手ですよ。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません