PHPのxpathについて

「PHPでXPath を使用する」を勉強しています。
https://www.ibm.com/developerworks/jp/xml/library/x-xpathphp/

上記サイトのproducts.xmlを対象に、
「リスト 2. SimpleXML を使用し、すべてのノードを配列として表示する」
はそのままできるのですが、

「リスト 3. SimpleXML を使用し、すべての製品名を配列として表示する」
<?php
$xml = simplexml_load_file("products.xml");
$products = $xml->xpath("/PRODUCTS/PRODUCT/NAME");
print_r($products);
?>
*$products = $xml->xpath("/PRODUCTS/PRODUCT/NAME");
の部分が違うだけです。

だと、配列に何もはいりません。
Array ( [0] => SimpleXMLElement Object ( )
*この状態が、[0]~[3]まで表示

何が悪いのかわかりません。
教えていただけると大変助かります。

よろしくお願いします。

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

ベストアンサー

id:rouge_2008 No.2

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

ポイント200pt

ありがとうございます。
コメントをまとめただけの回答で失礼します。

PHPのバージョン5.6.11、および5.5.27で修正されたようです。
最新版の5.6.14では正常に取得できる事を確認済みです。(※5.6.11および5.5系最新の5.5.30でも確認済みですが、5.5.27は未確認)

・PHP 5 ChangeLog
http://php.net/ChangeLog-5.php#5.6.11

Version 5.6.11
10 Jul 2015

  • SimpleXML:
    • Refactored the fix for bug #66084 (simplexml_load_string() mangles empty node name).

・Bug #66084 simplexml_load_string() mangles empty node name
https://bugs.php.net/bug.php?id=66084

・Fix #66084: whitespace depending iteration over SimpleXMLElements (php-src/1306)
https://github.com/php/php-src/pull/1306

英語が苦手なので全部は読んでいませんが、「var_dump」や「print_r」だけでなく「json_encode」にも影響があるという事です。


※libxmlの問題ではありませんでした。修正前の5.6.10でもバージョン2.9.2です。

id:kohhi

ありがとうございました。お手数おかけしました。また、よろしくお願いします。

2015/10/13 23:02:39

その他の回答1件)

id:tezcello No.1

回答回数460ベストアンサー獲得回数69

ポイント100pt

単純にIBMのページの内容が正しくない(あるいは今のバージョンとは応答が違う)のだろうと思います。
__ミスもあるようですしね
__[SKU='soft5678'] で Pro Reporting が得られるみたいな記述だけど
__「Pro Reporting」は SKUが soft32323 だし(というか soft5678 は存在しない)


