人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

現在、PHP4環境にて、XML_unserialize関数を使用したXMLパーサ処理を作っています。
具体的には、沿線データ(API)を取得し、表示したい…といったものです。

以下に作りかけのソースを添付します。(コメント欄参照)
おおまかな流れとして、APIから抽出されたXMLデータをアンシリアライズした後、
変数$dataにセット、その後、各ノードに格納された値を取得し変数にセットしています。

「完全一致」の場合は動くのですが、例えば複数のクエリーが返される「横浜」など
で検索すると、検索結果には何も表示されなくなってしまいます。
参考→http://www.ekidata.jp/api/n.php?w=%e6%a8%aa%e6%b5%9c

理想の動きとしては、以下の様に複数行を表示したいのですが、どのようにプログラムを変更すれば宜しいでしょうか?
PHPの配列操作が初心者のため、参考サイトを見ながら苦戦しています…

宜しければ御回答をよろしくお願い致します。

●質問者: takupon2009
●カテゴリ:インターネット ウェブ制作
✍キーワード:API PHP XML クエリ コメント欄
○ 状態 :終了
└ 回答数 : 4/4件

▽最新の回答へ

1 ● QuestR2
●30ポイント

PHP5の関数をPHP4で使う - PHP_Compatを使ったほうがよいと思います。

http://techblog.ecstudio.jp/tech-tips/php_compat.html

◎質問者からの返答

コメントありがとうございます!

PEARのPHP_Compatは以前、検討したことがあります。

しかし、作りこみを全てPHP4でやってしまったので、出来ればPHP4の関数で

使用したいという気持ちがありまして…。 ギリギリまで頑張ってみます!


2 ● kn1967
●100ポイント ベストアンサー

配列の構造としては下記のようになります

■1件の場合

Keith Devens .com - XML to PHP translator

Array
(
 [ekidata attr] => Array
 (
 [version] => ekidata.jp station name list api 1.0
 )
 [ekidata] => Array
 (
 [coord] => Array
 (
 [word] => 陸奥横浜
 [total] => 1
 [error] => 0
 )
 [station] => Array
 (
 [line_cd] => 11203
 [line_name] => JR大湊線(はまなすベイライン大湊線)
 [station_cd] => 1120305
 [station_g_cd] => 1120305
 [station_name] => 陸奥横浜
 [pref_cd] => 2
 [lon] => 141.249757
 [lat] => 41.086544
 )
 )
)

■複数件の場合

Keith Devens .com - XML to PHP translator

(本当は[15]まであるのだけれども長くなるので省略してあります)

Array
(
 [ekidata attr] => Array
 (
 [version] => ekidata.jp station name list api 1.0
 )
 [ekidata] => Array
 (
 [coord] => Array
 (
 [word] => 横浜
 [total] => 16
 [error] => 0
 )
 [station] => Array
 (
 [0] => Array
 (
 [line_cd] => 11203
 [line_name] => JR大湊線(はまなすベイライン大湊線)
 [station_cd] => 1120305
 [station_g_cd] => 1120305
 [station_name] => 陸奥横浜
 [pref_cd] => 2
 [lon] => 141.249757
 [lat] => 41.086544
 )
 [1] => Array
 (
 [line_cd] => 11301
 [line_name] => JR東海道本線(東京?熱海)
 [station_cd] => 1130105
 [station_g_cd] => 1130105
 [station_name] => 横浜
 [pref_cd] => 14
 [lon] => 139.622704
 [lat] => 35.466195

 )
 )

 )

)

上記を比較すれば理解しやすいかと思いますが

同じ「陸奥横浜」でも

$data[ekidata][station][station_name]

$data[ekidata][station][0][station_name]

という具合に入っている階層が違いますので取り出し方も当然違いが出てきます。


対処方法として簡単な方法としては

件数が $data[coord][total] に入っていますから、この値を使って

1件の場合はそのまま表示処理に進み、

複数件の場合は[total]の値を使ってループ処理で駅名一覧を作成・表示して

駅名を選択させるなどといった対応にすれば良いでしょう。

(入っている数値は16だけど、配列の通し番号はゼロから始まりますので

-1して15で終わるように、処理の際には注意してくださいね)


なお、

※コメント欄を表示する設定にしておかないと

自分で書き込んだコメントも表示されません。

※php5にするようにという注意だけの書き込みはどうかと思うけど

出来るならばバージョンアップする事をお勧めはします。

◎質問者からの返答

コメントありがとうございます!

自分なりに、色々と弄っていたのですが、配列の場合だけ

Arrayと結果が返ってきてしまいます…。

因みに、

include('xml.php');

$keyword = $_GET['keyword']; (フォームからGETで値を取得しています)

// API情報の取得

$xml_data = file_get_contents("http://www.ekidata.jp/api/n.php?w=$keyword");

$data = XML_unserialize($xml_data);

// 必要な情報をピックアップして取得、変数に代入

$word = print_r($data["ekidata"]["coord"]["word"],TRUE); // 検索ワード

$total = print_r($data["ekidata"]["coord"]["total"],TRUE); // 検索結果

$station_nm = print_r($data["ekidata"]["station"]["station_name"],TRUE); // 駅名

$line_nm = print_r($data["ekidata"]["station"]["line_name"],TRUE); // 沿線名

// 文字コンバート

各変数はmb_convert_encodingで文字コードを変換する(省略)

// 配列に入っていた場合…

foreach( $data["ekidata"]["station"] as $key => $value )

{

echo $key. ":" .$value."
\n";

}

まだ続くのですが、最後の「配列に入っていた場合」の処理ですが、

0:Array

1:Array

2:Array...

と続き、配列は取得できているものの、値が表示できていません。

