The types

Page Contents

支持的类型为:

Scalars

这些是基本的简单值。他们可以:

  • 字符串:这是简单的文本,例如产品名称。

如果您想直接在模板中提供字符串值,而不是使用数据模型中的变量,则可以在引号之间 Importing 文本,例如"green mouse"'green mouse'。 (有关语法的更多详细信息,请参见later。)

  • 数字:例如产品的价格。不区分整数和非整数;只有一个数字类型。因此,例如 3/2 将始终为 1.5,而永远不会为 1.就像使用计算器一样。

如果要直接在模板中提供数值,则可以编写例如150-90.050.001。 (有关语法的更多详细信息,请参见later。)

  • 布尔值:布尔值代表逻辑上的是或否(是或否)。例如,如果访客已经登录或未登录。通常,您将布尔值用作if指令的条件,例如<#if loggedIn >...</#if><#if price == 0>...</#if>;在最后一种情况下,price == 0部分的结果为布尔值。

在模板中,您可以直接使用保留字truefalse指定一个布尔值。

  • 日期:类似日期的值,用于存储与日期/时间相关的数据。它具有三个变体:

  • 日期:类似于 2003 年 4 月 4 日。日精度,无时间部分。

    • 时间:像晚上 10:19:18.毫秒精度,无日期部分。

    • 日期时间(有时称为“时间戳记”)为 2003 年 4 月 4 日晚上 10:19:18.日期和时间都以毫秒为单位。

不幸的是,由于 Java 平台的局限性,FreeMarker 有时无法确定使用日期的哪一部分(即,日期时间,日期还是时间)。该问题的解决方案是一个高级主题,将在later上进行讨论。

可以直接在模板中定义类似日期的值,但这是一个高级主题,将在later中进行说明。

请记住,FreeMarker 可以将字符串与数字,布尔值和类似日期的值区分开。例如,虽然字符串"150"看起来像数字150,但是字符串仍然只是任意字符序列,您无法对其进行算术运算,无法将其与其他数字进行比较,等等。

Containers

这些值的目的是包含其他变量。他们只是容器。包含的变量通常称为* sub 变量*。容器类型为:

  • 哈希:将唯一的查询名称与其每个子变量关联。名称是不受限制的字符串。哈希并未为其中的子变量定义排序。也就是说,没有第一个子变量和第二个子变量等。仅通过名称访问变量。

  • 序列:将整数与其每个子变量关联。第一个子变量与 0 相关联,第二个与 1 相关联,第三个与 2 相关联,依此类推;子变量是有序的。这些数字通常称为子变量的“索引”。序列通常是密集的,即直到最后一个子变量的索引的所有索引都具有关联的子变量,但这不是严格必要的。子变量值的类型不必相同。

  • 集合:从模板作者的角度来看,集合是受限制的序列。您无法访问其大小或按索引检索其子变量,但它们仍可以与list directive一起列出。此外,通常只能列出一次。 (如果您是 Java 程序员,则“可迭代”将比集合更合适.)

请注意,由于一个值可以有多种类型,因此值既可以是哈希也可以是序列,在这种情况下,它将支持基于索引的访问以及按查找名称的访问。但是,通常,容器将是哈希或序列,而不是两者。

由于存储在哈希和序列(和集合)中的变量的值可以是任何值,因此它也可以是哈希或序列(或集合)。这样,您可以构建任意深的结构。

数据模型本身(或者最好说它的根)是一个哈希。

FreeMarker 模板不支持修改容器的内容(例如添加,删除或替换子变量),并且假定其内容在模板处理期间不会更改。 (但是您可以通过使用+将两个现有容器值相加来创建新的容器值;请参见关于表达式的章节中的内容,并请注意性能后果。)

Subroutines

方法和功能

作为方法或函数的值将用于计算另一个值,该值受提供给它的参数的影响。

对于程序员类型:方法/函数是一等值,就像在函数式编程语言中一样。这意味着函数/方法可以是其他函数/方法的参数或返回值,您可以将它们分配给变量,依此类推。

