[perlメモ]さくらインターネットのレンタルサーバーでeucのXMLファイルをXMLinで解析しようとするとParser.pmがエラーを吐く件について

過去にも下の記事で扱ったのですが、通常文字コードがEUC形式のXMLファイルをXML::SimpleのXMLinを使って解析するとエラーになります。

◆関連記事:perlメモ:Perl XMLでencoding=’Shift_JIS’や’euc-jp’を使う – KUMA TYPE
http://blog.kumacchi.com/2008/02/perlperl_xmlencodingshift_jise.html

これは、XML::Parserにeuc-jpやShift_JISに対する文字コードのマッピングがされていない事が原因なのですが、それを解決するスクリプトを下記のサイトで公開されています。通常はこれを利用することによりこの問題を回避するのだと思いますが、今までさくらインターネットのレンタルサーバーでは特にこの対応を行わなくてもエラーも発生せずに利用できていたので、さくらインターネットさんの中の人が対応してくださっているのだろうと思ってすごいなーと思っていたのですが、少し前のOSのバージョンアップメンテ以降このエラーが発生するようになっています。

Perlの小技

関連:Perl XMLでencoding=’Shift_JIS’や’euc-jp’を使う
http://homepage3.nifty.com/hippo2000/perltips/xml/xmlenc.htm

EUC文字コードのRSSをperlでXML::Simpleを使って解析しようとすると下記のエラーが発生します。XML::Parser.pmの中でエラーが発生しています。現在ほかに二つほどさくらのレンタルサーバーを借りていますが、それらも同様のエラーが発生します。もう対応しないのか、忘れているのかわかりませんが、ちょっと困りました。問い合わせてもよかったのですが、めんどくさいのでプログラムで何とかできないかと思って、そのうち対応してくれるかもしれないのでとりあえず回避する方法を考えてみました。

Couldn’t open encmap euc-jp.enc: No such file or directory at /usr/local/lib/perl5/site_perl/5.8.9/mach/XML/Parser.pm line 187

 

通常は、下のソースのような感じでXMLファイルをgetしてXMLinに渡すと思います。(実際にはCache =>’storable’などやってキャッシュ処理したりともうちょっと複雑ですが)

 

use strict;
use warnings;
use LWP::Simple;
use XML::Simple;
use Encode qw/from_to/;
use Encode::Guess qw/ascii utf8 euc-jp shiftjis 7bit-jis/;

my $rss_response = get($rss);

my $xmlsimple = XML::Simple->new();
my $rss_xml = $xmlsimple->XMLin($rss_response, ForceArray=>[‘item’]);

 

euc形式だとマッピングされてないのでエラーになるのだから要は、XMLinに渡す前にUTF-8に変換しっちゃえばいいじゃない?という事になると思います。

それで、下のように、文字コードをUTF-8に変換する処理とXMLファイルのヘッダ部分にある

<?xml version="1.0" encoding="euc-jp"?>を

<?xml version="1.0" encoding="UTF-8"?>に

書き換える処理を追加してからXMLinに渡すようにした場合下のような感じのソースになります。

これで、とりあえず動くようになりました。

 

use LWP::Simple;
use XML::Simple;
use Encode qw/from_to/;
use Encode::Guess qw/ascii utf8 euc-jp shiftjis 7bit-jis/;

my $rss_response = get($rss);

my $dec = Encode::Guess->guess($rss_response);
if(ref($dec)){
    $rss_response = Encode::decode($dec->name, $rss_response);
}
$rss_response =~ s/euc-jp/UTF-8/;

my $xmlsimple = XML::Simple->new();
my $rss_xml = $xmlsimple->XMLin($rss_response, ForceArray=>[‘item’]);

 

※あくまでも上のソースたちは、ヒントとして本来のソースから抜粋したものでかなり端折られていますのでそこのところご了承ください。

解決の糸口になれば幸いです。

タグ : ,