XML::Simpleで取得したデータが引き起こす文字化けの対処方法

XML::Simpleで取得したデータが引き起こす文字化けの対処方法

Posted at June 18,2010 1:55 AM
Tag:[Perl]

XML::Simpleを使ったPerlスクリプトの文字化けではまってしまったので、その備忘録です。

1.発生事象

Perlスクリプトで次のXMLファイルを読み込みます。ファイルの文字コードはUTF-8です。

<?xml version="1.0" encoding="utf-8"?>
<list>
<name>ほげ</name>
</list>

Perlスクリプト(CGI)のサンプルは次の通りです。ファイルの文字コードはUTF-8です。

#!/usr/bin/perl
 
use strict;
 
use CGI;
use XML::Simple;
 
my $q = new CGI;
print $q->header(-charset=>'utf-8');
print $q->start_html;
 
my $xml = XMLin('foo.xml');
my $name = $xml->{name};
 
print <<EOF;
<form method="post" action="hoge.cgi">
名前:<input type="text" id="hoge" name="hoge" value="$name" />
<input type="submit" name="submit" value="送信" />
</form>
EOF
 
print $q->end_html;

このCGIをブラウザで表示すると、次のように、スクリプトに記述した全角文字の文字化けが発生します。

文字化けが発生

XMLファイルから取得する文字が、次のように全角文字でなければ文字化けは発生しません。

<?xml version="1.0" encoding="utf-8"?>
<list>
<name>hoge</name>
</list>

文字化けが発生しない

2.原因

XMLinで日本語を含む文字列を取得する場合、XML宣言のencoding属性に指定した文字コードの内部文字列に変換されます。よって外部に出力する場合、バイト文字列に変換(エンコード)する必要があるようです。

Data::Dumperで$nameを出力すると、「ほげ」は次のようになっていました。

$VAR1 = "\x{307b}\x{3052}";

試しに、次のようなサンプルであれば、

my $name = 'ほげ';

Data::Dumperで$nameを出力すると、

$VAR1 = 'ほげ';

となりました。

推測ですが、文字化けが発生したのは、内部文字列とバイト文字列が混在していたため、Perl自体がバイト文字列である「名前」「送信」をさらにエンコードを行い、文字化けが発生したものと思われます(解釈が間違っていたらご指摘ください)。

3.対処

スクリプトの$nameをUTF-8にエンコードすることで解決しました。

#!/usr/bin/perl
 
use strict;
 
use CGI;
use XML::Simple;
use Encode;
 
my $q = new CGI;
print $q->header(-charset=>'utf-8');
print $q->start_html;
 
my $xml = XMLin('foo.xml');
my $name = encode('UTF-8', $xml->{name});
 
print <<EOF;
<form method="post" action="hoge.cgi">
名前:<input type="text" id="hoge" name="hoge" value="$name" />
<input type="submit" name="submit" value="送信" />
</form>
EOF
 
print $q->end_html;

文字化けが発生しない

4.その他

出力時だけでなく、スクリプトに記述した全角文字と比較をする際も、予めエンコードしておく必要があります。

my $name = encode('UTF-8', $xml->{name});
if ($name eq 'ほげ') { ... }

以上です。色々調べてこれが最適解と思ったのですが、より適切な解決方法がありましたらコメントください。

2010.6.18 追記
下記の記事で、utf8プラグマの情報頂きました。ありがとうございました。

日曜プログラマのそゞろ事 - XML::Simpleで文字化けしない方法

5.参考サイト

参考サイトは下記です。ありがとうございました。

サンプルコードによるPerl入門 - XML::Simple - シンプルなXMLパーサ / Perlモジュール徹底解説
関連記事
zenback
人気エントリー
トラックバックURL


トラックバック

XML::Simpleで文字化けしない方法 from 日曜プログラマのそゞろ事
普段、MovableTypeのプラグインでお世話になっている「小粋空間」さんが、... [続きを読む]

Tracked on June 18, 2010 11:05 PM
コメント

utf8 フラグあたりはなかなか理解しにくいところですが、このあたりが参考になるかもしれません。
http://wiki.bayashi.net/perl/unicode
http://blog.livedoor.jp/dankogai/archives/51031595.html
http://d.hatena.ne.jp/tokuhirom/20080408/1207619640
http://blog.livedoor.jp/dankogai/archives/51290188.html

それでも足りない場合は 'perl utf8 flag' でぐぐると幸せになれるかも。

問題ないように追記するとこうなるのかなぁ。
http://codepad.org/g3Rkgelf

[1] Posted by punitan logo : June 18, 2010 10:36 PM
コメントする
greeting

*必須

*必須(非表示)


ご質問のコメントの回答については、内容あるいは多忙の場合、1週間以上かかる場合があります。また、すべてのご質問にはお答えできない可能性があります。予めご了承ください。

太字イタリックアンダーラインハイパーリンク引用
[サインインしない場合はここにCAPTCHAを表示します]

コメント投稿後にScript Errorや500エラーが表示された場合は、すぐに再送信せず、ブラウザの「戻る」ボタンで一旦エントリーのページに戻り(プレビュー画面で投稿した場合は、投稿内容をマウスコピーしてからエントリーのページに戻り)、ブラウザをリロードして投稿コメントが反映されていることを確認してください。

コメント欄に(X)HTMLタグやMTタグを記述される場合、「<」は「&lt;」、「>」は「&gt;」と入力してください。例えば「<$MTBlogURL$>」は「&lt;$MTBlogURL$&gt;」となります(全て半角文字)