> Array ( [0] => SimpleXMLElement Object ( )
良く考えてみれば、これで良いんじゃないでしょうか?

xpath() の戻り値 $products は単なる配列で $products[0] は SimpleXMLElement。
$products[0] は何らかのプロパティやノードを含んでいる訳ではないので $product[0] は SimpleXMLElement としか表示できない。

例えば、
<NAME><AAA>hoge</AAA>Widget Reporting</NAME>
のように書いてやれば
Array ( [0] => SimpleXMLElement Object ( [hoge] => fuga )
のようになります。

id:rouge_2008 No.2

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

ポイント200pt

ありがとうございます。
コメントをまとめただけの回答で失礼します。

PHPのバージョン5.6.11、および5.5.27で修正されたようです。
最新版の5.6.14では正常に取得できる事を確認済みです。(※5.6.11および5.5系最新の5.5.30でも確認済みですが、5.5.27は未確認)

・PHP 5 ChangeLog
http://php.net/ChangeLog-5.php#5.6.11

Version 5.6.11
10 Jul 2015

  • SimpleXML:
    • Refactored the fix for bug #66084 (simplexml_load_string() mangles empty node name).

・Bug #66084 simplexml_load_string() mangles empty node name
https://bugs.php.net/bug.php?id=66084

・Fix #66084: whitespace depending iteration over SimpleXMLElements (php-src/1306)
https://github.com/php/php-src/pull/1306

英語が苦手なので全部は読んでいませんが、「var_dump」や「print_r」だけでなく「json_encode」にも影響があるという事です。


※libxmlの問題ではありませんでした。修正前の5.6.10でもバージョン2.9.2です。

id:kohhi

ありがとうございました。お手数おかけしました。また、よろしくお願いします。

2015/10/13 23:02:39
  • id:rouge_2008
    「NAME」ノードが空だとそのような表示になります。
    「products.xml」の中身は同じなのでしょうか?(※「リスト 1. 製品群を表現する XML 文書の例 (products.xml)」をコピー)
  • id:kohhi
    早速お問い合わせをいただき、ありがとうございます。
    products.xmlの中身は

    <?xml version="1.0" encoding="UTF-8"?>
    <PRODUCTS>
    <PRODUCT category="software">
    <SKU>soft32323</SKU>
    <SUB_CATEGORY>Business Analysis</SUB_CATEGORY>
    <NAME>Widget Reporting</NAME>
    <PRICE>4500</PRICE>
    </PRODUCT>
    <PRODUCT category="software">
    <SKU>soft32323</SKU>
    <SUB_CATEGORY>Business Analysis</SUB_CATEGORY>
    <NAME>Pro Reporting</NAME>
    <PRICE>2300</PRICE>
    </PRODUCT>
    <PRODUCT category="storage">
    <SKU>soft32323</SKU>
    <SUB_CATEGORY>Tape Systems</SUB_CATEGORY>
    <NAME>Tapes Abound</NAME>
    <PRICE>2300</PRICE>
    </PRODUCT>
    <PRODUCT category="storage">
    <SKU>soft32323</SKU>
    <SUB_CATEGORY>Disk Systems</SUB_CATEGORY>
    <NAME>Widget100 Series</NAME>
    <PRICE>6500</PRICE>
    </PRODUCT>
    </PRODUCTS>
  • id:kohhi
    1つ上のノードで、プログラムの3行目
    $products = $xml->xpath("/PRODUCTS/PRODUCT");
    だと、配列にしっかり値が入っています。

    いつも、お手数おかけしてすいません。
  • id:rouge_2008
    OSやウェブサーバーの種類等、テスト環境を教えてください。
    それから、PHPやlibxmlのバージョンはいくつでしょう?(「phpinfo()」で確認してみてください。)


    ・指定方法を変えた場合はどうなりますか?

    $products = $xml->xpath("//NAME");


    ・「NAME」ノード以外で同じ階層にあるノードの取得結果も確認してみてください。

    $products = $xml->xpath("/PRODUCTS/PRODUCT/SUB_CATEGORY");

    あるいは

    $products = $xml->xpath("/PRODUCTS/PRODUCT/PRICE");
  • id:kohhi
    遅くまですいません。

    OSやウェブサーバーの種類等、テスト環境
    ->
    Windows8.0 
    Apache2.4 
    php5.6.2
    libxml:2.9.1

    $products = $xml->xpath("//NAME");
    ->配列に何も入ってないです。

    $products = $xml->xpath("/PRODUCTS/PRODUCT/SUB_CATEGORY");
    ->やはり、配列に何も入ってないです。

    $products = $xml->xpath("/PRODUCTS/PRODUCT/PRICE");
    ->やはり、配列に何も入ってないです。

    お手数おかけして、すいません。
  • id:rouge_2008
    PHP 5.6.2に含まれるlibxml 2.9.1が原因かもしれません。
    Windows版で問題の現象が発生するのを確認できました。(※Linux版では未確認ですので、Windows版だけの問題の可能性もあります。)
    最新版のPHP 5.6.14(libxml 2.9.2)では正常に取得できましたので、PHPを最新版にアップグレードしてみてください。
  • id:kohhi
    rouge_2008 さん、すいません。うまくバージョン変えられません。もう少し時間ください。
  • id:rouge_2008
    どのように上手くいかないのでしょう?
    何かエラーメッセージは出ていますか?

    Apache、PHP、MySQLをそれぞれ別々にインストールしたのでしょうか?
    それともXamppでしょうか?
  • id:kohhi
    早速コメントありがとうございます。

    別のパソコンに新規にapche2.4.16と
    http://php.net/ から VC11 x86 Thread Safe (2015-Oct-01 01:19:35)
    をダウンロードして、php5.6.14インストールしています。
    (それとMySQL)

    php.ini(c:\phpに配置)、apacheのconf(c:\Tools\htdocs\confに配置)
    でphp.iniとhttpd.confファイルは見直したつもりなのですが。
    現象:info.php(<?php phpinfo(); ?>)で、このまま文字列で<?php phpinfo(); ?>が表示されます。

    通常使っているパソコンではできているので、あれこれやっているところです。
    何から何まですいません。
  • id:rouge_2008
    通常使っているPCではPHPのバージョンアップが完了して、正常に動作しているという事でしょうか?
    そちらのPCと今回新たにインストールしているPCでは、各環境を別の方法でインストールしているのですか?

    Apacheのインストール先の確認です。

    > apacheのconf(c:\Tools\htdocs\confに配置)

    Apacheの設定ファイル「httpd.conf」を「c:\Tools\htdocs\conf」に入れてあるのでしょうか?
    Apache本体は何処にありますか?
    「htdocs」はドキュメントルート用に用意されたディレクトリです。
    通常は「htdocs」と同じ階層に「conf」ディレクトリがあります。
    Apacheの場合、各種ファイルの場所は変更せず、階層を維持したままインストールする方が良いと思います。(※特にWindowsでのテスト環境では必要ないと思います。)


    他、とりあえずPHPに関する設定について、次の2点について確認してみてください。

    1.PHPのApache用モジュールを読み込む設定を追加していますか?

    以下を「httpd.conf」に追加します。(各種ディレクティブの外側なら何処でも大丈夫です。)
    (※「C:/php/」がPHPのディレクトリの場合の例)

    LoadFile "C:/php/php5ts.dll"
    LoadModule php5_module C:/php/php5apache2_4.dll
    PHPIniDir C:/php/

    ・Apache モジュール mod_so #LoadModule ディレクティブ
    http://httpd.apache.org/docs/2.4/mod/mod_so.html#loadmodule
    ※コンテキストが「サーバ設定ファイル」と「バーチャルホスト」です。

    ・ディレクティブの解説に使われる用語 #コンテキスト
    http://httpd.apache.org/docs/2.4/mod/directive-dict.html#Context


    2.PHPファイルをPHPとして動作させる為の設定を追加していますか?

    「<Directory>」ディレクティブ内でも設定できますので、「httpd.conf」のドキュメントルートディレクトリの設定内に記述してみてください。

    # ドキュメントルートのディレクトリは設定例です。
    DocumentRoot "C:/example/www"
    <Directory "C:/example/www">
    #
    # Possible values for the Options directive are "None", "All",
    # or any combination of:
    # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
    # ...(~略~)
    Options Indexes FollowSymLinks

    # ...(~略~)
    <FilesMatch "\.php$">
    SetHandler application/x-httpd-php
    </FilesMatch>
    </Directory>

    ※「.phps」ファイルをPHPのソースファイルとして表示させる場合は以下も追加

    <FilesMatch "\.phps$">
    SetHandler application/x-httpd-php-source
    </FilesMatch>


    ・PHPに関するApacheの設定
    http://www.adminweb.jp/xampp/php/index3.html


    ※各種設定ファイルの設定変更後はApacheの再起動が必要です。
  • id:kohhi
    http://www.adminweb.jp/apache/php/index2.html
    に記載のある
    AddType application/x-httpd-php .php
    AddType application/x-httpd-php-source .phps
    の2行をconfに追加したらできました。

    お手数おかけしてすいません。
    できました。

    ->

    この質問の
    $products = $xml->xpath("/PRODUCTS/PRODUCT/NAME");
    も表示されました。
    ありがとうございました。

    rouge_2008 さんを
    ベストアンサーにさせていただきたいのですが、
    正式なご回答いただけませんか。
    よろしくお願いします。
  • id:tobeoscontinue
    既に解決済みですが配列に何も入っていないわけではなくvar_dumpやprint_rでは表示されないだけのようです。
    foreach ($products as $p) print_r($p->__toString());

    foreach ($products as $p) echo $p;
    でテキストが表示されました。
  • id:rouge_2008
    > 何も入っていないわけではなくvar_dumpやprint_rでは表示されない

    「SimpleXMLElement::__toString()」や「echo」以外でも文字列として認識させると大丈夫なようです。(「print」「printf()」等)
    型を変換したり、明示的にセットする事でも表示されました。

    ・型の相互変換
    http://php.net/manual/ja/language.types.type-juggling.php

    ・settype
    http://php.net/manual/ja/function.settype.php

    値を直接「var_dump()」で確認すると次のようになっています。
    ------------------------------------
    foreach($products as $p) {
    var_dump($p);
    }

    結果:
    object(SimpleXMLElement)#8 (0) {
    }
    object(SimpleXMLElement)#9 (0) {
    }
    object(SimpleXMLElement)#2 (0) {
    }
    object(SimpleXMLElement)#3 (0) {
    }
    ------------------------------------
    ※オブジェクトのカウントが0です。

    バージョン5.6.11と5.5.27で修正されたようです。
    英語が苦手なので全部は読んでいませんが、「var_dump」や「print_r」だけでなく「json_encode」にも影響があるようでした。

    ・PHP 5 ChangeLog
    http://php.net/ChangeLog-5.php#5.6.11

    ・Bug #66084 simplexml_load_string() mangles empty node name
    https://bugs.php.net/bug.php?id=66084

    ・Fix #66084: whitespace depending iteration over SimpleXMLElements (php-src/1306)
    https://github.com/php/php-src/pull/1306

    ※libxmlの問題ではありませんでした。修正前の5.6.10でもバージョン2.9.2です。
  • id:kohhi
    何から何まですいません。
  • id:rouge_2008
    kohhiさん、ありがとうございます。
    コメントをまとめて回答しました。
    無事にバージョンアップ完了したという事で良かったです。

    ※誤字を修正して再投稿しています。

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

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

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

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