本章节将介绍 FreeMaker 中的 <#include> 指令。主要内容如下:
您可以使用 include 指令在你的模板中插入另外一个 FreeMarker 模板文件,将在 include 指令出现的位置插入的被包含模版的内容。 被包含的模版文件和 include 指令所在的模板共享变量,就像是被复制粘贴进去的一样。语法如下:
<#include path> <!-- 或 --> <#include path options>
参数说明:
path: 要包含模版文件的路径,可以是一个字符串表达式。例如:profile.baseDir + "/menu.ftl"
options: 可选的,一个或多个选项: encoding=encoding, parse=parse
encoding:被包含文件从包含它的文件继承的编码方式 (实际就是字符集),除非你用这个选项来指定编码方式。 合法的名字有:ISO-8859-2,UTF-8,Shift_JIS,Big5,EUC-KR,GB2312。注意:编码名称要和 java.io.InputStreamReader 中支持的那些一致 (对于Java API 1.3版本:MIME 希望的字符集是从IANA字符集注册处得到的)
parse:如果它为 true,那么被包含的文件将会当作FTL来解析,否则整个文件将被视为简单文本 (也就是说不会在其中查找 FreeMarker 的结构)。如果你忽略了这个选项,那么它默认是 true。
ignore_missing:当为 true,模板引用为空时压制错误,而 <#include ...> 不会输出任何东西。当为 false 时,如果模板不存在, 那么模板处理就会发生错误并停止。如果忽略这个选项,那么它的默认值是 false。
path 参数可以是如 "foo.ftl" 和 "../foo.ftl" 一样的相对路径,或者是如 "/foo.ftl" 这样的绝对路径。 相对路径是相对于使用 import 指令的模板文件夹。 绝对路径是相对于程序员在配置 FreeMarker 时定义的基路径 (通常指代 "模板的根路径")。
include 指令不能由被包含文件的内容所替代, 它只是当 FreeMarker 每次在模板处理期间到达 include 指令时处理被包含的文件。所以对于如果 include 在 list 循环之中的例子, 你可以为每个循环周期内指定不同的文件名。实例:
<html> <head> <title>include 指令</title> </head> <body> <#if message_type="email"> <#include "sub/email.ftl"> <#elseif message_type="sms"> <#include "sub/sms.ftl"> <#else> <#include "sub/default.ftl"> </#if> </body> </html>
上面实例中,将根据 message_type 变量来 include 不同的模版。如果 message_type 等于 “sms”,输出内容如下:
<html> <head> <title>include 指令</title> </head> <body> <div> <h2>一条短信</h2> <p>感谢您对《FreeMaker 零基础教程》的支持,^_^</p> </div> </body> </html>
注意:通常使用 / (斜杠) 来分隔路径成分,而不是 \ (反斜杠)。如果你从你本地的文件系统加载模板,而它使用反斜杠 (像Windows操作系统),也要使用 /。
当然,我们还可以使用 encoding 来指定模版的编码,被包含模版默认继承包含它的模版的编码。例如:
<html> <head> <title>include 指令</title> </head> <body> <#if message_type="email"> <#include "sub/email.ftl" encoding="GB2312"> <#elseif message_type="sms"> <#include "sub/sms.ftl" encoding="GB2312"> <#else> <#include "sub/default.ftl" encoding="GB2312"> </#if> </body> </html>
FreeMaker 的 include 指令 path 属性可以使用 *,星号(*)被解释为 "当前目录或其他任意它的父目录"。因此, 如果模板在 /foo/bar/template.ftl 位置上,有下面这行:
<#include "*/footer.ftl">
那么引擎就会在下面的位置上寻找模板,并按这个顺序:
/foo/bar/footer.ftl:先在 include 指令所在模版的路径下查找
/foo/footer.ftl:到父目录查找
/footer.ftl:到父目录的父目录查找
该机制被称为 acquisition 并允许设计者在父目录中放置通用的被包含的文件, 而且当需要时在每个子路径基础上重新定义它们。 我们说包含它们的模板获得了从包含它的第一个父目录中的模板。请注意, 你不但可以在星号的右面指定一个模板的名字,也可以指定一个子路径。 也就是说,如果前面的模板由下面这个所替代:
<#include "*/commons/footer.ftl">
那么引擎将会从下面的路径开始寻找模板,并按这个顺序:
/foo/bar/commons/footer.ftl
/foo/commons/footer.ftl
/commons/footer.ftl
如果星号没有放到路径的第一个元素:
<#include "commons/*/footer.ftl">
会让引擎将会从下面的路径开始寻找模板,并按这个顺序:
/foo/bar/commons/footer.ftl
/foo/bar/footer.ftl
/foo/footer.ftl
/footer.ftl
然而,在路径中最多只能有一个星号。 指定多余一个星号会导致模板不能被发现。
本地化是指根据当前的设置的语言、国家或方言标识符匹配最优的显示文字。例如:一些网站在中国显示中文,在日本显示日文,在英国显示英文。无论何时模板被请求,期望的本地化都会被指定, FreeMarker 会试图找到变化的模板来匹配本地化环境。当模板包含或引入其它模板时,在内部也会被请求一个本地化环境,也就是 locale 配置的本地化, 通常它是顶级模板的本地化设置。
假设模板使用本地化 en_US 来加载,就是美国英语。当包含其它模板时:
<#include "footer.ftl">
引擎实际上就会寻找一些模板,并按照这个顺序:
footer_en_US.ftl
footer_en.ftl
footer.ftl
它会使用第一个存在的。
注意:如果 FreeMarker 查找的本地化变化是由程序员配置的,那么这里我们只能描述默认的行为。 可以使用 localized_lookup 设置来禁用本地化查找 ( Configuration.setLocalizedLookup(boolean) )。 而且,可以使用 template_lookup_strategy 设置来自行定义推导出的模板名称序列 (Configuration.setTemplateLookupStrategy(TemplateLookupStrategy))。
当你同时使用星号机制 (也就是路径中的 * 步骤) 和本地化查找时,在父目录中有指定本地化的模板优先于在子目录中的本地化模板。 假设你使用下面的代码来包含 /foo/bar/template.ftl:
<#include "*/footer.ftl">
引擎将会查找这些模板,并按照这个顺序:
/foo/bar/footer_en_US.ftl
/foo/footer_en_US.ftl
/footer_en_US.ftl
/foo/bar/footer_en.ftl
/foo/footer_en.ftl
/footer_en.ftl
/foo/bar/footer.ftl
/foo/footer.ftl
/footer.ftl
上面中,父目录中的 /footer_en_US.ftl 优先子目录 /foo/bar/footer_en.ftl,/foo/bar/footer.ftl 模版,这是因为 /footer_en_US.ftl 同时指定了语言 (en)代码与国家地区(US),比 /foo/bar/footer_en.ftl,/foo/bar/footer.ftl 模版信息更完整、具体。