Velocity directives

A directive is a Velocity keyword starting by a "#", for example "#set", "#if", "#foreach", etc.

Directives can be thought of as "instructions" for handling rendering in a model. They can be used to define variables (#set), apply logical conditions (#if), iterate over collections (#foreach), etc.

#set( $name = "Bob" )
#foreach( $v in $elements )
 $v
#end

To avoid misinterpretations the name of the directive can be bracketed with "{" and "}"

#if($x)true#{else}false#end

Most used directives

#set

The #set directive is used for setting a value. A value can be assigned to either a simple variable or an object property. "#set" always defines a "global variable" wherever you use it.

#set( $name = "Bob" )
#set( $customer.name = "Bob")
#set( $user.level = 3 ) ## number literal
#set( $a = $b ) ## variable reference
#set( $mylist = [ "A", $v, "Z"] ) ## list

You cannot set a variable to "null" explicitly

#set( $v = null ) ## causes an error

NB : if the value to be assigned is null then it will not be assigned!

#set( $v = $o.get("abc") ) 
## if get returns null then $v remains unchanged

#foreach / #end

The "#foreach" directive is used to loop through a list of objects. Within the "#foreach" directive 2 local variables are created to represent : - the current item in the loop (you can name it as you want) - the "$foreach" object providing properties like "count", "index", "hasNext", "first", "last", "parent", "topmost". The visibility of these variables is only "local" (visible only in the "#foreach" block). A variable defined with "#set" inside a "#foreach" block remains global (visible outside of the block). The "$foreach" object is an instance of org.apache.velocity.runtime.directive.ForeachScope.

Examples :

Loop with given values :

#foreach ( $item in [1..8] ) ## from 1 to 8
 . item = $item 
#end

#foreach ( $item in [3,2,1] ) ## from 3 to 1
 . item = $item 
#end

## Everything in a single line
#foreach( $item in ['A','B','C','D'] ) ${item}#end

Loop with an object (array, list, collection) :

#foreach( $attribute in $entity.attributes )
 $attribute.type $attribute.name
#end

Map iteration :

#set ( $map = {"banana" : "good", "cream" : "bad"} ) 
#foreach($key in $map.keySet() )
 $key --> $map.get($key)
#end

Break the current iteration :

#foreach ( $item in [1..20] )
#if ( $item > 3 ) #break #end
 . item = $item 
#end

"$foreach.count" loop counter ( 1 to N ) :

#foreach ( $item in ["A", "B", "C", "D" ] ) 
 . $foreach.count : $item 
#end

"$foreach.index" zero-based index ( 0 to N-1 ) :

#foreach ( $item in ["A", "B", "C", "D" ] ) 
 . $foreach.index : $item 
#end

"$foreach.hasNext" ( true if not last item ) :

#foreach( $customer in $customerList )
  $customer.Name#if( $foreach.hasNext ),#end
#end

Nested loops :

It's possible to access outer loops properties by using "$foreach.parent" or "$foreach.topmost" (e.g. $foreach.parent.index or $foreach.topmost.hasNext).

#foreach ( $item1 in ["A", "B", "C", "D" ] ) 
#foreach ( $item2 in [1,2,3 ] )
 . $foreach.index : $item1 / $item2  
   ($foreach.parent.index) ($foreach.topmost.index)
#end 
#end

#if / #else / #elseif / #end

Conditional output or instructions

Examples :

#if / #end :

 #if ( $v == 1 ) equals 1 #end 

 #if ( $v == 1 ) 
 equals 1 
 #end 

#if / #else / #end :

 #if ( $v == 1 ) equals 1 #else not equals 1 #end 

 #if ( $v == 1 ) 
 equals 1 
 #else 
 not equals 1 
 #end 

#if / #elseif / #else / #end :

 #if ( $v == 1 ) 
 equals 1 
 #elseif ( $v == 2 ) 
 equals 2 
 #else 
 other 
 #end 

#include

The #include directive allows to import a local file at the current position. The file is included "as is" (as a text file, not rendered through the template engine, not parsed). If more than one file will be included, they should be separated by commas. A variable can be used instead of a literal filename. Any files to which #include refers must be included under "TEMPLATE_ROOT" ( the "bundle" directory for Telosys ).

Examples :

## Include a single file :
#include( "myfile.txt" )
#include( "include/myfile.txt" ) 

## Include multiple files :
#include( "a.txt", "b.html" )

## Include with variables :
#include( $myfile )
#include( "header.include", $myfile ) 

#parse

The #parse directive allows to import a local Velocity template file. The file is parsed by the Velocity engine. Only one argument is accepted (only one file for each call, other arguments are ignored). A variable can be used instead of the literal filename. All the variables defined before the "#parse" call are usable in the parsed file. All the variables defined in the parsed file are usable in the primary file after the "#parse" call. Any templates to which #parse refers must be included under "TEMPLATE_ROOT" ( the "bundle" directory for Telosys ).

Examples :

#parse("foo.vm")
#parse($myfile)
#parse("include/initvar.vm")
## Here we can use variables defined in "initvar.vm"

#parse can be used inside "parsed files". Recursion is permitted (with a condition to stop recursion).

Primary file :

#set( $count = 8 )
#parse( "foo.vm" )

"foo.vm" file with recursive "parse" :

#set( $count = $count - 1 )
#if( $count > 0 )
  #parse( "foo.vm" )
#else
  End of recursion.
#end

Other directives

#stop

The #stop directive stops any further rendering and execution of the template. This is true even when the directive is nested within another template accessed through #parse or located in a velocity macro.

The resulting output will contain all the content up to the point the #stop directive was encountered. This is handy as an early exit from a template.

Example :

#if ( $v == 12 ) 
#stop 
#end 

#break

The #break directive stops any further rendering of the current "execution scope". An "execution scope" can be - a directive with content : #foreach, #parse, #evaluate, #define, #macro, or #@somebodymacro - the current template ("root scope"). Unlike #stop, #break will only stop the innermost, immediate scope, not all of them.

Examples :

## BREAK at template level (stop template rendering)
#break

## BREAK in a single loop
#set($mylist = ["A", "B", "C", "D", "E", "F" ])
#foreach( $v in $mylist )
#if( $foreach.count > 3 ) 
  #break
#end
$foreach.count : $v

## BREAK in a nested loop (break innermost)
#set($mylist1 = ["A", "B", "C", "D", "E", "F" ])
#set($mylist2 = [1, 2, 3, 4, 5, 6 ])
#foreach( $v1 in $mylist1 )
#foreach( $v2 in $mylist2 )
#if( $foreach.count > 3 )#break
#end
$foreach.parent.count : $v1 / $foreach.count : $v2
#end
#end

#evaluate

The #evaluate directive can be used to dynamically evaluate a statement (piece of Velocity code). This allows to evaluate a string that is created dynamically at render time. '#evalute' works like '#parse' but with content that comes from a variable in memory instead of a file (it's possible to evaluate multiple lines).

Examples :

#set($v = 2)
#set($statement = '#set($r = $v * 10)' )
#evaluate($statement)
v : $v 
statement : $statement
r : $r ## r : 20

#macro

Velocity "macros" allow you to define a portion of VTL code which will then be reusable several times. They are often called "Velocimacro".

Example : basic macro (without argument)

#macro( three )
#set ( $result = "" )
#foreach ( $i in [1..3] ) ${i}#end
#end
## -------
#three() 

Arguments : A Velocimacro can take any number of arguments (0 to N arguments). When the Velocimacro is invoked, it must be called with the same number of arguments with which it was defined. Each argument is a local variable and can never be used outside.

Example : macro with 2 arguments

#macro( add $a1 $a2 )
#set ( $r = $a1 + $a2 )
$a1 + $a2 = $r 
#end
## -------
#add( 20, 3 )
## rendering : 20 + 3 = 23

NB : Macros are not functions, they are designed to render and they cannot return a value. But you can simulate a "return value" by setting a variable in the macro and using it after calling the macro or by setting the result as a string.

Example : "Function like call" getting the result as text (with quotes)

#macro( add3 $a1 $a2 $a3 )
#set ( $r = $a1 + $a2 + $a3)
$r## NO EOL
#end
## -------
#set($v = 50)
#set( $result = "#add3(10,20,$v)" )
result : $result

#define

The #define directive allows to assign a block of code to a variable. The associated block of code can contain any valid code.

The code associated with a variable by #define is executed when the variable is referenced.

The type of the variable created by #define is org.apache.velocity.runtime.directive.Block$Reference

Example :

#define( $block )Hello $who#end
#set( $who = 'World!' )
$block

Differences between "#define" and "#macro" : " - #macro" accepts parameters so that they provide a context for creation of local variables - "#define" structure (unless it contains macros) only works with global variables

Last updated