FreeMarker Template Language 入門(6)
パッケージJava製品開発担当の大です。こんにちは。
前回に引き続き、FreeMarker Template Language(以下 FTL)の解説をします。
今回は、マクロに関するお話です。
マクロとは
FreeMarkerにおけるマクロとは、「変数に束縛されたテンプレートのフラグメント(断片)」です。簡単な例をあげましょう:
<#macro greet> こんにちは! </#macro>
ここで定義された変数greetは、ユーザ定義のディレクティブとして呼び出すことができます。通常のディレクティブと違い、ユーザ定義のディレクティブは先頭に「@」をつけて呼び出します:
<@greet />
実行すると、こんな風に表示されます:
こんにちは!
マクロは、引数をとることもできます:
<#macro greet user>
こんにちは、${user}さん!
</#macro>
呼び出しはこんな風になります:
<@greet user="大"/>
実行結果:
こんにちは、大さん!
関数との違い
マクロは、前回出てきた関数とは異なるものです。
関数は値を返さなければなりませんが、マクロは、値を返すことができません。
マクロの本体は、前述のとおり「テンプレートのフラグメント」なので、テキストはそのままテキストとして出力されますが、関数の本体ではテキスト出力があっても無視されます。
関数呼び出しは式を書ける場所ならどこでもできますが、マクロ呼び出しはFTLタグを書ける場所でしかできません。
たとえば、上で定義したgreetマクロぐらいの内容なら、関数として定義、使用することも可能でしょう。
<#function greet user>
<#return "こんにちは、${user}さん!">
</#function>
${greet("大")}
しかし、以下のようににちょっと複雑な出力をするなら、マクロでやるほうが関数でやるより便利です(関数でもやれないことはありませんが。。)。
<#macro table cols rows>
<table>
<#list 1..rows as row>
<tr>
<#list 1..cols as col>
<td>${row}, ${col}</td>
</#list>
</tr>
</#list>
</table>
</#macro>
<@table cols=3 rows=2 />
<table>
<tr>
<td>1, 1</td>
<td>1, 2</td>
<td>1, 3</td>
</tr>
<tr>
<td>2, 1</td>
<td>2, 2</td>
<td>2, 3</td>
</tr>
</table>
returnディレクティブ
マクロ中でもreturnディレクティブを使用できます。が、前述のとおり値を返すことはできません。処理をそこで終了するというだけです。
<#macro hoge> ここは表示されます。 <#return> ここは表示されません。 </#macro>
nestedディレクティブ
nestedディレクティブは、マクロ呼び出し時に渡されたテンプレートのフラグメントをマクロ中から呼び出します。Rubyをご存知でしたら、yieldみたいなものと考えればわかりやすいでしょう。nestedを利用すれば、マクロをより汎用的に定義することができます。たとえば、リストを引数にとり、その要素をnested呼び出しに使用するマクロを考えます。
<#macro lprint lst>
<#list lst as item>
・${item}<#nested item />
</#list>
</#macro>
このマクロを、
<@lprint 1..3; x>^2 = ${x * x}</@lprint>
のように呼び出せば、
・1^2 = 1 ・2^2 = 4 ・3^2 = 9
このように表示されます。また、
<@lprint 1..3; x>^3 = ${x * x * x}</@lprint>
と違うフラグメントを渡せば、
・1^3 = 1 ・2^3 = 8 ・3^3 = 27
違う出力が得られます。
<@lprint ["Let's go", "to the", "land of Medetai"] />
nested呼び出しするものがなければ、何も行われません。
・Let's go ・to the ・land of Medetai