escape, noescape
概要
<#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}
当你在嵌入的转义区块内使用非转义指令时,它仅仅不处理一个单独层级的转义。 因此,为了在两级深的转义区块内完全关闭转义,你需要使用两个嵌套的非转义指令。