#freeze #setlinebreak(on) * SJIS、EUC-JP、JISなどの日本語をSimpleXMLで使う方法 [#i74ad925] #htmlinsert(googleAdsense.html) **概要 [#t316cdb3] XMLと言えばUnicode(UTF-8)な訳だが、 データによってはそうでないものも良くある。 特に、日本語ってやつは面倒くさいことが多い。 日本語の文字コードで代表的なものは、 Shift-JIS, EUC-JP, UTF-8, ISO-2202-JP 一つの言語でこれだけコードがあるのは日本語・中国語・韓国語ぐらいだろう。 simple_xml関数を使用すると、 UTF-8以外の文字コードを使用した場合、 パーサエラーが出ることがある。 結構きまぐれなのか、 環境によって出たりでなかったりしているような印象だ。 **multibyte関数との関係 [#r30cba2c] マルチバイトと言えばマルチバイト関数mb_convert_encodingが思いつくが、 メインでは使用しない。 Do you PHP? http://www.doyouphp.jp/php5/php5_simplexml.shtml では、 マルチバイト文字を扱う場合、internal_encodingに変換して出力する と書いてあるが、 これは正しくないと思われる。 実際はSimpleXML、もっと言うならLibxml2とmb_convert_encodingは、 なんの横つながりもない。 **実際 [#u22a5a53] では実際どうなのかというと、 Hawk's W3 Laboratory : XMLパーサ関数で日本語を扱う http://www.hawk.34sp.com/stdpls/php/xml_parse.html での記述。 内部エンコーディングはUTF-8 デフォルトでサポートしているエンコーディングは、 UTF-8, UTF-16LE/BE, iso-8859-1, ASCII, HTML(エンティティ参照) iconv が利用可能な環境なら iconvがサポートしているエンコーディングが全て使える つまり、iconvが影響しているのだ。 iconv(i18n converter)とは、 文字コードの変換をする関数。 iconvはlibiconvを使用した関数。 マルチバイト関数はPHP独自実装。 PHP 3.0.x国際化対応版、PHP4.2.2国際化版をPHPに取り込んだもの。 やっていることはどちらも同じで、 文字コードの変換を行っている。 XMLのヘッダー部分に <?xml version="1.0" encoding="EUC-JP" ?> と記述してあるわけだが、 このencode属性を読みとって、 SimpleXMLは変換を行っている。 デフォルトでは ISO-8859-1 UTF-8 US-ASCII の3つにしか対応していないので、 どんなに頑張っても文字化けする。 UTF-8に変換すればいいと思う人もいるかもしれないが、 その場合UTF-8に変換後、ヘッダー部分を <?xml version="1.0" encoding="UTF-8" ?> と書き換えなければならないので、 少し面倒だ。 そこで、iconvライブラリを使用すると、 ほぼすべての言語に対応できるというわけ。 **対処法 [#x4bac058] 日本語を使用するときは、 特別ソースコードを変更することはない。 phpinfoに iconv があればよい。 無い場合はのconfigureオプションに --with-iconv を追加しておく。 fladdict.net blog rssに非UTF8の不正な文字列がある場合の対処法 http://fladdict.net/blog/2006/06/rssutf8.html で、 PHP5のSimpleXMLが、rss内に不正な文字列があるとパースエラーを起こしてしまうのだけど、 ついに対処法を編み出した。 というか朝思いつきでやったら動いたwwwww $xmlStr = mb_convert_encoding($xmlStr, "SJIS", "UTF-8"); //一度sjisにする $xmlStr = mb_convert_encoding($xmlStr, "UTF-8", "SJIS"); //またutf8に戻す mb_convert_encodingスゴス。 とあるが、 これはもう一つ進んだ話。 条件は例えばこう ・XMLヘッダーに <?xml version="1.0" encoding="UTF-8" ?> と記述してある ・属性、値の中に別の文字コード(EUC-JP, SJISなど)が入っている と言った具合。 つまり一度すべての文字コードを統一してから、 SimpleXMLにパースさせると安全に文字変換が行える。 **サンプル [#dbc07c4c] UTF-8,EUC-JP,SJISのXMLファイルを読み込むことを想定して、 ソースはこんな感じだろうか。 // get xml if( ! $xmlStr = file_get_contents( "http://hoge.com/hoge.xml" ) ) throw new Exception("Not Open Url"); // parse xml $encode = mb_detect_encoding( strip_tags( $xmlStr ) ); $xmlStr = mb_convert_encoding( $xmlStr, $encode, "SJIS-win,EUCJP-win,UTF-8,JIS,ASCII" ); $xmlObjs = @simplexml_load_string( $xmlStr, "SimpleXMLIterator" ); print_r( $xmlObjs ); 1行目を読みとって、 encodingを取得する方がより安全かもしれない。 -カピバラ -- [[みる]] &new{2006-11-21 13:26:48 (火)}; #comment