FreeMarker Template Language 入門(7)
パッケージJava製品開発担当の大です。こんにちは。毎日暑いですね。
前回に引き続き、FreeMarker Template Language(以下 FTL)について書きます。
今回は、名前空間と変数のスコープに関するお話です。
名前空間
テンプレートの数が増え、開発規模が少し大きくなってくると、再利用可能なマクロや共通で使いたい変数などをまとめておいて、各テンプレートから参照したくなります。そのような場合に利用可能なディレクティブが、includeとimportです。
共通部分をまとめたファイル(common.ftl):
<#macro greet name>
こんにちは、${name}さん!
</#macro>
<#assign url="https://www.hos.co.jp/">
includeを使って参照する場合は、以下のような感じになります。
<#include "common.ftl">
${url}
<@greet name="大" />
実行結果:
https://www.hos.co.jp/ こんにちは、大さん!
しかし、includeでは困ったことが起きる場合があります。共通部分をまとめたFTLファイル中で使われている変数名やマクロの名前が、呼び出し側でも使われている場合、上書きされてしまうのです。
<#assign url="http://example.com/">
include前: ${url}
<#include "common.ftl">
include後: ${url}
実行結果:
include前: http://example.com/ include後: https://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="大" />
実行結果:
https://www.hos.co.jp/ こんにちは、大さん!
変数のスコープ
これまでこの連載中では、変数の宣言には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}