概要
<#escape identifier as expression>
...
<#noescape>...</#noescape>
...
</#escape>
描述
当你使用escape指令包围模板中的一部分时,在块中出现的插值
(${...})
会和转义表达式自动结合。这是一个避免编写相似表达式的很方便的方法。
它不会影响在字符串形式的插值(比如在 <#assign x =
"Hello ${user}!">)。而且,它也不会影响数值插值
(#{...})。
例如:
<#escape x as x?html>
First name: ${firstName}
Last name: ${lastName}
Maiden name: ${maidenName}
</#escape>事实上它等同于:
First name: ${firstName?html}
Last name: ${lastName?html}
Maiden name: ${maidenName?html}请注意,它和你在指令中用什么样的标识符无关 - 它仅仅是作为一个转义表达式的正式参数。
当在调用宏或者 include 指令时,
理解 在模板文本 中转义仅仅对出现在 <#escape
...> 和
</#escape> 中的插值起作用是很重要的。
也就是说,它不会转义文本中
<#escape ...>
之前的东西或 </#escape> 之后的东西,
也不会从 escape 的部分中来调用。
<#assign x = "<test>">
<#macro m1>
m1: ${x}
</#macro>
<#escape x as x?html>
<#macro m2>m2: ${x}</#macro>
${x}
<@m1/>
</#escape>
${x}
<@m2/>将会输出:
<test> m1: <test> <test> m2: <test>
从更深的技术上说,
escape 指令的作用是用在模板解析的时间而不是模板处理的时间。
这就表示如果你调用一个宏或从一个转义块中包含另外一个模板,
它不会影响在宏/被包含模板中的插值,因为宏调用和模板包含被算在模板处理时间。
另外一方面,如果你用一个转义区块包围一个或多个宏声明(算在模板解析时间,和宏调用想法),
那么那些宏中的插值将会和转义表达式合并。
有时需要暂时为一个或两个在转义区块中的插值关闭转义。你可以通过关闭, 过后再重新开启转义区块来达到这个功能,但是那么你不得不编写两遍转义表达式。 你可以使用非转义指令来替代:
<#escape x as x?html>
From: ${mailMessage.From}
Subject: ${mailMessage.Subject}
<#noescape>Message: ${mailMessage.htmlFormattedBody}</#noescape>
...
</#escape>和这个是等同的:
From: ${mailMessage.From?html}
Subject: ${mailMessage.Subject?html}
Message: ${mailMessage.htmlFormattedBody}
...转义可以被嵌套(尽管你不会在罕见的情况下来做)。
因此,你可以编写如下面代码(这个例子固然是有点伸展的,
正如你可能会使用 list 来迭代序列中的每一项,
但是我们现在所做的是阐述这个观点)的东西:
<#escape x as x?html>
Customer Name: ${customerName}
Items to ship:
<#escape x as itemCodeToNameMap[x]>
${itemCode1}
${itemCode2}
${itemCode3}
${itemCode4}
</#escape>
</#escape>实际上和下面是等同的:
Customer Name: ${customerName?html}
Items to ship:
${itemCodeToNameMap[itemCode1]?html}
${itemCodeToNameMap[itemCode2]?html}
${itemCodeToNameMap[itemCode3]?html}
${itemCodeToNameMap[itemCode4]?html}当你在嵌入的转义区块内使用非转义指令时,它仅仅不处理一个单独层级的转义。 因此,为了在两级深的转义区块内完全关闭转义,你需要使用两个嵌套的非转义指令。