WebAPIの返すJSONは、おいそれと読めるもんじゃない。例えばTwitterのpublic_timelineだとこんな感じ。
JSONをPerlのオブジェクトに変換する
JSONモジュールを使えば、簡単にJSONをPerlのオブジェクトに変換できる。
use JSON qw(from_json); my $obj = from_json($json);
JavaScriptのオブジェクトと配列は、Perlのハッシュと配列に変換される。*1
JSONの入れ子構造をulで表現する
見やすく表現するために、JSONの入れ子はHTMLのul要素で表現することにした。
sub json_to_html { my ($json) = @_; my $html; if (ref($json) eq 'HASH') { foreach my $key (sort keys %$json) { $html .= $cgi->li($cgi->strong("$key: "), json_to_html($json->{$key})); } return defined $html ? 'Object{<a href="#">...</a>}'.$cgi->ul($html) : 'Object{}'; } elsif (ref($json) eq 'ARRAY') { for (my $i = 0; $i < @$json; $i++) { $html .= $cgi->li($cgi->strong("$i: "), json_to_html($json->[$i])); } return defined $html ? 'Array[<a href="#">...</a>]'.$cgi->ul($html) : 'Array[]'; } return defined $json ? $cgi->tt(q(').$cgi->escapeHTML($json).q(')) : '(null)'; }
入力パラメータはPerlのオブジェクト。HTMLの編集にはCGI.pmを使ってます。
こんな感じで json_to_html() を呼び出せばよい。
my $json = $cgi->param('json'); my $html; if (length $json) { eval { $html = $cgi->ul({class=>'JSON'}, $cgi->li(json_to_html(from_json($json)))); }; if ($@) { $@ =~ s/ at \S+ line \d+\.$//; $html = $cgi->p($@); } }
from_json() は変換に失敗するとdieするので、ちょっと厄介。evalブロック内で処理する必要がある。dieした際に有用なメッセージが $@ に入ってるんだけど、ファイル名と行番号はじゃまなので捨ててます。*2
要素を非表示にできるようにする
大きなデータの場合、全体を表示すると見にくいので、Firebugのように要素の表示・非表示を切り替えられるようにした。
以下のJavaScriptを埋め込む。jQueryを使っています。
$(document).ready(function(){ $('.JSON ul').each(function(){ var ul = $(this); ul.parent().children('a').click(function(){ ul.slideToggle('fast'); return false; }); ul.hide(); }); $('.JSON > li > ul').show(); });
全体のコード
#!/usr/bin/perl -T use strict; use CGI; use CGI qw(fatalsToBrowser); use JSON qw(from_json); my $cgi = new CGI; $cgi->charset('utf-8'); my $jquery_url = 'http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js'; my $script = <<'++'; $(document).ready(function(){ $('.JSON ul').each(function(){ var ul = $(this); ul.parent().children('a').click(function(){ ul.slideToggle('fast'); return false; }); ul.hide(); }); $('.JSON > li > ul').show(); }); ++ sub json_to_html { my ($json) = @_; my $html; if (ref($json) eq 'HASH') { foreach my $key (sort keys %$json) { $html .= $cgi->li($cgi->strong("$key: "), json_to_html($json->{$key})); } return defined $html ? 'Object{<a href="#">...</a>}'.$cgi->ul($html) : 'Object{}'; } elsif (ref($json) eq 'ARRAY') { for (my $i = 0; $i < @$json; $i++) { $html .= $cgi->li($cgi->strong("$i: "), json_to_html($json->[$i])); } return defined $html ? 'Array[<a href="#">...</a>]'.$cgi->ul($html) : 'Array[]'; } return defined $json ? $cgi->tt(q(').$cgi->escapeHTML($json).q(')) : '(null)'; } my $json = $cgi->param('json'); my $html; if (length $json) { eval { $html = $cgi->ul({class=>'JSON'}, $cgi->li(json_to_html(from_json($json)))); }; if ($@) { $@ =~ s/ at \S+ line \d+\.$//; $html = $cgi->p($@); } } print $cgi->header(-charset=>'utf-8'), $cgi->start_html( -title => 'JSON to HTML', -encoding => 'utf-8', -script => [ { src => $jquery_url }, $script ], ), $cgi->h1($cgi->a({href=>''},'JSON to HTML')), $html, $cgi->start_form, $cgi->h2('Input JSON'), $cgi->textarea('json','',20,120), $cgi->div($cgi->submit); $cgi->endform; $cgi->end_html;