xml 代码
- 1、快速入门
- (1)模板 + 数据模型 = 输出
- FreeMarker基于设计者和程序员是具有不同专业技能的不同个体的观念
- 他们是分工劳动的:设计者专注于表示——创建HTML文件、图片、Web页面的其它可视化方面;程序员创建系统,生成设计页面要显示的数据
- 经常会遇到的问题是:在Web页面(或其它类型的文档)中显示的信息在设计页面时是无效的,是基于动态数据的
- 在这里,你可以在HTML(或其它要输出的文本)中加入一些特定指令,FreeMarker会在输出页面给最终用户时,用适当的数据替代这些代码
- 下面是一个例子:
- <html>
- <head>
- <title>Welcome!title>
- head>
- <body>
- <h1>Welcome ${user}!h1>
- <p>Our latest product:
- <a href="${latestProduct.url}">${latestProduct.name}a>!
- body>
- html>
- 这个例子是在简单的HTML中加入了一些由${…}包围的特定代码,这些特定代码是FreeMarker的指令,而包含FreeMarker的指令的文件就称为模板(Template)
- 至于user、latestProduct.url和latestProduct.name来自于数据模型(data model)
- 数据模型由程序员编程来创建,向模板提供变化的信息,这些信息来自于数据库、文件,甚至于在程序中直接生成
- 模板设计者不关心数据从那儿来,只知道使用已经建立的数据模型
- 下面是一个可能的数据模型:
- (root)
- |
- +- user = "Big Joe"
- |
- +- latestProduct
- |
- +- url = "products/greenmouse.html"
- |
- +- name = "green mouse"
-
- 数据模型类似于计算机的文件系统,latestProduct可以看作是目录,而user、url和name看作是文件,url和name文件位于latestProduct目录中(这只是一个比喻,实际并不存在)
- 当FreeMarker将上面的数据模型合并到模板中,就创建了下面的输出:
- <html>
- <head>
- <title>Welcome!title>
- head>
- <body>
- <h1>Welcome Big Joe!h1>
- <p>Our latest product:
- <a href="products/greenmouse.html">green mousea>!
- body>
- html>
- (2)数据模型
- 典型的数据模型是树型结构,可以任意复杂和深层次,如下面的例子:
- (root)
- |
- +- animals
- | |
- | +- mouse
- | | |
- | | +- size = "small"
- | | |
- | | +- price = 50
- | |
- | +- elephant
- | | |
- | | +- size = "large"
- | | |
- | | +- price = 5000
- | |
- | +- python
- | |
- | +- size = "medium"
- | |
- | +- price = 4999
- |
- +- test = "It is a test"
- |
- +- whatnot
- |
- +- because = "don't know"
- 类似于目录的变量称为hashes,包含保存下级变量的唯一的查询名字
- 类似于文件的变量称为scalars,保存单值
- scalars保存的值有两种类型:字符串(用引号括起,可以是单引号或双引号)和数字(不要用引号将数字括起,这会作为字符串处理)
- 对scalars的访问从root开始,各部分用“.”分隔,如animals.mouse.price
- 另外一种变量是sequences,和hashes类似,只是不使用变量名字,而使用数字索引,如下面的例子:
- (root)
- |
- +- animals
- | |
- | +- (1st)
- | | |
- | | +- name = "mouse"
- | | |
- | | +- size = "small"
- | | |
- | | +- price = 50
- | |
- | +- (2nd)
- | | |
- | | +- name = "elephant"
- | | |
- | | +- size = "large"
- | | |
- | | +- price = 5000
- | |
- | +- (3rd)
- | |
- | +- name = "python"
- | |
- | +- size = "medium"
- | |
- | +- price = 4999
- |
- +- whatnot
- |
- +- fruits
- |
- +- (1st) = "orange"
- |
- +- (2nd) = "banana"
- 这种对scalars的访问使用索引,如animals[0].name
- (3)模板
- 在FreeMarker模板中可以包括下面三种特定部分:
- ${…}:称为interpolations,FreeMarker会在输出时用实际值进行替代
- FTL标记(FreeMarker模板语言标记):类似于HTML标记,为了与HTML标记区分,用#开始(有些以@开始,在后面叙述)
- 注释:包含在<#--和-->(而不是)之间
- 下面是一些使用指令的例子:
- if指令
- <#if animals.python.price < animals.elephant.price>
- Pythons are cheaper than elephants today.
- <#else>
- Pythons are not cheaper than elephants today.
- #if>
- list指令
- <p>We have these animals:
- <table border=1>
- <tr><th>Name<th>Price
- <#list animals as being>
- <tr><td>${being.name}<td>${being.price} Euros
- #list>
- table>
- 输出为:
- <p>We have these animals:
- <table border=1>
- <tr><th>Name<th>Price
- <tr><td>mouse<td>50 Euros
- <tr><td>elephant<td>5000 Euros
- <tr><td>python<td>4999 Euros
- table>
- include指令
- <html>
- <head>
- <title>Test pagetitle>
- head>
- <body>
- <h1>Test pageh1>
- <p>Blah blah...
- <#include "/copyright_footer.html">
- body>
- html>
- 一起使用指令
- <p>We have these animals:
- <table border=1>
- <tr><th>Name<th>Price
- <#list animals as being>
- <tr>
- <td>
- <#if being.size = "large"><b>#if>
- ${being.name}
- <#if being.size = "large">b>#if>
- <td>${being.price} Euros
- #list>
- table>
- 2、数据模型
- (1)基础
- 在快速入门中介绍了在模板中使用的三种基本对象类型:scalars、hashes 和sequences,其实还可以有其它更多的能力:
- scalars:存储单值
- hashes:充当其它对象的容器,每个都关联一个唯一的查询名字
- sequences:充当其它对象的容器,按次序访问
- 方法:通过传递的参数进行计算,以新对象返回结果
- 用户自定义FTL标记:宏和变换器
- 通常每个变量只具有上述的一种能力,但一个变量可以具有多个上述能力,如下面的例子:
- (root)
- |
- +- mouse = "Yerri"
- |
- +- age = 12
- |
- +- color = "brown">
- mouse既是scalars又是hashes,将上面的数据模型合并到下面的模板:
- ${mouse} <#-- use mouse as scalar -->
- ${mouse.age} <#-- use mouse as hash -->
- ${mouse.color} <#-- use mouse as hash -->
- 输出结果是:
- Yerri
- 12
- brown
- (2)Scalar变量
- Scalar变量存储单值,可以是:
- 字符串:简单文本,在模板中使用引号(单引号或双引号)括起
- 数字:在模板中直接使用数字值
- 日期:存储日期/时间相关的数据,可以是日期、时间或日期-时间(Timestamp);通常情况,日期值由程序员加到数据模型中,设计者只需要显示它们
- 布尔值:true或false,通常在<#if …>标记中使用
- (3)hashes 、sequences和集合
- 有些变量不包含任何可显示的内容,而是作为容器包含其它变量,者有两种类型:
- hashes:具有一个唯一的查询名字和它包含的每个变量相关联
- sequences:使用数字和它包含的每个变量相关联,索引值从0开始
- 集合变量通常类似sequences,除非无法访问它的大小和不能使用索引来获得它的子变量;集合可以看作只能由<#list …>指令使用的受限sequences
- (4)方法
- 方法变量通常是基于给出的参数计算值
- 下面的例子假设程序员已经将方法变量avg放到数据模型中,用来计算数字平均值:
- 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 python and elephant is: ${avg(animals.python.price, animals.elephant.price)}
- (5)宏和变换器
- 宏和变换器变量是用户自定义指令(自定义FTL标记),会在后面讲述这些高级特性
- (6)节点
- 节点变量表示为树型结构中的一个节点,通常在XML处理中使用,会在后面的专门章节中讲述
- 3、模板
- (1)整体结构
- 模板使用FTL(FreeMarker模板语言)编写,是下面各部分的一个组合:
- 文本:直接输出
- Interpolation:由${和},或#{和}来限定,计算值替代输出
- FTL标记:FreeMarker指令,和HTML标记类似,名字前加#予以区分,不会输出
- 注释:由<#--和-->限定,不会输出
- 下面是以一个具体模板例子:
- <html>[BR]
- <head>[BR]
- <title>Welcome!title>[BR]
- head>[BR]
- <body>[BR]
- <#-- Greet the user with his/her name -->[BR]
- <h1>Welcome ${user}!h1>[BR]
- <p>We have these animals:[BR]
- <ul>[BR]
- <#list animals as being>[BR]
- <li>${being.name} for ${being.price} Euros[BR]
- #list>[BR]
- ul>[BR]
- body>[BR]
- html>
- [BR]是用于换行的特殊字符序列
- 注意事项:
- FTL区分大小写,所以list是正确的FTL指令,而List不是;${name}和${NAME}是不同的
- Interpolation只能在文本中使用
- FTL标记不能位于另一个FTL标记内部,例如:
- <#if <#include 'foo'>='bar'>...if>
- 注释可以位于FTL标记和Interpolation内部,如下面的例子:
- <h1>Welcome ${user <#-- The name of user -->}!h1>[BR]
- <p>We have these animals:[BR]
- <ul>[BR]
- <#list <#-- some comment... --> animals as <#-- again... --> being>[BR]
- ...
- 多余的空白字符会在模板输出时移除
- (2)指令
- 在FreeMarker中,使用FTL标记引用指令
- 有三种FTL标记,这和HTML标记是类似的:
- 开始标记:<#directivename parameters>
- 结束标记:#directivename>
- 空内容指令标记:<#directivename parameters/>
- 有两种类型的指令:预定义指令和用户定义指令
- 用户定义指令要使用@替换#,如<@mydirective>...@mydirective>(会在后面讲述)
- FTL标记不能够交叉,而应该正确的嵌套,如下面的代码是错误的:
- <ul>
- <#list animals as being>
- <li>${being.name} for ${being.price} Euros
- <#if use = "Big Joe">
- (except for you)
- #list>
- #if><#-- WRONG! -->
- ul>
- 如果使用不存在的指令,FreeMarker不会使用模板输出,而是产生一个错误消息
- FreeMarker会忽略FTL标记中的空白字符,如下面的例子:
- <#list[BR]
- animals as[BR]
- being[BR]
- >[BR]
- ${being.name} for ${being.price} Euros[BR]
- #list >
- 但是,<、和指令之间不允许有空白字符
- (3)表达式
- 直接指定值
- 字符串
- 使用单引号或双引号限定
- 如果包含特殊字符需要转义,如下面的例子:
- ${"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: \
- 下面是支持的转义序列:
- 转义序列 含义
- \" 双引号(u0022)
- \' 单引号(u0027)
- \\ 反斜杠(u005C)
- \n 换行(u000A)
- \r Return (u000D)
- \t Tab (u0009)
- \b Backspace (u0008)
- \f Form feed (u000C)
- \l <
- \g >
- \a &
- \{ {
- \xCode 4位16进制Unicode代码
- 有一类特殊的字符串称为raw字符串,被认为是纯文本,其中的\和{等不具有特殊含义,该类字符串在引号前面加r,下面是一个例子:
- ${r"${foo}"}
- ${r"C:\foo\bar"}
- 输出的结果是:
- ${foo}
- C:\foo\bar
- 数字
- 直接输入,不需要引号
- 精度数字使用“.”分隔,不能使用分组符号
- 目前版本不支持科学计数法,所以“1E3”是错误的
- 不能省略小数点前面的0,所以“.5”是错误的
- 数字8、+8、08和8.00都是相同的
- 布尔值
- true和false,不使用引号
- 序列
- 由逗号分隔的子变量列表,由方括号限定,下面是一个例子:
- <#list ["winter", "spring", "summer", "autumn"] as x>
- ${x}
- #list>
- 输出的结果是:
- winter
- spring
- summer
- autumn
- 列表的项目是表达式,所以可以有下面的例子:
- [2 + 2, [1, 2, 3, 4], "whatnot"]
- 可以使用数字范围定义数字序列,例如2..5等同于[2, 3, 4, 5],但是更有效率,注意数字范围没有方括号
- 可以定义反递增的数字范围,如5..2
- 散列(hash)
- 由逗号分隔的键/值列表,由大括号限定,键和值之间用冒号分隔,下面是一个例子:
- {"name":"green mouse", "price":150}
- 键和值都是表达式,但是键必须是字符串
- 获取变量
- 顶层变量: ${variable},变量名只能是字母、数字、下划线、$、@和#的组合,且不能以数字开头
- 从散列中获取数据
- 可以使用点语法或方括号语法,假设有下面的数据模型:
- (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"]
- 使用点语法,变量名字有顶层变量一样的限制,但方括号语法没有该限制,因为名字是任意表达式的结果
- 从序列获得数据:和散列的方括号语法语法一样,只是方括号中的表达式值必须是数字;注意:第一个项目的索引是0
- 序列片断:使用[startIndex..endIndex]语法,从序列中获得序列片断(也是序列);startIndex和endIndex是结果为数字的表达式
- 特殊变量:FreeMarker内定义变量,使用.variablename语法访问
- 字符串操作
- Interpolation(或连接操作)
- 可以使用${..}(或#{..})在文本部分插入表达式的值,例如:
- ${"Hello ${user}!"}
- ${"${user}${user}${user}${user}"}
- 可以使用+操作符获得同样的结果
- ${"Hello " + user + "!"}
- ${user + user + user + user}
- ${..}只能用于文本部分,下面的代码是错误的:
- <#if ${isBig}>Wow!#if>
- <#if "${isBig}">Wow!#if>
- 应该写成:
- <#if isBig>Wow!#if>
- 子串
- 例子(假设user的值为“Big Joe”):
- ${user[0]}${user[4]}
- ${user[1..4]}
- 结果是(注意第一个字符的索引是0):
- BJ
- ig J
- 序列操作
- 连接操作:和字符串一样,使用+,下面是一个例子:
- <#list ["Joe", "Fred"] + ["Julia", "Kate"] as user>
- - ${user}
- #list>
- 输出结果是:
- - Joe
- - Fred
- - Julia
- - Kate
- 散列操作
- 连接操作:和字符串一样,使用+,如果具有相同的key,右边的值替代左边的值,例如:
- <#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 * x - 100}
- ${x / 2}
- ${12 % 10}
- 输出结果是(假设x为5):
- -75
- 2.5
- 2
- 操作符两边必须是数字,因此下面的代码是错误的:
- ${3 * "5"}