假定程序员已将方法变量avg放入可用于计算数字平均值的数据模型中。如果在访问avg时将 3 和 5 作为参数,则将得到值 4.

方法的用法将在later处进行解释,但也许此示例有助于了解什么是方法:

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 directive-一个高级主题),但是两者可以在同一模板上使用方式。

User-defined directives

此类型的值可用作用户定义的指令(换句话说,用作 FreeMarker 标记)。用户定义的指令是一个子例程,类似于一些可重用的模板片段。但这是一个高级主题,将在其自己的章节中later1 进行说明。

对于程序员类型:用户定义的指令(例如宏)也像函数/方法一样,也是一等值。

只是为了了解用户定义的指令(如果您不理解,请忽略此内容),假设我们有一个变量box,其值是用户定义的指令,该指令会打印出一些带有样式的精美 HTML 消息框标题栏和其中的消息。可以在模板中使用box变量,例如:

<@box title="Attention!">
  Too much copy-pasting may leads to
  maintenance headaches.
</@box>

函数/方法与用户定义的指令

再次适用于高级用户(如果您不了解,请忽略它)。如果您应该使用函数/方法或用户定义的指令来实现某些功能,则经常会遇到两难境地。经验法则是:如果满足以下条件,则将设施作为用户定义的指令而不是函数/方法来实现。

  • ...的目的是生成一部分输出,而不仅仅是单个值,并且通常涉及标记。模板语言被设计为直接通过_循环,if -s 等逐段直接打印到输出。在变量中构建字符串值然后返回它非常不方便。

  • ……重要的是副作用,而不是返回值。例如,旨在将条目添加到服务器日志的指令就是这样。 (实际上,您无法为用户定义的指令提供返回值,但是通过设置非局部变量仍然可以进行某种反馈.)

  • ...它将在调用方进行流控制(例如listif指令一样)。您只是无法使用函数/方法来做到这一点。

  • ...您正在通过escape指令(而不是auto-escaping)使用旧式转义,并且结果包含标记。当您使用${...}打印结果时,标记将被转义并因此被破坏,但是如果通过指令调用(<@...>)打印,则不会。

不考虑 FreeMarker 的 Java 对象的 Java 方法通常作为模板中的方法可见,而与 Java 方法的性质无关。您别无选择。

Miscellaneous

Nodes

节点变量表示树结构中的节点,并且通常与XML processing一起使用,这是一个高级且专门的主题。

尽管如此,快速概述适用于高级用户*:一个节点类似于存储其他节点的序列,这些节点通常被称为子节点。节点存储对其容器节点的引用,该引用通常称为父节点。成为节点的要点是拓扑信息。必须利用一个值可以具有多种类型来存储其他数据。同样,值可以是节点,也可以是数字,在这种情况下,它可以将数字存储为“有效负载”。除了拓扑信息之外,节点还可以存储一些元信息:节点名称,节点类型(字符串)和节点名称空间(字符串)。例如,如果节点在 XHTML 文档中表示h1元素,则其名称可以为"h1",其节点类型可以为"element",并且其名称空间可以为"http://www.w3.org/1999/xhtml"。但是,这些元信息的含义是什么,以及是否使用它们,完全取决于数据模型的设计者。 在下一章中描述了检索拓扑和元信息的方法(此时您无需了解)。

Markup output

此类型与auto-escaping mechanism FreeMarker 2.3.24 引入的有关;您可以在这里阅读有关此类型的信息。简而言之,这是一个值,用于存储已经采用输出标记格式的文本(例如 HTML,XML,RTF 等),因此不能自动转义。

这种类型的值通常在模板内部生成(例如no_esc built-in输出捕获分配),但也可以是数据模型的一部分。数据模型中的此类值很有用,例如,如果您的消息资源有时包含 HTML 格式而不是纯文本格式的消息。如果数据模型对这些消息而不是字符串使用 HTML 标记输出值,则模板作者不必知道哪些消息包含 HTML 和哪些纯文本,因为当使用${...}插入消息时,将自动避免两次转义。