2009年4月14日星期二

FreeMarker中文手册--KLW 类型

类型

支持的类型如下:标量(基本类型)

这些是基本简单的值,可以是:
  • 字符串,简单的文本,比如货物的名称.如果你想在模版中直接使用字符串,而不是一个来自数据模型的变量,可以再字符串两端加引号,如"green mouse" 或者'green mouse'.

  • 数值类型:想货物的价格就是数值类型.全部是数字或者非全部数字并没有明显区别.数值类型只有一种.比如,3/2会一直是1.5,而永远不会是1,就好像你在计算器一样.如果你想在模版中使用数字,直接写就行了,如150,-90.06或者0.001.

  • 布尔型:一个布尔型的值代表逻辑上的真(true)或假(false).例如,一个访问者是否登录.通常你会在if指令中使用布尔值作为条件,像<#if loggedIn>…<#/if>或者 <#if price == 0>...</#if>;其中price == 0部分的值是一个布尔型值.在模版中你可以直接使用保留字true和false代表布尔值.

  • 日期:日期型变量保存着日期时间有关的值.一共有三种:
    • 包含日期,如April 4,2003
    • 包含时间,没有日期部分,如10:19:18 PM,时间部分存为毫秒值.
    • 日期时间(包含日期和时间),如 April 4, 2003 10:19:18 PM,时间部分存为毫秒值.
    不幸的是,由于java平台的限制,FreeMarker有时不能区分是哪部分在使用(日期还是时间).针对这个问题的解决办法是一个高级主题,这里暂不讨论,详细见这里.直接在模版中定义日期值是可以的,但这也是高级主题,详细见这里.
另外需要记住FreeMarker是区分字符串,数值型和布尔值的,所以字符串”150”和数值150是完全不同的.一个数值型包含数字变量,而布尔型只包含true或false.一个字符串包含由任意个字符组成的序列.

容器

有些变量的目的就是包含其他变量,这些变量就是容器.这些被包含的变量也被称为子变量.容器类型是:
  • 哈希(哈希表):每个子变量都和一个独一无二的名字相关联.在一个哈希表中的所有子变量是无序的,所以对哈希表来说,没有第一个子变量,第二个子变量这种说法.自变量都是根据名字访问的.

  • 序列:每个子变量都和一个整数(索引)相关联.第一个子变量关联的是0,第二个是1,第三个是3,依此类推.所有的子变量是按顺序排列的.这些关联的整数也被称为索引.序列通常是密集的,所有的索引通常都关联着子变量,但这并不严格要求.子变量的类型不要求相同.

  • 集合:一个集合,从模版作者的角度看,是一个受限制的序列.你不同访问它的大小,或者根据索引访问它的子变量.但是这些子变量仍可通过list指令罗列出来.
注意到,一个值可有有多种类型,有可能一个值既是哈希表也是序列,在这种情况下,它既支持基于索引的访问,又支持根据名字的访问.尽管如此,一个容器要吗是一个序列,要么是一个哈希表,而不是两者都是.

因为存在哈希表和序列(和集合)中的变量的值可以是任何东西,它可以是哈希表或者序列或者集合.这样,你可以构造任意深度的数据模型结构.

数据模型本身(或者更确切地说,它的根)就是一个哈希表.

子程序
方法和函数
一个值是方法或者函数,表示它能根据你传入的参数,计算出另外的值.

给编程人员:方法或函数是第一阶层的值,就像函数式编程语言中那样.这表示,方法或函数可以作为参数或其它方法或函数的返回值.你可以使用它们给变量赋值等.

假设编程人员在数据模型中添加了方法变量avg,来计算数值的平均数.如果你使用3和5作参数访问avg,然后你可以得到一个值4.

方法的使用方法稍后再做解释,但是这个例子也许可以帮你理解什么是方法:

The average of 3 and 5 is: ${avg(3, 5)}
The average of 6 and 10 and 20 is: ${avg(6, 10, 20)}
The average of the price of a python and an elephant is:
${avg(animals.python.price, animals.elephant.price)}
输出结果是:
The average of 3 and 5 is: 4
The average of 6 and 10 and 20 is: 12
The average of the price of a python and an elephant is:
4999.5
方法和函数的区别是什么呢?对模版设计者来说,它们并没有区别.实际上并不是没有区别,方法基本上来自数据模型(反应为java对象的方法),而函数是在模版中定义的(使用function指令定义的),但是两者的调用方法是一样的.

用户自定义指令

一个类型为用户自定义指令的值可以作为指令来使用(换句话说,和其他FreeMarker标签一样).一个用户自定义的指令,是一个子程序,比如一些可重用的模版碎片.(又是一个高级主题,以后在说啦).

给编程人员的提示:用户定义的指令,比如宏,也是第一阶层的值,和方法和函数一样.

仅仅是为了理解一下用户自定义指令(如果你不理解直接跳过也行),假设我们有个变量,box,它的值是用户自定义指令,用来打印一些花俏的HTML消息框带标题栏和消息.这个box变量可以这样用在模版中:
<@box title="Attention!">
Too much copy-pasting may leads to
maintenance headaches.
</@box>
方法/函数和用户自定义指令比较

这里又是给高级用户的(如果你不理解,直接跳过).这经常是个两难的决定,当你实现某样东西时,是使用方法函数呢,还是使用用户自定义指令呢.这里的经验法则是:使用用户自定义指令而不是方法或者函数,如果:
  • …输出(返回值)是有标记的(HTML,XML等).主要原因是函数的返回结果会自动过滤XML,而用户自定义指令不会. 用户自定义指令的输出是假设为有标记的.

  • …如果副作用而不是返回结果是重要的.例如,一个向服务日志添加一条记录的指令.实际上,用户定义指令是没有返回结果的.当然通过设置非本地变量,也可以得到一些返回值.

  • …它会做流控制(如list指令和if指令),你在方法和函数中做不到这样.
Java对象的方法在模版中作为方法可见,无论这个java方法本身是否可见.这里,你没得选择.

其他
节点
节点变量代表树结构中的一个节点,在XML处理的时候,会常常用到.这是一个高级并且专门的主题.(呵呵,如果不理解,跳过吧)

不过,给高级用户的一个快速浏览:一个节点类似于一个包含其他节点中的序列,这些包含的序列也被称为子节点.一个节点包还一个它自身容器的引用,也被称为父节点.一个节点的主要信息是它的拓扑信息.另外的数据使用使用一个变量有多种类型这个特性来保存.比如,一个值可以是一个节点,又是一个数值,这样可以讲数值存为”有效负荷”.除了拓扑信息,节点也可以保存一些元信息:节点名,节点类型(字符串等)和节点命名空间.例如,XHML文档中的h1节点,它的名字可以是”h1”,节点类型可以是”element”,它的命名空间可以是” http://www.w3.org/1999/xhtml”.这些元数据代表什么,这是数据模型设计者的事情.如何获得节点的拓扑信息和元信息随后章节会详细描述.(在这里你不理解没有关系.)

没有评论: