前回はMobaSiFに含まれる個々のPerlモジュールを解説しました。今回は,MobaSiFに含まれるテンプレートエンジンMTemplateについて説明します。
テンプレートエンジンMTemplate
MobaSiFに付属するテンプレートエンジンMTemplateは,次のような特徴を持ちます。
- 1つのテンプレートファイルで3キャリアに対応
1つのテンプレートファイルを記述するだけで,3キャリアに対応できます。また,キャリアごとに表示する内容を変えることもできます。
- 事前コンパイルにてバイナリテンプレート生成
HTTPリクエストを受け付けるたびにテンプレートをparseするのは非効率と考え,事前コンパイルによりバイナリテンプレートを生成する方式をとっています。
- mmapによる共有メモリの利用
DeNAのサービスで長く使われているFastCGIでは,プロセス上のメモリキャッシュを利用するとアプリケーションプロセスごとにメモリが利用されてしまい非効率です。そこで,UNIX系のシステムコールであるmmap( )を使い,ファイルをメモリにマップして各アプリケーションプロセスから共通のメモリ領域を利用できるようにしています。
- XSによる高速処理
主要部分がC言語で実装されているため処理が高速です。
MTemplateの利用の流れ
(1)テンプレートファイルの作成
テンプレートファイルはtemplate/_system以下に.htmlという拡張子を付けて置きます。文字コードはShift-JISを利用します。テンプレートファイルで利用できる独自タグなどについては後述します。
(2)テンプレートファイルのコンパイル
script/tool/compile_templateコマンドを実行すると,templateディレクトリ以下のテンプレートファイルのうち,前回のコンパイル以後に変更のあったファイルがすべてコンパイルされます。コンパイル結果はdata/html_binディレクトリに出力されます。
Webサーバ(Webアプリケーション)が起動している場合でもコンパイルされたテンプレートは即時に反映されるので,再起動は不要です。
(3)Webアプリケーションロジック(.pmファイル)から呼び出す
リスト11は,Webアプリケーションロジックからテンプレートを利用する例です。MTemplate::
insert( )の第1引数はテンプレートファイル名で,template/_systemからの相対パスで記述し,拡張子.htmlは省略します。たとえば上記の利用例では,template/_system/regist/test.htmlが利用されます。
リスト11 Webアプリケーションロジックからテンプレートを利用する
use MTemplate;
my $html = MTemplate::insert("regist/test", $rhData);
Common::output(¥$html);
第2引数は,変数展開や条件分岐に利用されるハッシュリファレンスです。詳しい利用の仕方については次項「テンプレートファイルの記述方法」とともに説明します。
テンプレートファイルの記述方法
MTemplateのテンプレートファイル独自の記述は「$」と「$」の間で行います。あるいは「$で囲まれたタグを利用します」という表現が正しいかもしれません。以下,具体的な記述方法を説明します。
変数展開
リスト12は,テンプレートファイルでの変数展開の記述例です。NAMEはMTemplate::insert( )の第2引数に与えたハッシュリファレンスのキーに対応します。たとえば$rhData->{text}にセットした値によって,$b:=text$が置き換えられます。また,オプションについては表4にまとめました。
リスト12 変数展開の記述例
$=OPTIONS:NAME$
表4 MTemplateで使用するオプション
| 表記 | 機能 | 詳細 |
|---|---|---|
| h | HTML特殊文字変換 | 下記のような変換を行う。クロスサイトスクリプティングなどへの対策のため,hオプションは常に付けるのが原則 " => " < => < > => > & => & |
| hn | 改行コード変換 | hの処理に加え「\n」を「<br />」に変換する |
| e | url escape | URLに含めてはならない文字をエスケープする(例:半角スペースを%20に変換) |
| b | bypass | 無変換 |
条件分岐
条件分岐のときの記述はリスト13のようになります。これらの条件分岐はネスト({ }の間にさらにif文を書くなど)も可能です。
条件文CONDには表5の形式が利用できます。左辺値の変数は,変数展開と同様,ハッシュリファレンスのキーを記述します。右辺値は定数のみ利用できます。また,変数の値が0のとき(表5の★印)の場合は,Perlの一般的な動作と異なる点にも注意が必要です。
リスト13 条件分岐の記述例
$ if (COND) { $
$ } elsif (COND1 || COND2) { $
$ } elsif (COND1 && COND2) { $
$ } else { $
$ } $
表5 CONDの形式
| 式 | はたらき |
|---|---|
| 変数=定数 | 文字列比較 |
| 変数!=定数 | 文字列比較 |
| 変数 | ne '' ★(空文字との比較なので,変数="0"の場合はTRUE) |
| !変数 | eq '' ★(空文字との比較なので,変数="0"の場合はFALSE) |
| 変数>=定数 | 数値比較 |
| 変数>定数 | 数値比較 |
| 変数<=定数 | 数値比較 |
| 変数<定数 | 数値比較 |
ループ
ループはリスト14の形式になります。ループの中にループを記述することもできます。
リスト14 テンプレートファイル中のループ記述例
$ loop (NAME) { $
$ } $
たとえば,前述の$rhDataについてリスト15のようにハッシュリファレンスを要素に持つリストのリファレンスをセットし,テンプレートファイルにはリスト16のような記述を行うと,出力は図2のようになります。つまり,リストの各要素のハッシュリファレンスに関して変数展開が行われながら繰り返し処理がされるということです。
リスト15 ループに渡すリストの定義例
my @fruits = ( {name => 'apple', price => '100'},
{name => 'orange', price => '120'},
{name => 'melon', price => '500'},
);
$rhData->{List} = \@fruits;
リスト16 リストの各要素を表示するテンプレートファイル例
$ loop (List) { $
$=h:name$ は $=h:price$ 円!
$ } $
図2 実行結果
apple は 100 円! <br> orange は 120 円! <br> melon は 500 円! <br>

