FreeMarker Template Language 入門(7)
パッケージJava製品開発担当の大です。こんにちは。毎日暑いですね。
前回に引き続き、FreeMarker Template Language(以下 FTL)について書きます。
今回は、名前空間と変数のスコープに関するお話です。
名前空間
テンプレートの数が増え、開発規模が少し大きくなってくると、再利用可能なマクロや共通で使いたい変数などをまとめておいて、各テンプレートから参照したくなります。そのような場合に利用可能なディレクティブが、include
とimport
です。
共通部分をまとめたファイル(common.ftl):
<#macro greet name> こんにちは、${name}さん! </#macro> <#assign url="http://www.hos.co.jp/">
includeを使って参照する場合は、以下のような感じになります。
<#include "common.ftl"> ${url} <@greet name="大" />
実行結果:
こんにちは、大さん!
しかし、include
では困ったことが起きる場合があります。共通部分をまとめたFTLファイル中で使われている変数名やマクロの名前が、呼び出し側でも使われている場合、上書きされてしまうのです。
<#assign url="http://example.com/"> include前: ${url} <#include "common.ftl"> include後: ${url}
実行結果:
include前: http://example.com/ include後: http://www.hos.co.jp/
import
を使えば、共通部分をまとめたFTLファイルを、呼び出し側の名前空間とは別の名前空間に読み込みますので、上書きされません。
<#assign url="http://example.com/"> import前: ${url} <#import "common.ftl" as hoge> import後: ${url}
実行結果:
import前: http://example.com/ import後: http://example.com/
アクセスするには、import
時に「as 名前
」で指定した名前を使ってアクセスします。
<#import "common.ftl" as hoge> ${hoge.url} <@hoge.greet name="大" />
実行結果:
こんにちは、大さん!
変数のスコープ
これまでこの連載中では、変数の宣言にはassign
ディレクティブとlocal
ディレクティブを使用してきました。変数は、このほかにglobal
ディレクティブで宣言することもできます。また、繰り返しを行うlist
ディレクティブでリストの各要素を参照するループ変数というものがあります。これらの違いは以下のようになっています。
種類 | 宣言 | スコープ |
---|---|---|
グローバル変数 | global ディレクティブで宣言 |
すべての名前空間から参照可能(どの名前空間にも含まれません) |
(プレーンな)変数 | assign ディレクティブで宣言 |
名前空間内 |
ローカル変数 | local ディレクティブで宣言 |
マクロ/関数内 |
ループ変数 | list ディレクティブで宣言 |
ループ内 |
以上を踏まえて、宣言した変数がどのように見えるか検証してみましょう。
main.ftl:
<#global x = "グローバル1" /> 01. ${x} <#assign x = "プレーン1" /> 02. ${x} <#import "common.ftl" as common /> <@common.test /> 11. ${x} 12. ${common.x}
common.ftl:
<#macro test> 03. ${x} <#global x = "グローバル2"> 04. ${x} <#assign x = "プレーン2"> 05. ${x} <#local x = "ローカル1"> 06. ${x} <#list ["ループ1"] as x> 07. ${x} <#local x = "ローカル2"> 08. ${x} <#assign x = "プレーン3"> 09. ${x} </#list> 10. ${x} </#macro>
実行結果:
01. グローバル1 02. プレーン1 03. グローバル1 04. グローバル2 05. プレーン2 06. ローカル1 07. ループ1 08. ループ1 09. ループ1 10. ローカル2 11. プレーン1 12. プレーン3
- グローバルに宣言した
x
です。 - 同じ名前でプレーンな
x
を宣言すると、グローバルなx
が隠れます。 - インポートされた
common
名前空間では、グローバルなx
が見えています。 - グローバルな
x
を上書きしてみます。 - もちろんここでもプレーンな
x
を宣言すると、グローバルなx
が隠れます。 - ローカルな
x
を宣言すると、今度はプレーンなx
が隠れます。 - ループ変数
x
を宣言すると、ローカルなx
が隠れます。 - ローカルな
x
を上書きしてみますが、隠れたままです。 - プレーンな
x
を上書きしてみますが、隠れたままです。 - ループを抜けたので、ローカルな
x
が見えるようになります。08で上書きされた値になっています。 - メインの名前空間では、相変わらずプレーンな
x
が見えます。 common
のx
を見ると、09で上書きされた値になっています。
同名の変数の宣言により隠れてしまった変数を参照するために、さまざまな「スペシャル変数」が用意されています。たとえば、グローバルのx
の値を参照したい場合は、以下のように書くことができます。
${.globals.x}