結城浩のはてな日記 このページをアンテナに追加 RSSフィード Twitter

2007年5月1日(Tue)

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

khashikhashi 2007/05/01 18:04 こんにちは。コメントで書くには長いと思ったので、自分のところに書いてトラックバックを送りました。もっといい方法があればいいのですが…。

khashikhashi 2007/05/01 19:09 HTML::Template::Compiledを使う方法を追記しました。
でも、ここまでやるならTemplate::Toolkitの方がいいかも(^_^;