3.4 Escaping VTL elements

Most of the time, there is no problem, rendering a Velocity template because the rendering engine is quite smart about finding Velocity statements and references and distinguishing them from regular text.

Example 3.9. Distinguishing between text and references

## Renders as normal text, because the dollar sign 
## is not followed by a letter.
I bought a 4 lb. sack of potatoes for only $2.50!

## Renders as variable
I bought a 4 lb. sack of potatoes for only $money.

Velocity allows for explicit escaping of references and directives using the \ (backslash) character. If the character following the \ would start a new directive or reference, then this character is output verbatim. This can lead to some unexpected behaviour, especially with directives.

Example 3.10. VTL escaping examples

\         ## Renders as a single backslash (no # or $ follows)

\\ \# \$  ## Renders as \\ \# \$ (no directive or reference follows)

\#end     ## Renders as #end, backslash escapes an existing directive

Unfortunately, the escaping of VTL elements contains a number of quirks that make them actually hard to use[2]. As you have seen, the behaviour of the \ differs whether a directive or just text follows:

Example 3.11. Escaping VTL references

$a     ## $a is a reference but an unbound one (it has no value)
       ## This renders as $a in the output

\$a    ## Escaping an unbound reference renders it as \$a

#set($a = 10)  ## When a value is assigned to the reference...

$a     ## ... then it renders as 10 ...

\$a    ## ... and gets escaped and now renders as $a.

Escaping VTL statements works in the same way.

Example 3.12. Escaping VTL statements

\#end    ## Renders as #end
\# end   ## Renders as \# end (note the space)

\#set ($a = 10) ## Renders as #set ($a = 10)

## If $a has been assigned a value:

#set ($a = 10)
\#set ($a = 20) ## Renders as #set (10 = 20)

## The backslash does not escape a whole multi-line statement
## This is a syntax error: (#end without a starting statement)
\#if ($a == 10)
#end

Using Velocity Macros, the behaviour of escaping # changes a bit:[3]

Example 3.13. Escaping Velocimacros

#apple    ## Renders as #apple, because it is not a VTL
          ## statement
\#apple   ## Renders as \#apple

#macro(apple)
 Apple
#end

#apple    ## This is now a syntax error
          ## (#apple Velocimacro invocation needs brackets)

#apple()  ## Renders as Apple (invocation of a Velocimacro)

\#apple   ## renders as #apple, because it is now a VTL
          ## statement after Velocimacro definition.



[2] It is really mind-boggling how we came up with this. It is tied more to the internal workings of the Velocity engine than any user-friendlyness. This is definitely subject to change in future Velocity versions. Until then, please be kind to our mistakes.

[3] ...and you probably thought, the worst part was over...