表达式

当需要给插值或指令参数提供值时,可以使用变量或其他复杂的表达式


例如:

  • 当给插值提供值时 —— 插值的使用方式为 ${expression},把它放到想输出文本的位置上然后就可以打印出来了。例如${(5+8)/2}会打印出6.5
  • 当给指令参数提供值时 —— <#if expression> ... </#if>,这里的表达式结果必须时布尔类型;比如<#if  2 < 3  >是结果为true的布尔表达式


直接确定值

字符串

在文本中确定字符串的方法是看引号和单引号,比如 "some text" 和 'same text' 这两种形式是相等的。如果文本本身包含用于字符引用的引号或反斜杠时,应该使用转移。

例如:


${"It's \"quoted\" and
this is a backslash: \\""}

${'It\'s "quoted" and
this is a backslash: \\'}



输出为:


It's "quoted" and
this is a backslash: \

It's "quoted" and
this is a backslash: \

下面的表格是FreeMarker支持的所有的转义字符,在字符串使用反斜杠的其他所有情况都是错误的,运行模板都会失败:

转义序列

含义

\

引号(u0022)

\'

单引号(u0027)

\\

反斜杠(u005C)

\n

换行符(u000A)

\r

回车(u000D)

\t

水平制表符(u0009)

\b

退格(u0008)

\f

换页(u000C)

\l

小于号:<

\g

大于号:>

\a

和号:&

\xCode

字符的16进制Unicode码


原生字符串

在原生字符串中,反斜杠和${没有特殊的含义,它们被视为普通的字符。为了表明字符串是原生字符串,在开始的引号或单引号之间放置字母 r ,例如:

${r"${foo}"}
${r"C:\foo\bar"}


打印结果:

${foo}
C:\foo\bar



数字

输入不带引号的数字就可以直接指定一个数字,必须使用 点 作为小数的分隔符而不能是其他的分组分隔符。可以使用 - 和 +  表明符号。科学计数法暂不支持,且不能在小数点之前不写0

${08}, ${+8}, ${8.00}, ${8}


与数值文字 08,+8, 8.00 和 8 的打印结果是完全相等的。


布尔值

直接写 true  或 false ,不需要使用引号。


序列

指定一个文字的序列,使用逗号分隔其中的每个子变量,然后把整个列表放到方括号中。

例如:

<#list ["winter", "spring", "summer", "autumn"] as x>
${x}
</#list>



打印结果:

winter
spring
summer
autumn



列表中的项目是表达式,也可以这样做:

[2 + 2, [1,2,3,4], "whatnot"]

第一个子变量是数字4,第二个子变量是一个序列,第三个子变量是字符串“whatnot”。


也可以使用 start .. end 形式存储数字范围的序列;例如 2 .. 5和[2,3,4,5]是相同的。


哈希表

在模板中指定一个哈希表,就可以遍历用逗号分隔开的“键/值”对,把列表放到花括号内。键和值成对出现并以冒号分隔。

例如:

{“name”:"green mouse", "price":150}

名字和值都是表达式,但是用来检索的名字必须是字符串类型。


检索变量

顶层变量

为了访问顶层变量,可以简单使用变量名,例如:

${user}



从哈希表中检索数据

假定如下数据模型:

(root)
|
+- book
| |
| +- title = "Breeding green mouses"
| |
| +- author
|    |
|    +- name = "Julia Smith"
|    |
|    +- info = "Biologist, 1923-1985, Canada"
|
+- test = "title"



下面这些形式都是等价的:

book.author.name, 
book["author"].name, 
book.author.["name"], 
book["author"]["name"]



对于顶层变量来说,如果尝试访问一个不存在的变量也会引起错误导致模板解析执行的中断(除非程序员事先配置过FreeMarker)。

从序列中检索数据

使用方括号加索引值,例如:

animal[0].name



特殊变量

特殊变量是由FreeMarker引擎本身定义的,为了使用它们,可以按照如下语法形式来进行:


.variable_name



通常情况下是不需使用特殊变量。


字符串操作

插值/连接

如果要在字符串中插入表达式的值,可以在字符串的文字中使用${…}(#{…})。${...}的作用和在文本区的是相同的。

例如:假设 user 是 Big Joe,

${"Hello ${user}!"}
${"${user}${user}${user}${user}"}

打印结果:

Hello Big Joe!
Big JoeBig JoeBig JoeBig Joe



也可以使用 + 达到类似的效果,这是比较老的方法,例如:

${"Hello " + user + "!"}
${user + user + user + user}



插值只能在文本区段(<h1>Hello ${name}!</h1>)和字符串文字(<#include "/footer/${company}.html">)中使用

获取一个字符

使用序列方式,例如:(假设 user 为 “Big Joe”)

${user[0]}
${user[4]}



打印出:

B
J

或者还可以使用内建函数(后续)。


序列操作

连接

使用 + 号进行:

<#list ["Joe", "Fred"] + ["Julia", "Kate"] as user>
- ${user}
</#list>


打印结果:

- Joe
- Fred
- Julia
- Kate



序列切分

使用

[firstindex..lastindex]

可以获取序列中的一部分,这里的firstindex和lastindex表达式的结果是数字。

如果seq存储序列"a", "b", "c", "d", "e", "f",那么表达式seq[1..4]将会是含有"b", "c", "d", "e"的序列。

lastindex可以被省略,那么这样将会读取到序列的末尾。如果seq存储序列"a", "b", "c", "d", "e", "f",那么seq[3..]将是含有"d", "e", "f"的序列。

如果试图访问一个序列首变量之前的项或末变量之后的项将会引起错误,模板的执行也会中断



哈希表操作

连接

像连接字符串那样,也可以使用+号的方式来连接哈希表。如果两个哈希表含有键相同的项,那么在+号右侧的哈希表中的项目优先

例如:

<#assign ages = {"Joe":23, "Fred":25} + {"Joe":30, "Julia":18}>
- Joe is ${ages.Joe}
- Fred is ${ages.Fred}
- Julia is ${ages.Julia}

打印出:

- Joe is 30
- Fred is 25
- Julia is 18




算数运算

+  -  *  /  %

例如:假设x为5

${100 – x*x}
${x/2}
${12%10}



打印出:

75
2.5
2


除 + 号外(+号可将数字转成字符),其他的运算符中非数字操作数将会导致FreeMarker错误。

有时我们只想获取计算结果的整数部分,这可以使用内建函数int来解决;例如:

${(x/2)?int}
${1.1?int}
${1.999?int}
${-1.1?int}
${-1.999?int}



打印出:

2
1
1
-1
-1



比较运算

相等 —— =

不相等 —— !=


逻辑运算

常用的逻辑操作符:

  • 逻辑或:||
  • 逻辑与:&&
  • 逻辑非:!

逻辑操作符仅仅在布尔值之间有效,若用在其他类型将会产生错误导致模板执行中止。


内建函数

内建函数以  ?  形式提供变量的不同形式或者其他信息。使用内建函数的语法和访问哈希表子变量的语法很像,除了使用?号来代替点,其他的都一样。

例如得到字符串的大写形式:user?upper_case。

在参考文档中可以查到所有内建函数的资料。

  • 字符串使用的内建函数:
  • html: 字符串中所有的特殊HTML字符都需要用实体引用来代替(比如<代替&lt;)。
  • cap_first:字符串的第一个字母变为大写形式
  • lower_case:字符串的小写形式
  • upper_case:字符串的大写形式
  • trim:去掉字符串首尾的空格
  • 序列使用的内建函数:
  • size:序列中元素的个数
  • 数字使用的内建函数:
  • int:数字的整数部分(比如-1.9?int就是-1)

例如,假设seasons存储了序列"winter", "spring", "summer", "autumn"

${seasons?size}
${seasons[1]?cap_first} <#-- left side can by any expression -->
${"horse"?cap_first}



打印出:

4
Spring
Horse



方法调用

可以使用方法调用操作来使用一个已经定义过的方法。方法调用的语法形式是使用逗号来分割在括号内的表达式而形成的参数列表,这些值就是参数。方法调用操作将这些值传递给方法,然后返回一个结果,这个结果就是整个方法调用表达式的值。

例如:

${repeat("What", 3)}



处理不存在的值

当访问一个不存在的变量时FreeMarker将会报错而导致模板执行中断。

模板语言中也没有null这个概念。

默认值

语法格式:

unsafe_expr!default_expr
或
unsafe_expr!
或
(unsafe_expr)!default_expr
或
(unsafe_expr)!



允许为不存在的变量指定一个默认值。默认值可以是任何类型的表达式,也可以不必是字符串。

例如:假设没有mouse变量

${mouse!"No mouse."}
<#assign mouse="Jerry">
${mouse!"No mouse."}



打印出:

No mouse.
Jerry




在不是顶层变量时,默认值操作符可以有两种使用方式

<ul><li><span style="font-family: Arial, Helvetica, sans-serif;">product.color!"red"</span></li></ul>


如果是这样的写法,那么在product中,当color不存在时(返回”red”)将会被处理,但是如果连produce都不存在时将不会处理。也就是说这样写时变量product必须存在,否则模板就会报错。

<ul><li><span style="font-family: Arial, Helvetica, sans-serif;">(product.color)!"red"</span></li></ul>


这时,如果当不存在时也会被处理,那就是说如果product不存在或者product存在而color不存在,都能显示默认值”red”而不会报错。本例和上例写法的重要区别在于用括号时,就允许其中表达式的任意部分可以未定义。


默认值也可以用于序列,例如:

<#assign seq = ['a', 'b']>
${seq[0]!'-'}
${seq[1]!'-'}
${seq[2]!'-'}
${seq[3]!'-'}

打印出:

a
b
-
-



检测不存在的值

语法格式:

unsafe_expr??
或
(unsafe_expr)??



结果是 true  或 false。


例如:

<#if mouse??>
Mouse found
<#else>
No mouse found
</#if>
Creating mouse...
<#assign mouse = "Jerry">
<#if mouse??>
Mouse found
<#else>
No mouse found
</#if>

打印出:

No mouse found
Creating mouse...
Mouse found




访问非顶层变量的使用规则和默认值操作符也是一样的,即product.color??和(product.color)?? 。


括号


表达式中的空格

FTL忽略表达式中的多余空格。



操作符优先级