PHPで、RSS等のXMLを取得し、パースしています。


その際、
・不正な文字
・不正な文字コード
をうまく除去できずに、エラーが沢山出ます。
preg_matchを使うので、urlencode で変な記号が入らないようにしていますが、
別のとこでエラーがでたりします。

unterminated entity reference ...

Compilation failed: nothing to repeat at offset

Entity: line 499: parser error : Input is not proper UTF-8, indicate encoding ! Bytes: 0xE3 0x2E 0x2E 0x2E in

というようなのが多いです。

php5のsimplexml_load_string等で今はパースしています。
文字コードを整え、不正文字を見つければ一つ一つ追加で置換コードを書き、
preg_matchのために「+」等をいちいち置換し・・・。
エラーが筍のように次々と出て終わりが見えません。

WEBから受け取ったデータを加工して使う、というスキルが足りない気がします。


何かスマートに、XMLを取得して使う方法はないのでしょうか?

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2007/06/07 08:33:55
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:tezcello No.2

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

ポイント100pt

今まで問題になっている文字を漠然と不正文字と捉えてきましたが、よく見てみたら解決したような気がします。

hotpepper の文字は、コードが x0B つまり制御文字でした。

なので、UTF-8 に変換してもすり抜けるのは当り前です。

そこで、制御文字は全部除去してみました。

UTF-8 には漢字部分にASCIIの制御文字が来る事は無いので漢字に影響は与えません。

 // test1.xml は問題の文字が入っているファイルです。この行は正規のRSSを代入する文と置き換えて下さい
$rss = file_get_contents('test1.xml');

$search = array("\0", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06"
	, "\x07", "\x08", "\x0b", "\x0c", "\x0e", "\x0f");
$rss = str_replace($search, '', $rss);

この後、UTF-8 -> UTF-8 のエンコード変換をすれば不正な文字も除去されて望むような結果になると思います。

id:onigirin

どうもありがとうございます。

試してみたところ、ホットペッパーの♂はうまく除去されました!

制御文字というやつなのですね。

自分のレベルを超えていて完全にわからなかったので助かりました・・・。

前回の質問の内容は完全に解消されて助かりました。

本当にどうもありがとうございます!


そのほかのエラーについては、これが解決して落ち着いてエラーを辿ってみると、

ただのコーディングミスな気がしてきました。

関数で「&」が含まれる変数をreturnしたところでエラーが出ていただけでした。

preg_matchで使うために、

urlencodeで自動変換されない「+」を「%2B」にしたり、

変数からreturnするために「&」を「%26」に変換したり、

泥臭い方法には変わりないままです・・・。

2007/06/03 08:32:06

その他の回答1件)

id:t_shiono No.1

回答回数256ベストアンサー獲得回数22

ポイント28pt

問題を確認させてください。

処理として、

・何らかの方法でデータをWEBから取得する

・取得したXMLをsimplexml_load_stringを利用してパースする

・パースしたXMLの一部分に正規表現によるマッチングを行いたいため、preg_matchを利用する

このうちのパースでエラーが出ているということでよいでしょうか?

どのようなデータを取得しているか分からないのですが、この場合であれば、WEBからの取得の方法が問題なのだと思うのですが、どのように取得していますか?

ちなみに、私はWEBからのデータの取得は、PEARのHTTP_Requestを利用して取得することが多いです。

それとも、正規表現の処理を踏まえてパース前に何か処理をしているために、パースが失敗しているのでしょうか?もし、そうであれば、パース後に必要があれば正規表現のための置換を行ってみてはどうでしょうか?

id:onigirin

どうもありがとうございます。

ちょっと混乱してました・・・。

http://b.hatena.ne.jp/keyword/web%E3%82%B5%E3%83%BC%E3%83%93%E3%...

のRSSを「simplexml_load_file」でパースし、データを取得。

ですが、 parser error : PCDATA invalid Char エラーが発生。

ホットペッパーの部分に、UTF-8エディタで見ると♂の半角のような文字が入っていてエラーになる。

そのため「simplexml_load_file」はやめ、「file_get_contents」でRSS取得。

「preg_replace」で上記不正文字を個別に指定して除去。

RSSによっては「Input is not proper UTF-8, indicate encoding」が出るため、

取得したデータはUTF-8に再変換してから除去することに。解決。


その後「simplexml_load_string」で変数に入れる。

そして「preg_match」でRSSのタグ情報を見て、変数に入れておいた同じ名前のタグかチェック。

そのときにRSS(上記とは別のキーワード)によっては

上記質問にあるようなエラーが出るので、

