2008-10-11
Google Calendar Data API で祝日を取得する
祝日というのは人間が決めたものなので非常に扱いにくいものです。春分、秋分という前年の2月に決まる祝日や、振替休日などもあります。
今回のサンプルではGoogleがGoogle Calendar Data APIで提供してくれている日本の祝日のデータを取得することにします。
あくまでGoogleが調べた日本の休日のデータなので絶対的な信頼性はありません。Googleが間違っていれば間違った祝日のデータを取得しますので、日付の間違いが損害を及ぼすようなアプリケーションにそのまま使用してはいけません。かならず他の手段で正しいことを確かめるようにします。
use strict; use warnings; use LWP::UserAgent; # Web上から情報を取得するのでHTTPクライアントを使用する。 use XML::Simple; #フィードがXMLで与えられるのでXML::Simpleで解析。 # Google Calendar Data API のURL( 日本の祝日を取得するためのURL ) my $feed_base = 'http://www.google.com/calendar/feeds/japanese@holiday.calendar.google.com/public/full'; # フィードに与える情報 my $start_date = '2007-01-01'; # この日を含む開始日 my $end_date = '2008-01-01'; # この日を含まない終了日 my $max_results = 100; # フィードの最大取得件数 my $query = "start-min=${start_date}&start-max=${end_date}&max-results=${max_results}"; my $feed_url = $feed_base . '?' . $query; # WebからXMLを取得 my $http_client = LWP::UserAgent->new; my $response = $http_client->get( $feed_url ); my $holidays_xml; if( $response->is_success ){ $holidays_xml = $response->content; } else{ die "フィードの取得に失敗しました。"; } # XMLを解析 my $xml_parser = XML::Simple->new(); $XML::Simple::PREFERRED_PARSER = 'XML::Parser'; # XML::SAXがない人のため # パーサを変更 my $holidays_data = $xml_parser->XMLin( $holidays_xml ); my $holidays = []; foreach my $key ( keys %{ $holidays_data->{ 'entry' } } ){ my $holiday_day = $holidays_data->{ entry }{ $key }{ 'gd:when' }{ startTime }; my $holiday_name =$holidays_data->{ entry }{ $key }{title}{content}; push @{ $holidays }, { day => $holiday_day, name => $holiday_name }; } # 文字コードがPerlの内部表現( UTF8 )になっているのでお好みに応じてエンコード use Encode; my $encode_to; if( $^O eq 'MSWin32' ){ $encode_to = 'shift-jis'; } else{ $encode_to = 'utf8'; # お好みに応じて } # データすべてをエンコード foreach my $holiday ( @{ $holidays } ){ foreach my $key ( keys %{ $holiday } ){ $holiday->{$key} = encode( $encode_to, $holiday->{$key} ); } } use Data::Dumper; print Data::Dumper->Dump( [ $holidays ], [ qw( *holidays ) ] ); __END__
祝日の問題
祝日は国によってことなります。また祝日が決まっても振り替え休日で休日が変化することもあります。春分や秋分などのように政府が前年の2月に正式な祝日の日を決定するものもあります。
Google Calender Data API
Google Calender Data API を使用すると、国民の休日を取得することができます。振替休日も考慮されています。信頼性はGoogleの信頼性によります。
コード解説
(1)Google Calender Data API
以下のURLがGoogle Calender Data API の祝日取得のためのURLです。
my $feed_base = 'http://www.google.com/calendar/feeds/japanese@holiday.calendar.google.com/public/full';
(2)クエリ文字列の作成
上記の元になるURLに条件を指定したクエリ文字列を連結します。指定する日付は開始日を含み、終了日を含まないものになります。
# フィードに与える情報 my $start_date = '2007-01-01'; # この日を含む開始日 my $end_date = '2008-01-01'; # この日を含まない終了日 my $max_results = 100; # フィードの最大取得件数 my $query = "start-min=${start_date}&start-max=${end_date}&max-results=${max_results}"; my $feed_url = $feed_base . '?' . $query;
このサンプルでは以下のURLを作成しています。
あとは上記URLの情報をWebから取得して、XMLデータなのでこれを解析して使いやすい形にして、OSに応じて文字コードをエンコードします。
(3)WebからXMLデータを取得する。
LWP::UserAgentは、HTTPクライアントを作成するためのモジュールです。Webブラウザがやっていることをプログラム上で行えます。
use LWP::UserAgent; # Web上から情報を取得するのでHTTPクライアントを使用する。 # WebからXMLを取得 my $http_client = LWP::UserAgent->new; my $response = $http_client->get( $feed_url ); my $holidays_xml; if( $response->is_success ){ $holidays_xml = $response->content; } else{ die "フィードの取得に失敗しました。"; }
(4)XMLを解析して使いやすいデータにする。
XMLを解析するにはXML::Simpleを使用します。XML::SimpleはXMLデータをPerlのデータ(ハッシュ、配列)に変換するためのモジュールです。
use XML::Simple; #フィードがXMLで与えられるのでXML::Simpleで解析 # XMLを解析 my $xml_parser = XML::Simple->new(); $XML::Simple::PREFERRED_PARSER = 'XML::Parser'; # XML::SAXがない人のため # パーサを変更 my $holidays_data = $xml_parser->XMLin( $holidays_xml ); my $holidays = []; foreach my $key ( keys %{ $holidays_data->{ 'entry' } } ){ my $holiday_day = $holidays_data->{ entry }{ $key }{'gd:when'}{ startTime }; my $holiday_name = $holidays_data->{ entry }{ $key }{ title }{ content }; push @{ $holidays }, { day => $holiday_day, name => $holiday_name }; }
XML変換後はデータに以下のようにしてアクセスできます。
# 祝日の日付 $holidays_data->{ 'entry' }{ 識別子となるURL }{'gd:when'}{ startTime }; # 祝日の名前 $holidays_data->{ entry }{ 識別子となるURL }{ title }{ content };
(5)文字コードを変換する。
Webから受け取ったXMLの文字コードはUTF-8です。XML::SimpleがXMLをPerlのデータに変換した時点で、文字はPerlの内部表現( UTF-8 )に変換されます。
これを正しく出力するためには、Perlの内部表現から適切な文字コードにエンコードする必要があります。
(出力する文字列がたとえUTF-8であろうともエンコードは必要です。内部表現UTF-8から外部表現UTF-8に変換すると考えると理解しやすいです。公式には「UTF-8フラグを落とす」といいますがわかりにくい)
use Encode; my $encode_to; if( $^O eq 'MSWin32' ){ $encode_to = 'shift-jis'; } else{ $encode_to = 'utf8'; # OSの標準の文字コードにおうじて変更 } # データすべてをエンコード foreach my $holiday ( @{ $holidays } ){ foreach my $key ( keys %{ $holiday } ){ $holiday->{$key} = encode( $encode_to, $holiday->{$key} ); } }