命名空间

优质
小牛编辑
141浏览
2023-12-01

当运行FTL模板时,就会有使用 assignmacro 指令创建的变量的集合(可能是空的), 可以从 前一章 来看如何使用它们。 像这样的变量集合被称为 命名空间。 简单的情况下可以只使用一个命名空间,称之为 主命名空间。因为通常只使用该命名空间, 所以就没有意识到这点。

如果想创建可以重复使用的宏,函数和其他变量的集合, 通常用术语来说就是引用 。 使用多个命名空间是必然的。只要考虑你在一些项目中, 或者想和他人共享使用的时候,你是否有一个很大的宏的集合。 但要确保库中没有宏(或其他变量)名和数据模型中变量同名, 而且也不能和模板中引用其他库中的变量同名是不可能的。 通常来说,变量因为名称冲突时也会相互冲突。 所以要为每个库中的变量使用不同的命名空间。

创建一个库

我们来建立一个简单的库。假设你需要通用的变量 copyrightmail (在你有疑问之前,宏 当作是 变量):

<#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

如果在主命名空间中有一个变量,名为 mailcopyright,那么就不会引起混乱了, 因为两个模板使用了不同的命名空间。例如,在 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

不要忘了在模板的命名空间(可以使用 assignmacro 指令来创建的变量) 中的变量有着比数据模型中的变量更高的优先级。因此, 数据模型的内容不会干涉到由库创建的变量。

Note:

在一些不寻常的应用中,也许想在模板中创建所有命名空间都可见的变量, 就像数据模型中的变量一样。但是你不能在模板中改变数据模型, 却可以通过 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

这里可以看到通过 myfoobar 访问相同的命名空间。

请注意,命名空间是不分层次的,它们相互之间是独立存在的。 那么,如果在命名空间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