FreeMarker(四)类型
简介:
支持的类型有:
标量:字符串、数字、布尔值、日期
容器:哈希表、序列、集
子程序:方法和函数、用户自定义指令
其他/很少使用:节点
1.标量
标量是最基本,最简单的数值类型,它们可以是:
字符串:简单的文本,例如:产品的名称。
如果想在模板中直接给出字符串的值,而不是使用数据模型中的变量,那么将文本写在引号内即可,比如“green mouse”或者‘green mouse’。
数字:例如:产品的价格。整数和非整数是不区分的,只有单一的数字类型。比如使用了计算器,计算3/2的结果是1.5而不是1。
如果要在模板中直接给出数字的值,可以这么来写:150,-90.05,或者0.001。
布尔值:布尔值代表了逻辑上的对与错(是或否)。例如:用户到底是否登录了。最典型的应用是使用布尔值作为if指令的条件,比如<#if loggedIn>...</#if>或者<#if price == 0>...</#if>,后面这个price==0部分的结果就是布尔值。在模板中可以使用保留字true和false来指定布尔值。
日期:日期变量可以存储和日期/时间相关的数据,一共三种变化。
精确到天的日期(通常指的是“日期”),比如April 4,2003
每天的时间(不包括日期部分),比如10:19:18 PM。时间部分的存储精确到毫秒。
日期-时间(也称作“时间戳”),比如April4,2003 10:19:18 PM。时间部分的存储精确到毫秒。
不幸的是,受到java平台的限制,FreeMarker是不能决定日期的哪部分来使用(也就是说,是日期-时间格式,每天的时间格式等)。这个问题的解决方法是高级主题了,后面的章节将会讨论到。
在模板中直接定义日期数值是可以的,但这也是高级主题,后面的章节将会讨论到。
要记住,FreeMarker区别字符串,数字和布尔值,所以字符串“150”和数字150是完全不同的两种数值。数字持有的是数字的值,布尔值表达的是裸机上的对或错。字符串可以是任意字符的序列。
2.容器
这些值存在的目的是为了包含其他变量,它们仅仅作为容器。被包含的变量通常是子变量。容器的类型有:
哈希表:每个子变量都可以通过一个唯一的名称来查找,这个名称是不受限制的字符串。哈希表并不确定其中子变量的顺序,也就是说没有第一个变量,第二个变量这样的说法,变量仅仅是通过名称来访问的。(就像java语言中的HashMap一样,是实现了Hash算法的Map,不记录内部元素的顺序,仅仅通过名称来访问。)
序列:每个子变量通过一个整数来标识。第一个子变量的标识符是0,第二个是1,第三个是2,这样来类推,而且子变量是有顺序的。这些数字通常被称为是子变量的索引。序列通常比较密集,也就是所有的索引,包括最后一个子变量的,它们和子变量都是相关联的,但不是绝对必要的。子变量的数值类型也并不需要完全一致。
集:从模板设计者角度来看,集是有限制的序列。不能获取集的大小,也不能通过索引取出集中的子变量,但是它们仍然可以通过list指令来遍历。
要注意一个数值也可以有多种类型,对于一个数值可能存在哈希表和序列这两种类型,这时,该变量就支持索引和名称两种访问方式。不过容器基本是当做哈希表或者序列来使用的,而不是两者同时使用。
尽管存储在哈希表,序列(集)中的变量可以是任意类型的,这些变量也可以是哈希表,序列(集)。这样就可以构建任意深度的数据结构。
数据模型本身(最好说成是它的根)也是哈希表。
3.子程序
方法和函数:一个值是方法或者函数的时候那么它就可以计算其他值,结果取决于传递给它的参数。这部分是对程序员来说的:方法/函数是第一类值,就像函数化的编程语言。也就是说函数/方法也可以是其他函数或方法的参数或者返回值,并可以把它们定义成变量。
假设程序员在数据模型中放置了一个方法变量avg,那么它就可以被用来计算数字的平均值。给定3和5作为参数,访问avg时就能得到结果4。
那么方法和函数有什么区别呢?这是模板作者所关心的,它们没有关系,但也不是一点关系都没有。方法是来自于数据模型(它们反射了java对象的方法),而函数是定义在模板内的(使用了函数指令-这也是高级主题),但二者可以用同一种方式来使用。
用户自定义指令:(换句话说,就是FreeMarker的标签)这种类型的值也是一种子程序,一种可以复用的模板代码段。但这也是高级主题,我们在后续章节中会详细解释。这部分是对程序员来说的:用户自定义指令(比如宏),也是第一类值,就像函数/方法一样。这里仅仅对用户自定义指令有一个认识即可(如果现在还不能理解可以先忽略它)。假设现在有一个变量,box,它的值是用户自定义的指令,用来打印一些特定的HTML信息,这个指令定义了一个标题和其中的信息。
函数/方法和用户自定义指令的比较:这部分内容也是对高级用户来说的(如果你还不能理解可以先忽略它)。如果要使用函数/方法或自定义指令去实现一些东西的时候,二者之间的选择是两难的。按经验来说,如果能够实现,请先用自定义指令而不要用函数/方法,指令特征如下:
1.输出(返回值)的是标记(HTML,XML等)。主要原因是函数的返回结果可以自动进行XML转义(这是因为${...}的特性),而用户自定义指令的输出则不是(这是因为<@...>的特性所致,他的输出假定为是标记,因此就不再转义)。
2.副作用也是很重要的一点,它没有返回值。例如一个指令的目的是往服务器日志中添加一个条目。(事实上你不能得到自定义指令的返回值,但有些反馈的类型是有可能设置非本地变量的)
3.会进行流程的控制(就像list或if指令那样),但是不能在函数/方法上这么做。在模板中,FreeMarker不知道的java对象的方法通常是可以作为方法来使用的,而不是考虑java对象方法本身的特性,因为在这里没有其他的选择。
4.其他
节点:节点变量代表了树状结构中的一个节点,而且通常是配合XML格式来处理的,这是专业而且更高级的主题。这里我们仅对高级用户进行一个概要说明:节点和存储在其他节点中的序列很相似,通常也被当作为子节点。节点存储它所在的容器节点的引用,也就是父节点。节点的主要作用是拓扑信息。其他数据必须通过使用多类型的值来存储。就像一个值可以同时是一个节点和一个数字,这样它存储的数字可以作为如支付额来使用。除了拓扑信息,节点也可以存储一些元信息:如节点名称,它的类型(字符串),命名空间(作为字符串)。若一个节点象征XHTML文档中的h1元素,那么它的名字可以是“h1”,类型可以是“element”,命名空间可以是“http://www.w3.org/1999/xhtml”。但对于数据模型设计者来说,这些元信息,还有如何来使用它们又有什么意义呢。