PHPのxml_parse関数について教えてください。



xml_set_character_data_handler($xml_parser, "characterData");
ここで指定したcharacterData($parser, $data)の$dataにはちゃんと情報が入っているのに、これをglobal変数につっこんだのち、
xml_set_element_handler($xml_parser, "startElement", "diaryElement");
のfunction diaryElement($parser, $name)に移動したとき突っ込んだglobalの値を参照したら桁落ちしているのはどういうわけでしょうか?


ちなみに、自分の思ったとおりに動かないサンプルとソースはこちら。
http://kuippa.s188.xrea.com/h/ ここにソースもおいています。
これでつかってる getxml.php というファイルです。
xml_parseの使い方がよくわかっていないので、こんな風にやるんだよ~というサンプルなどがあればお教えいただければこれ幸い。

回答の条件
  • URL必須
  • 1人5回まで
  • 登録:2006/03/25 18:27:52
  • 終了:2006/03/26 16:28:54

ベストアンサー

id:bonlife No.1

回答回数421ベストアンサー獲得回数752006/03/26 10:34:00

ポイント35pt

調べてみたところ、xml_set_character_data_handlerに似たような現象(要素が途中で分割されてしまって最後の部分しか取得できない)がいくつか載っていました。

それを参考にして回答いたします。

ソースを見させていただきましたが、$retXmlの初期化の位置を修正すれば良いと思います。

getxml.phpの

function characterData($parser, $data){
	global $retXml;
	$retXml = "";
	$retXml = $data;
//	$retXml = mb_convert_encoding($data,"utf-8","utf-8");
	// ここにはちゃんとデータがはいっているのだけど…
}

の部分を

function characterData($parser, $data){
	global $retXml;
//	$retXml = "";
	$retXml .= $data;
//	$retXml = mb_convert_encoding($data,"utf-8","utf-8");
	// ここにはちゃんとデータがはいっているのだけど…
}

のように変更し、characterData内では$retXmlの初期化を行わず、次々と$dataの内容をappendするようにします。

これで複数に分割されてしまった要素の全てを$retXmlに入れることができます。

このままですと、$retXmlが初期化される場所がなくなってしまいます。

そこで、xml_set_element_handlerのend_element_handlerとして呼ばれる各種関数の最後に$retXmlを初期化する内容を追記します。

getxml.phpを確認したところ、xml_set_element_handlerのend_element_handler($xmlElement)は、fGetXmlの2つ目の引数で取得するものでした。

sns.phpにてfGetXmlの2つ目の引数にはdiaryElementとbmarkElementが指定されています。

そこで、getxml.php内のdiaryElementとbmarkElementの最後に

	unset($GLOBALS['retXml']);

という行を追記し、ここで$retXmlを初期化します。

初期化の方法は

	$retXML = "" ;

でも良いはずです。

(恥ずかしながら違いがよく分かってません…。)

これで上手く動くようになると思うのですが、いかがでしょうか。

一度確認してみてください。

id:kuippa

おー、できました!

printで吐かせていたので、気がつきませんでしたがcharacterDataって一回で完結してなかったんですね。

ありがとうございました。

2006/03/26 16:21:50

その他の回答(1件)

id:bonlife No.1

回答回数421ベストアンサー獲得回数752006/03/26 10:34:00ここでベストアンサー

ポイント35pt

調べてみたところ、xml_set_character_data_handlerに似たような現象(要素が途中で分割されてしまって最後の部分しか取得できない)がいくつか載っていました。

それを参考にして回答いたします。

ソースを見させていただきましたが、$retXmlの初期化の位置を修正すれば良いと思います。

getxml.phpの

function characterData($parser, $data){
	global $retXml;
	$retXml = "";
	$retXml = $data;
//	$retXml = mb_convert_encoding($data,"utf-8","utf-8");
	// ここにはちゃんとデータがはいっているのだけど…
}

の部分を

function characterData($parser, $data){
	global $retXml;
//	$retXml = "";
	$retXml .= $data;
//	$retXml = mb_convert_encoding($data,"utf-8","utf-8");
	// ここにはちゃんとデータがはいっているのだけど…
}

のように変更し、characterData内では$retXmlの初期化を行わず、次々と$dataの内容をappendするようにします。

これで複数に分割されてしまった要素の全てを$retXmlに入れることができます。

このままですと、$retXmlが初期化される場所がなくなってしまいます。

そこで、xml_set_element_handlerのend_element_handlerとして呼ばれる各種関数の最後に$retXmlを初期化する内容を追記します。

getxml.phpを確認したところ、xml_set_element_handlerのend_element_handler($xmlElement)は、fGetXmlの2つ目の引数で取得するものでした。

sns.phpにてfGetXmlの2つ目の引数にはdiaryElementとbmarkElementが指定されています。

そこで、getxml.php内のdiaryElementとbmarkElementの最後に

	unset($GLOBALS['retXml']);

という行を追記し、ここで$retXmlを初期化します。

初期化の方法は

	$retXML = "" ;

でも良いはずです。

(恥ずかしながら違いがよく分かってません…。)

これで上手く動くようになると思うのですが、いかがでしょうか。

一度確認してみてください。

id:kuippa

おー、できました!

printで吐かせていたので、気がつきませんでしたがcharacterDataって一回で完結してなかったんですね。

ありがとうございました。

2006/03/26 16:21:50
id:j0hn No.2

j0hn回答回数12ベストアンサー獲得回数02006/03/26 09:43:37

ポイント35pt

例えば、以下のようなXMLの場合

<description>文字列文字列……文字列</description>

characterData関数が呼ばれたときに「文字列……」のすべてが一度に渡されるように思えるのですが、実際にはそうではなく、何度かにわけて渡されるようです。

startElementで

global $retXml;
$retXml = "";

として、characterData内で、 $retXml = $dataとしているところを

$retXml = $retXml . $data (もしくは $retXml .= $data)

として、連結して伸ばしていくというのはどうでしょうか。

PHPのマニュアルのコメント欄にはxml_set_character_data_handlerでセットされたhandlerがうけとるdataの最大長が1024バイトなので、それ以上のデータが渡されるときには連結して受け取れ、とあります。(今、うちのPHPで試してみた感じだと、500バイトちょっとで千切れるようです) このことをきちんとマニュアル本体の説明に書いておくべきではないか、というコメントもあります。

freadで最大4096バイトしか読まずに処理しているわけですから、handlerのほうも途中で切れてもいいように書いておかないとまずい、ということでしょうか。

id:kuippa

ありがとうございます。一度のコールで完結しているものだと思っていました。

characterData内でprintさせてちゃんとデータが入ってるのになとおもったのですが、実際には何度か走ってたのですね。ありがとうございました。

解決しました。

2006/03/26 16:26:51

コメントはまだありません

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

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

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

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません