結城浩のはてなブログ

ふと思いついたことをパタパタと書いてます。

HTML::Templateで困っています→解決

PerlのHTML::Templateモジュールって、hashrefのarrayrefしか扱えないのでしょうか。以下に例を示します。サンプル1はよいのだけれど、サンプル2はどうテンプレートを書けばよいか、という話題です。サンプル2はhashrefのhashrefですね。もしどなたか情報があればご教示ください。
サンプル1: (これはOK)

use strict;
use warnings;
use HTML::Template;

my $data1 = [
    { NAME => 'Alice', AGE => 23 },
    { NAME => 'Bobby', AGE => 18 },
    { NAME => 'Chris', AGE => 17 },
];

my $t = HTML::Template->new(
    scalarref => \<<'EOD',
<TMPL_LOOP NAME=USER_LIST>
Name: <TMPL_VAR NAME=NAME>, Age: <TMPL_VAR NAME=AGE>
</TMPL_LOOP>
EOD
);

$t->param(USER_LIST => $data1);
print $t->output();

サンプル1の実行結果:

Name: Alice, Age: 23

Name: Bobby, Age: 18

Name: Chris, Age: 17

サンプル2: (INFOの先がarrayrefではなくhashref)

use strict;
use warnings;
use HTML::Template;

my $data2 = [
    { NAME => 'Alice', INFO => { AGE => 23, MAIL => 'alice@example.com' }},
    { NAME => 'Bobby', INFO => { AGE => 18, MAIL => 'bob@example.com' }},
    { NAME => 'Chris', INFO => { AGE => 17, MAIL => 'chris@example.com' }},
];

my $t = HTML::Template->new(
    scalarref => \<<'EOD',
<TMPL_LOOP NAME=USER_LIST>
Name: <TMPL_VAR NAME=NAME>, Info: <TMPL_VAR NAME=INFO>
</TMPL_LOOP>
EOD
);

$t->param(USER_LIST => $data2);
print $t->output();

サンプル2の実行結果: (INFOの先が展開されない)

Name: Alice, Info: HASH(0x276e90)           ←ここのHASHをちゃんと展開したい…。

Name: Bobby, Info: HASH(0x18fdce4)

Name: Chris, Info: HASH(0x1968c88)

追記:
khashiさんから「hashrefのarrayrefしか扱えないはず」とのこと。そうですか…。khashiさんのエントリにあるようにarrayrefつまり[ ]でくくってやるのは確かにアリですね。ただ、別のAPIからの結果が上の$data2のような形のときにちょっとつらいなあ、と。ともあれ、「扱えないはず」というのは重要情報でした。とっても感謝です♪
で、どうしよう。(1) データ構造をいじる。 (2) HTML::Templateをhackする。 (3) Template::Toolkitに乗り換える。うーん。
追記:(解決)
khashiさんからHTML::Template::Compiledを教えていただきました。これこれ!これですよ!ありがとうございますっ。ちなみに、HTML::Template::Toolkitのサンプルにまさに INFO => { ... } というのが出てきて笑った。
サンプル3:(HTML::Templte::Compiledを使う)

use strict;
use warnings;
use HTML::Template::Compiled;

my $data2 = [
    { NAME => 'Alice', INFO => { AGE => 23, MAIL => 'alice@example.com' }},
    { NAME => 'Bobby', INFO => { AGE => 18, MAIL => 'bob@example.com' }},
    { NAME => 'Chris', INFO => { AGE => 17, MAIL => 'chris@example.com' }},
];

my $t = HTML::Template::Compiled->new(
    scalarref => \<<'EOD',
<TMPL_LOOP NAME=USER_LIST>
Name: <TMPL_VAR NAME=NAME>, Age: <TMPL_VAR NAME=INFO.AGE>, MAIL: <TMPL_VAR NAME=INFO.MAIL>
</TMPL_LOOP>
EOD
);

$t->param(USER_LIST => $data2);
print $t->output();

サンプル3の実行結果:

Name: Alice, Age: 23, MAIL: alice@example.com

Name: Bobby, Age: 18, MAIL: bob@example.com

Name: Chris, Age: 17, MAIL: chris@example.com

ちなみに、ActivePerlでは、ppm installで一発でした。

C:\work> ppm install HTML::Template::Compiled
Downloading ActiveState Package Repository packlist...not modified
Downloading Theory X5 packlist...not modified
Downloading HTML-Template-Compiled-0.84...done
Unpacking HTML-Template-Compiled-0.84...done
Generating HTML for HTML-Template-Compiled-0.84...done
Updating files in site area...done
  31 files installed