escape, noescape (deprecated)

Synopsis

<#escape identifier as expression>
  ...
  <#noescape>...</#noescape>
  ...
</#escape>

Camel case name variant: noEscape

Description

Note:

These directives are deprecated by output-format-based auto-escaping since 2.3.24. Furthermore, on places that use auto-escaping (with an output format that actually does escaping) you aren't allowed to use the escape directive (as you will find out from the parsing error message anyway).

When you surround a part of the template with an escape directive, interpolations (${...}) that occur inside the block are combined with the escaping expression automatically. This is a convenience method for avoiding writing similar expressions all over. It does not affect interpolations in string literals (as in <#assign x = "Hello ${user}!">). Also, it does not affect numerical interpolations (#{...}).

Example:

Template
<#escape x as x?html>
  First name: ${firstName}
  Last name: ${lastName}
  Maiden name: ${maidenName}
</#escape>

is actually equivalent to:

Template
  First name: ${firstName?html}
  Last name: ${lastName?html}
  Maiden name: ${maidenName?html}

Note that it is irrelevant what identifier you use in the directive - it just serves as a formal parameter to the escaping expression.

When you are calling macros or the include directive, it is important to understand that escape has effect only on interpolations that occur between the <#escape ...> and </#escape> in the template text. That is, it will not escape anything that is before <#escape ...> in the text, or after the </#escape> in the text, not even if that part is called from inside the escape-d section.

Template
<#assign x = "<test>">
<#macro m1>
  m1: ${x}
</#macro>
<#escape x as x?html>
  <#macro m2>m2: ${x}</#macro>
  ${x}
  <@m1/>
</#escape>
${x}
<@m2/>

the output will be:

Output
  &lt;test&gt;
  m1: <test>
<test>
m2: &lt;test&gt;

More technically, the effects of escape directive are applied at template parsing time rather than at template processing time. This means that if you call a macro or include another template from within an escape block, it won't affect the interpolations in the macro/included template, since macro calls and template includes are evaluated at template processing time. On the other hand, if you surround one or more macro declarations (which are evaluated at template parsing time, as opposed to macro calls) with an escape block, the interpolations in those macros will be combined with the escaping expression.

Sometimes there is a need to temporarily turn off escaping for one or two interpolations in an escape block. You can achieve this by closing and later reopening the escape block, but then you have to write the escaping expression twice. You can instead use the noescape directive:

Template
<#escape x as x?html>
  From: ${mailMessage.From}
  Subject: ${mailMessage.Subject}
  <#noescape>Message: ${mailMessage.htmlFormattedBody}</#noescape>
  ...
</#escape>

is equivalent to:

Template
  From: ${mailMessage.From?html}
  Subject: ${mailMessage.Subject?html}
  Message: ${mailMessage.htmlFormattedBody}
  ...

Escapes can be nested (although you will do it only in rare circumstances). Therefore, you can write something like the below code (the example is admittedly a bit stretched, as you'd probably place item codes in a sequence and use list to iterate over them, but we're now doing it this way just to illustrate the point):

Template
<#escape x as x?html>
  Customer Name: ${customerName}
  Items to ship:
  <#escape x as itemCodeToNameMap[x]>
    ${itemCode1}
    ${itemCode2}
    ${itemCode3}
    ${itemCode4}
  </#escape>
</#escape>

is actually equivalent to:

Template
  Customer Name: ${customerName?html}
  Items to ship:
    ${itemCodeToNameMap[itemCode1]?html}
    ${itemCodeToNameMap[itemCode2]?html}
    ${itemCodeToNameMap[itemCode3]?html}
    ${itemCodeToNameMap[itemCode4]?html}

When you use the noescape directive in a nested escape block, it undoes only a single level of escaping. Therefore, to completely turn off escaping in a two-level deep escaped block, you need to use two nested noescape directives as well.