命名空间
当运行FTL模板时,就会有使用 assign
和 macro
指令创建的变量的集合(可能是空的),
可以从 前一章 来看如何使用它们。
像这样的变量集合被称为 命名空间。
简单的情况下可以只使用一个命名空间,称之为
主命名空间。因为通常只使用该命名空间,
所以就没有意识到这点。
如果想创建可以重复使用的宏,函数和其他变量的集合, 通常用术语来说就是引用 库。 使用多个命名空间是必然的。只要考虑你在一些项目中, 或者想和他人共享使用的时候,你是否有一个很大的宏的集合。 但要确保库中没有宏(或其他变量)名和数据模型中变量同名, 而且也不能和模板中引用其他库中的变量同名是不可能的。 通常来说,变量因为名称冲突时也会相互冲突。 所以要为每个库中的变量使用不同的命名空间。
创建一个库
我们来建立一个简单的库。假设你需要通用的变量
copyright
和 mail
(在你有疑问之前,宏 当作是 变量):
<#macro copyright date> <p>Copyright (C) ${date} Julia Smith. All rights reserved.</p> </#macro> <#assign mail = "jsmith@acme.com">
把上面的这些定义存储在文件 lib/my_test.ftl
中
(目录是存放模板的位置)。假设想在 aWebPage.ftl
中使用这个模板。如果在 aWebPage.ftl
中使用
<#include "/lib/my_test.ftl">
,
那么就会在主命名空间中创建两个变量,这样就不是很好,
因为想让它们只在同一个命名空间''My Test Library''中。所以就不得不使用 import
指令
来代替 include
了。乍一看,这个指令和
include
很相似,但是它会为 lib/my_test.ftl
创建一个空的命名空间,然后在那里执行。lib/my_test.ftl
会发现它自己在一个新的环境中,那里只有数据模型的变量可以找到
(因为它们在哪儿都是可见的),然后会在这个环境中创建两个变量。现在来看这很不错,
但是如果想访问 aWebPage.ftl
中的两个变量,
而它们使用的是主命名空间,就不能看到其他命名空间中的变量。
解决方法是 import
指令不仅仅创建命名空间,而且要通过
import
的调用者(本例中的主命名空间)创建一个新的哈希表变量,
这就成为进入新的命名空间的大门。那么
aWebPage.ftl
就像下面这样:
<#import "/lib/my_test.ftl" as my> <#-- the hash called "my" will be the "gate" --> <@my.copyright date="1999-2002"/> ${my.mail}
要注意它是怎么访问为 /lib/my_test.ftl
创建的命名空间中的变量的,使用新创建的命名空间访问哈希表,
my
。将会输出:
<p>Copyright (C) 1999-2002 Julia Smith. All rights reserved.</p> jsmith@acme.com
如果在主命名空间中有一个变量,名为 mail
或 copyright
,那么就不会引起混乱了,
因为两个模板使用了不同的命名空间。例如,在 lib/my_test.ftl
中修改 copyright
成如下这样:
<#macro copyright date> <p>Copyright (C) ${date} Julia Smith. All rights reserved. <br>Email: ${mail}</p> </#macro>
然后替换 aWebPage.ftl
中的内容:
<#import "/lib/my_test.ftl" as my> <#assign mail="fred@acme.com"> <@my.copyright date="1999-2002"/> ${my.mail} ${mail}
将会输出:
<p>Copyright (C) 1999-2002 Julia Smith. All rights reserved. <br>Email: jsmith@acme.com</p> jsmith@acme.com fred@acme.com
当调用了 copyright
宏之后,输出和上面的是相似的,
因为 FreeMarker 已经暂时转向由 import
指令为
/lib/my_test.ftl
生成的命名空间了。因此,
copyright
宏看到这里存在的变量 mail
,
而不是主命名空间中存在的其它 mail
在引入的命名空间中编写变量
偶尔想要在一个被包含的命名空间上创建或替换一个变量。
那么可以使用 assign
指令,
如果用到了它的 namespace
变量,例如下面这样:
<#import "/lib/my_test.ftl" as my> ${my.mail} <#assign mail="jsmith@other.com" in my> ${my.mail}
将会输出:
jsmith@acme.com jsmith@other.com
命名空间和数据模型
数据模型中的变量在任何位置都是可见的。例如,
如果在数据模型中有一个名为 user
的变量,那么 lib/my_test.ftl
也能访问它,
aWebPage.ftl
当然也能:
<#macro copyright date> <p>Copyright (C) ${date} ${user}. All rights reserved.</p> </#macro> <#assign mail = "${user}@acme.com">
如果 user
是 ''Fred''的话,下面这个例子:
<#import "/lib/my_test.ftl" as my> <@my.copyright date="1999-2002"/> ${my.mail}
将会输出:
<p>Copyright (C) 1999-2002 Fred. All rights reserved.</p> Fred@acme.com
不要忘了在模板的命名空间(可以使用 assign
或 macro
指令来创建的变量)
中的变量有着比数据模型中的变量更高的优先级。因此,
数据模型的内容不会干涉到由库创建的变量。
在一些不寻常的应用中,也许想在模板中创建所有命名空间都可见的变量,
就像数据模型中的变量一样。但是你不能在模板中改变数据模型,
却可以通过 global
指令来达到相似的效果,
可以阅读 参考手册 来获得更多信息。
命名空间的生命周期
命名空间由使用 import
指令中所写的路径来识别。
如果想多次 import
这个路径,那么只会为第一次
import
引用创建命名空间并执行模板。后面相同路径的
import
只是创建一个哈希表当作访问相同命名空间的“门”。
例如,在 aWebPage.ftl
中:
<#import "/lib/my_test.ftl" as my> <#import "/lib/my_test.ftl" as foo> <#import "/lib/my_test.ftl" as bar> ${my.mail}, ${foo.mail}, ${bar.mail} <#assign mail="jsmith@other.com" in my> ${my.mail}, ${foo.mail}, ${bar.mail}
将会输出:
jsmith@acme.com, jsmith@acme.com, jsmith@acme.com jsmith@other.com, jsmith@other.com, jsmith@other.com
这里可以看到通过 my
, foo
和 bar
访问相同的命名空间。
请注意,命名空间是不分层次的,它们相互之间是独立存在的。
那么,如果在命名空间N1中 import
命名空间N2,
那N2也不在N1中,N1只是可以通过哈希表来访问N2。这和在主命名空间中
import
N2,然后直接访问命名空间N2是一样的过程。
每一次 模板的执行过程,
它都有一个私有的命名空间的集合。每一次模板执行工作都是一个分离且有序的过程,
它们仅仅存在一段很短的时间,同时页面用以渲染内容,
然后就和所有填充过的命名空间一起消失了。因此,无论何时我们说第一次调用
import
,一个单一模板执行工作的内容都是这样。
为他人编写库
如果你已经为其他人员编写一个有用的,高质量的库,你也许想把它放在网络上 (就像 http://freemarker.org/libraries.html)。 为了防止和其他作者使用库的命名相冲突,而且引入其他库时要书写简单, 这有一个事实上的标准,那就是指定库路径的格式。这个标准是: 库的路径必须对模板和其他库可用(可引用),就像这样:
/lib/yourcompany.com/your_library.ftl
如果你为Example公司工作,它们拥有www.example.com网的主页, 你的工作是开发一个部件库,那么要引入你所写的FTL的路径应该是:
/lib/example.com/widget.ftl
请注意,www已经被省略了。第三次路径分割后的部分可以包含子目录,可以像下面这样写:
/lib/example.com/commons/string.ftl
一个重要的规则就是路径不应该包含大写字母,为了分隔词语,
使用下划线 _
,就像 wml_form
(而不是 wmlForm
)。
请注意,如果你的工作不是为公司或组织开发库,你应该使用项目主页的URL,比如
/lib/example.sourceforge.net/example.ftl
,或
/lib/geocities.com/jsmith/example.ftl
。