「urlencode」実施と「+」を空白に置換。解決。

ところが

http://b.hatena.ne.jp/keyword/%E6%A5%AD%E7%95%8C?mode=rss&so...

このRSSの場合、「unterminated entity reference work」や

「Compilation failed: nothing to repeat at offset」と出る。


ただRSSを取得してパースして、と簡単に考えていたのに、

とんでもなく難航してくる。


ここで、自分のやってることは

方向性が間違えている気がして壁にぶちあたってしまいました・・・。

2007/06/02 14:50:33
id:tezcello No.2

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

ポイント100pt

今まで問題になっている文字を漠然と不正文字と捉えてきましたが、よく見てみたら解決したような気がします。

hotpepper の文字は、コードが x0B つまり制御文字でした。

なので、UTF-8 に変換してもすり抜けるのは当り前です。

そこで、制御文字は全部除去してみました。

UTF-8 には漢字部分にASCIIの制御文字が来る事は無いので漢字に影響は与えません。

 // test1.xml は問題の文字が入っているファイルです。この行は正規のRSSを代入する文と置き換えて下さい
$rss = file_get_contents('test1.xml');

$search = array("\0", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06"
	, "\x07", "\x08", "\x0b", "\x0c", "\x0e", "\x0f");
$rss = str_replace($search, '', $rss);

この後、UTF-8 -> UTF-8 のエンコード変換をすれば不正な文字も除去されて望むような結果になると思います。

id:onigirin

どうもありがとうございます。

試してみたところ、ホットペッパーの♂はうまく除去されました!

制御文字というやつなのですね。

自分のレベルを超えていて完全にわからなかったので助かりました・・・。

前回の質問の内容は完全に解消されて助かりました。

本当にどうもありがとうございます!


そのほかのエラーについては、これが解決して落ち着いてエラーを辿ってみると、

ただのコーディングミスな気がしてきました。

関数で「&」が含まれる変数をreturnしたところでエラーが出ていただけでした。

preg_matchで使うために、

urlencodeで自動変換されない「+」を「%2B」にしたり、

変数からreturnするために「&」を「%26」に変換したり、

泥臭い方法には変わりないままです・・・。

2007/06/03 08:32:06
  • id:tezcello
    制御文字は本来表示しない(出来ない)文字なので、いつも雄記号の用に表示されるとは限りません。
    今回のx0Bは、バーチカルタブというものです。
    古くからコンピュータをいじっている人にはよく知られたものです。(ASCIIコードで調べるとその他も分かります)

    それで、これもRSSに含まれるべき文字ではないので、送り手側のミスの様に思われます。
    いや、どこでミスが起きているかは特定出来ませんね。大元となるHTMLページに含まれているとしたら、そんな記述をしたページ作者(あるいは、HTMLエディタの類い)のせいです。

    まぁ、「いけてない」ページやプログラムによる規格外れのデータ存在するのはいつもの事ですし、これらは受け取る時に矯正してやるしか方法が無いです。
    せめて自分の関係するもの位は標準を守る様にしたいです。

    URL辺りでご苦労されている様ですが、urlencode() 以外にも
    rawurlencode()
    htmlentities()
    htmlspecialchars()
    などありますので、使えるものがありませんか?
    http://www.php.net/manual/ja/ref.url.php
    http://www.php.net/manual/ja/ref.strings.php

    具体的に分かっていないので的が外れているかも知れませんが。
    (RSS辺りはやった事がないので、回答を書きながら勉強させてもらってます...)

  • id:onigirin
    どうもありがとうございます。
    制御文字は初めて知りました。
    安易に触ったXMLがこんな深いとこまでいくとは・・・。
    おかげさまで解決できて感謝しています。

    rawurlencode使ってみたところ、「+」の方も解決できました!
    ありがとうございます。

    変数に「&」の含まれた文字列を代入するときのエラーも、
    代入せずにそのまま表示させることで解決できました。

    レベル不足を実感してしまいましたが、
    おかげさまで頭が整理できました。
    本当にどうもありがとうございます。

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

トラックバック

  • RSSをパースするときの制御文字への対処 DOMを使ってRSSをパースしているとたまに以下のエラーがおきることがあります。(Livedoorブログ、FC2、Amebaブログとかが多い) An invalid XML character (Uni
  • htmlspecialcharsを使う 度々話題にしているアンパサンドなどの特殊文字。これを、HTMLエンティティ(実体参照)に変換するhtmlspecialchars関数を使ってみました。 XMLには、既に何度か(1/2)書い
「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

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

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