これは配列に値がしっかりと代入されていないということなのでしょうか…?


3 ● pahoo
●40ポイント

これは配列に値がしっかりと代入されていないということなのでしょうか…?

いいえ、違います。

配列の内容は echo で表示させることができないからです。


最後の foreach ループですが、$value そのものが連想配列になっています。関数 print_r を使って下記のようにすれば、取得したデータ構造がわかりやすくなると思います。

foreach( $data["ekidata"]["station"] as $key => $value ) {
 echo $key . ' : ';
 print_r($value);
 echo "\n";
}
◎質問者からの返答

ご回答ありがとうございます!

よくよく考えてみれば、確かに見当違いをしていたようです。。

ご指摘のように、print_rで配列を調べ、結果として以下のように書き直しました。

foreach( $data["ekidata"]["station"] as $key => $value )

{

$station_nm = print_r($data["ekidata"]["station"][$key]["station_name"],TRUE);

$line_nm = print_r($data["ekidata"]["station"][$key]["line_name"],TRUE);

echo $station_nm."駅(".$line_nm.")
";

echo "\n";

}

$keyには配列数が入ってくるので、その数をprint_r?の中にセットし、取得してみました。

すると、見事に一覧で取得することができました!

が・・・。

ここで不思議な現象が発生してしまいまして、

結果が以下のようになります。

「京急蒲田」での検索結果は2件です。

莠ャ諤・闥イ逕ー駅(莠ャ諤・譛ャ邱・

莠ャ諤・闥イ逕ー駅(莠ャ諤・遨コ貂ッ邱・

本来であれば、

「京急蒲田」での検索結果は2件です。

京急蒲田(京急本線)

京急蒲田(京急空港線)

のように表示してくれるハズなのですが、なぜか文字化けします。

文字化け対策として、mb_convert_encodingで適切な文字コードに変換しているのですが、

これまた不思議なことに、検索結果が複数返ってくる処理だけ、文字化けしてしまうのです。

完全一致での検索結果では、同じようにmb_convert_encodingで文字コードを変換して

成功しているので、このようなことはありえないと思うのですが…

念のため、echo mb_detect_encoding関数で文字列のエンコードを調べましたが、

SJISと出ます。 プログラム内ではmb_convert_encoding($total, "SJIS-win", "auto")

といった感じで、文字コードを変換しています。(この変換方法で完全一致の処理結果は成功しています)

if ($total == "1")

{

$station_nm = print_r($data["ekidata"]["station"]["station_name"],TRUE);// 駅名

$line_nm = print_r($data["ekidata"]["station"]["line_name"],TRUE);// 沿線名

$station_nm = mb_convert_encoding($station_nm, "SJIS-win", "auto");// 変換

$line_nm = mb_convert_encoding($line_nm, "SJIS-win", "auto");// 変換

}

else if ($total == "0")

{

echo "「".$word."」という駅は見つかりませんでした。
";

}

else

{

echo "「".$word."」での検索結果は".$total."件です。
";

$station_nm = "";

$station_nm = print_r($data["ekidata"]["station"]["station_name"],TRUE);// 駅名

$line_nm = print_r($data["ekidata"]["station"]["line_name"],TRUE);// 沿線名

$station_nm = mb_convert_encoding($station_nm, "UTF-8", "auto");// 変換

$line_nm = mb_convert_encoding($line_nm, "SJIS-win", "auto");// 変換

foreach( $data["ekidata"]["station"] as $key => $value )

{

$station_nm = print_r($data["ekidata"]["station"][$key]["station_name"],TRUE); ←なぜか文字化け

$line_nm = print_r($data["ekidata"]["station"][$key]["line_name"],TRUE); ←なぜか文字化け

echo $station_nm."駅(".$line_nm.")
";

echo "\n";

}

}

elseの処理で入ってくる変数は初期化をしていませんが、これが関係しているのかと思い、

変数を一度初期化した後に、再度値を入れなおして見ましたが変化がありません。

このPHPは文字コードSJISで保存しています。

サーバのPHP.iniのmb_stringは有効で、以下のような設定となっています。

[mbstring]

default_charset = "Shift_JIS"

mbstring.language = Japanese

mbstring.internal_encoding = SJIS

mbstring.http_input = pass

mbstring.http_output = pass

mbstring.encoding_translation = Off

mbstring.detect_order = SJIS,JIS,UTF-8,EUC-JP,ASCII

mbstring.substitute_character = none;

何か手がかりになるような情報を探してはいますが、文字化けだけが解消できず苦戦しています。

あと少しで完成しそうなのですが…(涙)


4 ● pahoo
●40ポイント

何か手がかりになるような情報を探してはいますが、文字化けだけが解消できず苦戦しています。

失礼ながら、多次元連想配列の扱いと、関数 print_r の使い方が間違っているようです。

foreach で回しながら文字コードを変換していくのがいいでしょう。下記にサンプル・スクリプト(一部)を掲げます。

foreach ($data['ekidata']['station'] as $station) {
 $station_nm = mb_convert_encoding($station['station_name'], 'SJIS-win', 'UTF-8');
 $line_nm = mb_convert_encoding($station['line_name'], 'SJIS-win', 'UTF-8');
 echo $station_nm . '駅(' . $line_nm . ')';
 echo "\n";
}

なお、mb_convert_encoding で 'auto' を使うと変換ミスを起こすケースがあるので、入力は 'UTF-8' で決め打ちにしました。

◎質問者からの返答

御回答ありがとうございます!

kn1967氏の模範解答と共に、foreachの中での変換処理について、対策を施してみました。

無事に文字化けは解消されました。 もう少し書籍やネットなどで情報を探して勉強してみようと思います!

お忙しい中、御回答ありがとうございました!

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