Directive Reference

assign

<#assign name=value>
or
<#assign name1=value1 name2=value2 ... nameN=valueN>
or
<#assign same as above... in namespacehash>
or
<#assign name>
  capture this
</#assign>
or
<#assign name in namespacehash>
  capture this
</#assign>

Parameter

Description

name

The name of the variable.
This is not an expression. However, it can be written as a string literal. This can be useful if the variable name contains reserved characters, for example <#assign "foo-bar" = 1>. Note that this string literal does not expand interpolations (as "${foo}").

value

The value to store. This is an expression.

namespacehash

A hash that was created for a namespace (by import). This is an expression.

 

Use this directive to create a new variable or replace an existing variable. Note that you can create and replace only top-level variables (i.e. you cannot create/replace some_hash.subvar, only some_hash).

Example: Create a variable called seasons that stores a sequence:

<#assign seasons = ["winter", "spring", "summer", "autumn"]>  

Example: Increment the numerical value stored in variable called test:

<#assign test = test + 1>  

As a convenience feature, you can do more assignments with one assign tag. The following example does the same as the two previous examples:

<#assign
  seasons = ["winter", "spring", "summer", "autumn"]
  test = test + 1

You can use this directive to create variables in namespaces. Normally, the directive creates the variable in the current namespace. However, if you use namespacehash, you can create/replace a variable in another namespace. For example, the following code creates/replaces a variable called bgColor in the namespace used for /contentlibrary/mylib.htm:

<#import "/contentlibrary/mylib.htm" as my>
<#assign bgColor="red" in my>  

You can also use this directive to capture the output generated between its start and end tags. That is, everything printed between the tags will not be shown on the page, but will be stored in the variable. For example:

<#macro myMacro>foo</#macro>
<#assign x>
  <#list 1..3 as n>
    ${n} <@myMacro />
  </#list>
</#assign>
Number of words: ${x?word_list?size}
${x}  

produces this output:

Number of words: 6
    1 foo
    2 foo
    3 foo

IMPORTANT: Do not to use the following to insert variables into strings:
<#assign x>Hello ${user}!</#assign> <#-- BAD PRACTICE! -->
Instead, use:
<#assign x="Hello ${user}!">

attempt, recover

<#attempt>
  attempt block
<#recover>
  recover block
</#attempt>

Parameter

Description

attempt block

Template block with any content. This will be always executed, but if an error occurs during execution, all output from this block is rolled back, and the recover block will be executed.

recover block

This parameter is required.

Template block with any content. This will be executed only if an error occurs during the execution of the attempt block. You can use the recover block, for example, to print an error message.

attempt and recover can be nested into other attempt blocks or recover blocks.

Use these directives to successfully output the page when execution of a part of the page fails. If an error occurs during the execution of the attempt block, all output from this block is rolled back, and the recover block is executed. If no error occurs during the execution of the attempt block, the recover block is ignored.

For example:

Primary content
<#attempt>
  Optional content: ${missinghash.thisMayFails}
<#recover>
  Ops! The optional content is not available.
</#attempt>
Primary content continued  

if thisMayFails variable does not exist, the output is:

Primary content
  Ops! The optional content is not available.
Primary content continued  

if thisMayFails variable exists and its value is 123, the output is:

Primary content
  Optional content: 123
Primary content continued  

The attempt block is either printed in its entirety (if there is no error) or not at all (if an error occurs). In other words, if an error occurs anywhere within the block, error-free parts will not be printed. This is implemented with the aggressive buffering of the output inside the attempt block. Not even the flush directive will send the output to the client.

To prevent misinterpretation, do not use attempt/recover for handling undefined variables (instead, use missing value handler operators). It can handle all types of errors that occur when the block is executed except syntactical errors, which are detected earlier. These directives are meant to enclose bigger template fragments, where errors can occur at various points. For example, a section of your template prints ads, but that is not the primary content of the page. In this case, you can put the ad printing section in the attempt block so that the rest of the page will print if an error occurs when printing ads.

A error message is available inside the recover block with the .error special variable (references to special variable begin with a dot (for example: ${.error}).

Errors occurring during template execution are always logged, even if they occur inside the attempt block.

compress

<#compress>
  ...
</#compress>

This directive is useful for removing superfluous white space when you use a white space-insensitive format (e.g. HTML or XML).

The directive captures the output generated between its start and end tags, and reduces all unbroken white space sequences to a single white space character. If the replaced sequence contains line breaks, the inserted character is a line break. Otherwise, the inserted character a space. The very first and very last unbroken white space sequences are removed.

Example:

<#assign x = "    moo  \n\n   ">
(<#compress>
  1 2  3   4    5
  ${moo}
  test only
 
  I said, test only
 
</#compress>)  

produces this output:

 (1 2 3 4 5
moo
test only
I said, test only)  

content, filter, break

<#content datasource as hash-name option=value-expr ...>
  <#filter key1 operator value-expr1 [&& key2 operator value-expr2] ...>
  ...
</#content>

Content

Parameter

Description

datasource

The name of the datasource alias, as defined in the Campaign Workbook. 

Not an expression. 

Note that this is an alial of the datasource, not its name.

hash-name

The name of the structure that can be used in the enumeration of records.

The hash name will be used to obtain the values for each of the resulting values. It will also be used as a prefix to the special variables that start with the hash name and have a suffix of _index, and _has_next.

option

It can be:

limit=numeric-expression

Limits the number of records returned from the execution of the expression. If the limit is greater than the existing number of records, it is ignored. The numeric expression is any expression that returns a number, including any numeric constants.  Non-integer numbers get rounded off.

IMPORTANT: An account has a maximum allowable number of rows (default is 20); providing a limit bigger than that number produces an error.

Filter

Parameter

Description

key1, key2, …

The alias names of the columns to be used to perform the filter, as defined in the Datasources tab of the Campaign Workbook.

Not an expression. 

operator

Either one of the following:

=, ==     
Equals operation

gte     
greater than or equals to

gt     
greater than

lte, <=     
less than or equals to

lt, <     
less than

value-expr-1, value-expr-2, …

The values to use to search for data. 

Can be expressions according to the data type in the datasource. 

WARNING: Template execution will fail if the wrong types are provided. Ask the campaign designer for the proper types.

&&, &

Represents the “and” operator.

Must be used between (key, operator, value) sets.

This directive searches content in an optimized fashion, applying the supplied predicates (expression set). The directive creates a hash, which is used in the body of the directive to retrieve and output the content by field name. The hash name is given in the content directive, while the predicates are given in the filter directive.

Unlike the data directive, this directive is optimized to retrieve content only as needed. For instance, if an audience of a million records is launched and there are only a thousand variants of the content, Oracle Responsys internally caches and keeps the data for future requests in an efficient manner. It also deals with images in the content by changing paths so that the files can be accessible from the Internet.

Two special loop variables are available inside the data loop:

hash-name_index
This is a numerical value that contains the index of the current item being stepped over in the loop.

hash-name_has_next
Boolean value that tells if the current item the last in the datasource query or not.

You can use the break instruction inside the loop body to exit the iteration.  For more information, see the list directive.

IMPORTANT: The results are not sorted in any order. If ordering is required, create an in-memory list of hashes in the loop using RPL, and use the ?sort_by builtin.

Example:

<#assign today=.now>
<#assign oneweek=dayadd(today, 7)>
<#content Events as event limit=5>
  <#filter REGION_NAME=PROFILE.REGION && DATE gte today && DATE lt oneweek>
  ${event.DESCR}-${event.CATEGORY}-${event.VENUE}-${event.DATE?string("yyyyMMdd")}
</#content>

produces output similar to this:

Eagles in concert-CONCERT-HP Pavillion-20161028
Knicks vs. Golden State-NBA-Oracle Arena-20161024
Lakers vs. Golden State-NBA-Oracle Arena-20161028
Trailblazers vs. Kings-NBA-Sleep Train Arena-20161030

Limiting the number of records
To limit the number of records, use the limit=x option in the content declaration. The limit expression can be any numeric expression. See the example in this section.

Two limits are configured in your account:

Default Limit
When the limit is not specified in the content directive, the default is 20.  This default limit can be configured by the account administrator.

Maximum Limit
To ensure efficiency, when the limit is specified, it cannot exceed this number of results. The default limite is also. Entering a limit greater than the allowed maximum produces an error.

Conditionally breaking out of the looping
It is possible to loop through the found records until all records are reached, according to the filter and limit declarations.  However, in some cases you might want to stop the iteration by using the break directive. The break directive is usually placed within an if construct.

Obtaining context information within the loop
In addition to the namespace variable, two other variables are also declared, to give context about the execution of the loop: hash-name_has_next, and hash-name_index

In the above example, these new variables are event_has_next and event_index.

Handling images
If the content table contains strings that begin with the sequence /contentlibrary/,  they are automatically converted to a valid path for the internet through the use of the Content Delivery Network (CDN). This way, you can create content that is related to images in the Content Library. For example, the image is created at the path

campaigns/campaign10242016/welcome1.jpg.

To properly convert the image to a CDN address during a launch, you must store the file name in the content table as

/contentlibrary/campaigns/campaign10242016/welcome1.jpg.

With this mechanism. you can manage images stored in the Content Library using meta data and paths in supplemental tables. Upload your images to the Content Library, and fill the table with paths related to each specific piece of content.

You can also store and manage content other than images (e.g. PDFs) in this way.

data, filter, fields, break

<#data datasource as hash-name option=value-expr ...>
  <#filter key1=value-expr-1 key2=value-expr-2 ...>
  <#fields field-name1 field-name2 ...>
  ...
</#data>

Parameter

Description

datasource

The name of the datasource alias, as defined in the Message Designer for Email. Not an expression.  Please note that this is not the name of the actual datasource. Datasource aliases are defined in the Message Designer for Email’s datasources tab.

hash-name

The name of the structure that can be used in the enumeration of records.

option

One of the following values:

limit
A numeric expression

Limits the number of records returned from the execution of the expression. If the limit is greater than the existing number of records, it is ignored.  This option is invalid when using the singlekey option. The numeric expression is any expression that returns a number, including any numeric constants.  Non-integer numbers are rounded off.

singlekey
A boolean-expression

Specifies that only one row should be returned for each key that matches the filter. This option is restricted to the case when there is only one key.  This option does not allow limiting the number of records returned (see the limit option above); it is an error to specify both options at the same time.  The boolean expression is any expression that results on true or false, including the constants true and false.

Filter

Parameter

Description

key1, key2, …

The alias names of the columns to use for the filter, as defined in the Datasources tab of Message Designer for Email.

Not an expression. 

value-expr-1, value-expr-2, …

The values to use to look up the data. 

The values can be expressions according to the data type in the datasource.

If the data types are different from the ones in the data source, template execution will fail. If  you do not know the value types in the data source, ask the campaign designer for the proper types to use.

Fields

Parameter

Description

field-name1, field-name2, etc.

The alias names of the fields to use. 

These appear in the hash specified by hash-name as hash values. The alias names are specified in the Datasources section of the Message Designer for Email.

This directive selects records from a given datasource with the given filter using the specified fields. A new hash is created with the given fields. The records are filtered as specified in the <#filter …> construct. The hash is created with the <#fields…> construct.

There are two special loop variables available inside the data loop:

hash-name_index
This is a numerical value that contains the index of the current item being stepped over in the loop.

hash-name_has_next
A boolean value that tells whether or not the current item the last in the datasource query.

The break instruction can be used inside the loop body to exit the iteration. For more information, see the list directive.

Select based on one value for one or multiple lookup fields

To use this option, specify multiple field/-value pairs in the filter specification. Each value must be a scalar.

The data query performed has the AND semantics.

Example:

<#data events as event limit=10>
  <#filter category="NBA Tickets" region="NY">
  <#fields event_id description venue city state event_date>
Event:
- ${event.event_id}, ${event.description}, ${event.venue},
  ${event.city}, ${event.state} ${event.event_date}
</#data> 

produces output similar to this:

Event:
- 15, Knicks vs. Raptors, Madison Square Garden, 
  New York, NY, 4/30/2013
Event:
- 16, Knicks vs. Clippers, Madison Square Garden,
  New York, NY, 5/1/2013

This option will look for records whose category is NBA Tickets and the region is NY.

In this modality, you can also specify the limit option as shown. If there were more records in the database table then the specified limit, the response would be limited to the first 10 elements.

In addition to retrieving records with one value (AND semantics), it is possible to specify multiple values for those fields.

This introduces a lower-level OR semantics to the selection of fields, for example:

<#data events as event limit=10>
  <#filter category=["NBA Tickets", "MLB Tickets"] region="NY">
  <#fields event_id description venue city state event_date>
Event:
- ${event.event_id}, ${event.description}, ${event.venue},
  ${event.city}, ${event.state} ${event.event_date}
</#data> 

Notice that the category now has a sequence.  The meaning of this expression is "obtain the records whose category is either NBA Tickets or MLB Tickets, but whose region has the value of NY."  This would get tickets for the NBA or the MLB in the NY region.

The limit option is also valid in this context. To use this option, specify a single field in the filter specification and provide a sequence of scalars (or a single value). All scalars must be of the same type and in accordance with the datasource specification.

You can add the singlekey option with a value of true to the data directive. The singlekey option only works with a single field.

The data query performed has the OR semantics. The sequence provides the possible values that the field can take. When a single value is provided, it has the EQUALITY semantics.

IMPORTANT: The filter will return at most only one value for each key. 

Example:

<#data events as event singlekey=true>
  <#filter category=["NBA Tickets", “MLB Tickets”, “NFL Tickets”]>
  <#fields category event_id description venue city state event_date>
Event:
- ${event.category}, ${event.event_id}, ${event.description}, ${event.venue}
  ${event.city}, ${event.state}, ${event.event_date}
</#data> 

produces output similar to this:

Event:
- MLB Tickets, 1, Mets vs Cardinals, Shea Stadium, 
  New York, NY, 5/25/2013
Event:
- NBA Tickets, 15, Knicks vs. Raptors, Madison Square Garden, 
  New York, NY, 4/30/2013
Event:
- NFL Tickets, 12, Jets vs. Raiders, MetLife Stadium,
  New York, NY, 3/1/2013

If two records match, for example NBA Tickets, then only the first one is returned.  This behavior is specified with the addition of the singlekey option.

IMPORTANT: It is not currently possible to query multiple keys with multiple values with th singlekey semantics.

Using the limit option will cause an error. Also, using a single value as opposed to a sequence will return zero, or at most, one record.

This option is useful when you want to retrieve, for example, all the event types in the NY region as shown in the following example:

<#assign categories=[]>
<#data events as event singlekey=true>
  <#filter category=["NBA Tickets", "MLB Tickets", "NFL Tickets"]>
  <#fields category>
  <a href="#${event.category}">${event.category}</a>
  <#assign categories=categories + [ event.category ]>
</#data>
 
<#list categories as category_name>
  <a name="${category_name}" />
  <h3>${category_name}</h3>
  <#data events as event limit=5>
    <#filter category=${category_name}>
    <#fields description venue city state event_date>
  ${event.description} at ${event.venue} in
  ${event.city}, ${event.state} on ${event.event_date}
  </#data>
</#list>

 

Limiting the number of records

To get a maximum number of records, use the limit=x option in the data declaration. This causes the number of records obtained be cut if there are more records than the specified limit. The limit can be any numeric expression. 

This option is not valid with the singlekey option.

Conditionally breaking out of the loop

It is possible to loop through the found records until all records are reached, according to the filter and limit declarations. However, you can stop the iteration by using the break directive, usually placed within an if construct.

Obtaining Context information within the loop.

In addition to the namespace variable, two other variables, hash_has_next and hash_index are also declared, to give context about the execution of the loop. In our example, these new variables are offer_has_next and offer_index.

escape

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

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

Example:

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

is equivalent to:

  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 serves as a formal parameter to the escaping expression.

When calling macros or the include directive, it is important to understand that escape affects only interpolations that occur between the <#escape ...> and </#escape> tags in the template text. That is, it will not escape anything before <#escape ...> or after </#escape> in the text, not even if it is called from inside the escaped section. For example:

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

produces this output:

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

The effect of the 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 will not 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) with an escape block, the interpolations in those macros will be combined with the escaping expression.

If you need to temporarily turn off escaping for one or two interpolations in an escape block, you can close and later reopen the escape block, but then you have to write the escaping expression twice. Instead, you can instead use the noescape directive as shown in the following example:

<#escape x as x?html>
  User: ${user.Name}
  Text: ${user.Text}
  <#noescape>Title: ${user.title}</#noescape>
  ...
</#escape>  

the above example is equivalent to:

  User: ${user.Name?html}
  Text: ${user.Text?html}
  Title: ${user.title}

You can nest escapes, although you should do it only in rare circumstances. Therefore, you can write something like the following example:

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

which is equivalent to:

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

When using 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, use two nested noescape directives.

fail

<#fail>
or
<#fail reason>

Parameter

Description

reason

Informative message about the reason for termination. Expression evaluates to a string.

Stops the processing of the entire launch. After this directive executes, no other instructions are executed.

A failed run appears in the Live Report as a launch failure.

function, return

<#function name param1 param2 ... paramN>
  ...
  <#return returnValue>
  ...
</#function>

Parameter

Description

name

The name of method variable. Not an expression.

param1, param2, ...etc.

The name of the local variables store the parameter values (not an expression), optionally followed by = and the default value (an expression).

paramN

The last parameter, can optionally include a trailing ellipsis (...), which indicate that the macro takes a variable number of parameters. Local variable paramN will be a sequence of the extra parameters.

returnValue

The expression that calculates the value of the method call.

Creates a method variable in the current namespace. This directive works in the same way as the macro directive, except that the return directive must have a parameter that specifies the return value of the method, and that attempts to write to the output will be ignored. If the </#function> is reached (i.e. there was no return returnValue), the return value of the method is an undefined variable.

You can use the return directive anywhere and any number of times between the <#function ...> and </#function>.

Parameters without default values must precede parameters with default values (paramName=defaultValue).

Example: Creating a method that calculates the average of two numbers:

<#function avg x y>
  <#return (x + y) / 2>
</#function>
${avg(10, 20)}  

produces this output:

15  

Example: Creating a method that calculates the average of multiple numbers:

<#function avg nums...>
  <#local sum = 0>
  <#list nums as num>
    <#local sum = sum + num>
  </#list>
  <#if nums?size != 0>
    <#return sum / nums?size>
  </#if>
</#function>
${avg(10, 20)}
${avg(10, 20, 30, 40)}
${avg()!"N/A"}  

produces this output:

15
25
N/A  

global

<#global name=value>
or
<#global name1=value1 name2=value2 ... nameN=valueN>
or
<#global name>
  capture this
</#global>

Parameter

Description

name

The name of the variable. Not a expression. However, it can be written as a string literal, which is useful if the variable name contains reserved characters, for example <#assign "foo-bar" = 1>.

Note that this string literal does not expand interpolations (as "${foo}").

value

The value to store. This is an expression.

This directive is similar to assign, but the variable created will be visible in all namespaces, and will not be inside any namespace as if you created or replaced a variable of the data model. Hence, the variable is global. If a variable with the same name already exists in the data model, it will be hidden by the variable created with this directive. If a variable with the same name already exists in the current namespace, it will hide the variable created with this directive.

For example, you create a variable with <#global x = 1> that is visible as x in all namespaces, unless another variable called x hides it (for example a variable created as <#assign x = 2>). In this case, you can use the special variable .globals, as ${.globals.x}. Note that with .globals, you see all globally accessible variables, including the variables of the data model.

if, else, elseif

<#if condition>
  ...
<#elseif condition2>
  ...
<#elseif condition3>
  ...
...
<#else>
  ...
</#if>

Parameter

Description

condition, condition2, ...etc.

Expression evaluates to a boolean value.

Use these directives to conditionally skip a section of the template. The conditions must evaluate to a boolean value. Otherwise, an error occurs that terminates template processing. The elseif(s) and else(s) must occur between the start and end tags of if. if can contain any number of elseif(s) and, optionally, one else at the end.

Examples:

if with no elseif and no else:

<#if x == 1>
  x is 1
</#if>  

if with no elseif and an else:

<#if x == 1>
  x is 1
<#else>
  x is not 1
</#if>  

if with 2 elseif and no else:

<#if x == 1>
  x is 1
<#elseif x == 2>
  x is 2
<#elseif x == 3>
  x is 3
</#if>  

if with 3 elseif and an else:

<#if x == 1>
  x is 1
<#elseif x == 2>
  x is 2
<#elseif x == 3>
  x is 3
<#elseif x == 4>
  x is 4
<#else>
  x is not 1 nor 2 nor 3 nor 4
</#if>  

You can nest if directives, as shown in the following example:

<#if x == 1>
  x is 1
  <#if y == 1>
    and y is 1 too
  <#else>
    but y is not
  </#if>
<#else>
  x is not 1
  <#if y < 0>
    and y is less than 0
  </#if>
</#if>  

IMPORTANT: To test whether x is greater than 1, write either <#if (x > 1)> or <#if x &gt; 1>. Note that <#if x > 1> is incorrect, as RPL will interpret the first > as the end of the tag.

list, break

<#list sequence as item>
    ...
</#list>
 
or
 
<#list sequence as item>
    ...
    <#break>
    ...
</#list>

Parameter

Description

sequence

Expressions evaluates to a sequence or collection.

item

Name of the loop variable (not an expression).

Use this directive to process a section of the template for each variable of a sequence. The code between the start and end tags will be processed for the first sub-variable, then for the second sub-variable, etc. until it passes the last one. For each such iteration, the loop variable will contain the current sub-variable.

Two special loop variables are available inside the list loop:

item_index
This is a numerical value that contains the index of the current item being stepped over in the loop.

item_has_next
A boolean value that specifies whether or not the current item the last in the sequence.

Example:

<#assign seq = ["winter", "spring", "summer", "autumn"]>
<#list seq as x>
  ${x_index + 1}. ${x}<#if x_has_next>,</#if>
</#list>  

produces this output:

  1. winter,
  2. spring,
  3. summer,
  4. autumn  

You can use this directive to count between numbers, using a numerical range sequence expression, for example:

<#assign x=3>
<#list 1..x as i>
  ${i}
</#list>  

produces this output:

  1
  2
  3

Note that the above example will not work as you may expect if x is 0, as it will print 0 and -1.

You can leave the list loop before it passes the last sub variable of the sequence using the break directive. For example, to print only winter and spring:

<#list seq as x>
  ${x}
  <#if x = "spring"><#break></#if>
</#list>  

You can also use this directive to create a comma separated list manually. Note that the join builtin can produce the same list with fewer lines.  For example, if the sequence animals contains [“giraffe”, “lion”, “eagle”], then:

<#assign readable=””>
<#list animals as animal>
  <#assign readable=readable+animal
  <#if animal_has_next>
    <#assign readable=readable + “, ”:
  <#else>
    <#assign readable=readable + “, and”>
  <#/if>
<#/list>

produces this output:

giraffe, lion, and tiger

The example above illustrates using the list directive. The same output can be achieved with the join builtin as follows:

<#assign readable=animals?join(", ", ", and ")>

import

<#import path as hash>

Parameter

Description

path

The path of a template. This is an expression that evaluates to a string.

hash

The unquoted name of hash variable by which you can access the namespace. Not an expression.

 

Imports a library. The directive creates a new empty namespace, then executes the template given with the path parameter in that namespace so the template populates the namespace with variables (macros, functions, ...etc.). Then, the directive makes the newly created namespace available to the caller with a hash variable. The hash variable will be created as a plain variable in the namespace used by the caller of import (as if you would create it with the assign directive), with the name given with the hash parameter.

Calling import multiple times with the same path creates the namespace and runs the template only for the first call. Subsequent calls will create a hash by which you can access the same namespace.

The template is executed to populate the namespace with variables, not to write to the output. Therefore, the output produced by the imported template will be ignored (will not be inserted at the place of importing).

Example:

<#import "/contentlibrary/libs/mylib.htm" as my>
 
<@my.copyright date="1999-2002"/>  

The path parameter can be a relative path such as "foo.htm" and "../foo.htm", or an absolute path such as "/contentlibrary/foo.htm". Relative paths are relative to the directory of the template that uses the directive.

NOTE: Always use the forward slash (/) to separate path components, never the back slash (\). If you are loading templates from your local file system and it uses backslashes, RPL will convert them automatically.

Similarly to the include directive, you can use acquisition and localized lookup for resolving the path.

For information about namespaces, see Namespace Reference.

include

<#include path>
or
<#include path options>

Parameter

Description

path

The path of the file to include; an expression that evaluates to a string.

options

One or more of the following:

encoding=encoding
Expression evaluates to a string

parse=parse
Expression evaluates to Boolean

cleanup=cleanup
Expression evaluates to Boolean

cleanupmode=cleanupmode
Expression evaluates to a string

For more information about these options, see “Supported Options” further in this section.

You can use this directive to insert the RPL template file specified by the path parameter into the template.

The output from the included template is inserted at the point where the include tag occurs. The included file shares the variables with the including template, similarly as if it was copy/pasted into it.

The include directive does not replace the content of the included file, it just processes the included file each time RPL reaches the include directive during template processing. For example, if you use include inside a listloop, you can specify different file names in each cycle.

The path parameter can be a relative path such as "foo.htm" and "../foo.htm", or an absolute path such as "cms://contentlibrary/foo.htm". Relative paths are relative to the directory of the template that uses the import directive.

NOTE: Always use the forward slash (/) to separate path components, never the back slash (\).

Example:

If /common/copyright.htm contains:

Copyright 2001-2002 ${me}<br>
All rights reserved.  

then the following example:

<#assign me = "Juila Smith">
<h1>Some test</h1>
<p>Yeah.
<hr>
<#include "cms://contentlibrary/common/copyright.htm">  

produces this output:

<h1>Some test</h1>
<p>Yeah.
<hr>
Copyright 2001-2002 Juila Smith
All rights reserved.  

Supported options

parse
If true, the included file will be parsed as RPL. Otherwise, the file will be considered as simple text. If you omit this option, the default is true.

encoding
The included file inherits the encoding (charset) of the including template, unless you specify an encoding with this option. Encoding names are the same as those supported by java.io.InputStreamReader (as of Java API 1.3: MIME-preferred charset names from the IANA Charset Registry). Examples of valid names: ISO-8859-2, UTF-8, Shift_JIS, Big5, EUC-KR, GB2312.

cleanup
In some cases, the contents of the included file is a complete HTML file, with HTML and body tags in it. Inserting such a file into the destination stream might result in a file with double HTML and body tags. The effect of this double body becomes apparent when the footers are inserted after personalization: the footer might be placed right on top of the wrong closing body tag. http/https included files are usually retrieved with contents in this way. The cleanup flag allows the extraction of all content between the included file's body tags, thus eliminating any extra HTML, head, or body tags.  Note that an inclusion of a file with no body tags will result in empty content. For this reason, use this flag only when you are sure that the content contains a body tag.

cleanupmode
In some cases, the content of the included file does not contain an html <body> tag. In such cases, if the cleanup parameter is set to true, it will return an empty document by default. If you want to return either the original content or empty content, use the cleanupmode parameter which can take either of two values: "empty" or "original".

If cleanupmode is not specified, the default value is "empty". 

If "empty" is specified, or no cleanupmode is specified, include returns an empty document if the content does not have a <body> tag.

If "original" is specified, the original content is returned if the content does not have a <body> tag.

Example:

<#include "cms://contentlibrary/common/navbar.html" parse=false encoding="Shift_JIS" cleanup=true cleanupmode="original">   

Using acquisition

Acquisition allows you to place commonly included files in a parent directory, and place them in sub-directories as needed. The including template will then acquire the template to include from the parent directory.

To use acquisition, use an asterisk (*) to represent a directory and any of its parents. For example, if the template is located in /contentlibrary/foo/bar/template.htm , this line:

<#include "*/footer.htm">  

searches for the template in the following locations, in the order shown:

  1. /contentlibrary/foo/bar/footer.htm

  2. /contentlibrary/foo/footer.htm

  3. /contentlibrary/footer.htm

Note that you can specify not only a template name to the right of the asterisk, but a sub-path as well. For example, this line:

<#include "*/commons/footer.htm">  

searches for the template in following locations, in the order shown:

  1. /contentlibrary/foo/bar/commons/footer.htm

  2. /contentlibrary/foo/commons/footer.htm

  3. /contentlibrary/commons/footer.htm

Finally, * does not have to be the first element in the path, as shown in the following example:

<#include "commons/*/footer.htm">  

This searches for the template in following locations, in the order shown:

  1. /contentlibrary/foo/bar/commons/footer.htm

  2. /contentlibrary/foo/bar/footer.htm

  3. /contentlibrary/foo/footer.htm

  4. /contentlibrary/footer.htm

The path can include only one asterisk. Specifying more than one asterisk will result in the template not being found.

Localized lookup

When a template is loaded, it is assigned a locale. A locale is a language and an optional country or dialect identifier. A template is typically loaded by and the locale is chosen based on the profile.

When a template includes another template, it attempts to load a template with the same locale. For example, your template was loaded with locale en_US, which means U.S. English. When you include another template:

<include "footer.htm">  

the engine will look for several templates, in the order shown:

  1. footer_en_US.htm

  2. footer_en.htm

  3. footer.htm

When you use both acquisition and localized template lookup, the template with a more specific locale in a parent directory takes precedence over template with a less specific locale in a child directory. For example, if you use the following include from /foo/bar/template.htm:

<#include "*/footer.htm">  

RPL will look for these templates, in the order shown:

  1. /foo/bar/footer_en_US.htm

  2. /foo/footer_en_US.htm

  3. /footer_en_US.htm

  4. /foo/bar/footer_en.htm

  5. /foo/footer_en.htm

  6. /footer_en.htm

  7. /foo/bar/footer.htm

  8. /foo/footer.htm

  9. /footer.htm

Loading from the Content Library

In most cases, the templates are stored in the Content Library. You can include additional documents in other scenarios as described below.

Using the full path referencing the document

In this case, specify your import as:

<#import “cms://full-content-library-path”>

The full content path is described using the root as /contentlibrary/ and thus the previous example will look this:

<#import “cms://contentlibrary/sub-content-library-path”>

Using a document that includes a document in the same directory, a subdirectory, or a directory right above it.

In this case, you can import the document specifying a root or the cms:// prefix.  RPL will ensure that the document is located using the path of the current template. For example:

<#import “document2.htm”>
Or
<#import “subdir/document3.htm”>
Or
<#import “../siblingdir/document4.htm”>

The nomenclature for .. means one directory above the current directory.

Using a document including a document in an unspecified subdirectory

See the section of content acquisition above.

Loading from urls

To be able to download content from urls, your account must be enabled to download from http and https.

In cases when content is stored content remotely, i.e. in a web server outside of the system, use the http:// or https:// prefix and the full path name of the remote template.

We recommend that you do not store content on your web site because it can open your campaign to malicious attacks. In addition, you can cause a “denial-of-service” attack to your web server by repeatedly requesting a template during a launch with many records.

To prevent malicious attacks, RPL tries to optimize access to remote sites by following the commonly used HTTP/1.1 protocol.  It is very important that the web site is configured correctly to avoid repeated calls. You can optimize content retrieval using either the expiration model or the validation model.   

Expiration model
In the expiration model, content remains valid until a specified time. RPL will not try to retrieve such content until the expiration time has been reached, keeping the content available for personalization.

Validation model
The validation model works after prior content has been retrieved, the expiration time is reached, or the expiration time has not been set. RPL will send the last retrieval time (or the last modified date as specified by the web server), and the web server can respond with new content or notify RPL that the current content has not been modified. When using the validation model without expiration, the same warnings apply regarding “denial-of-service”.

It is always recommended to ensure that the web server correctly sends the expiration time. As a safeguard, when no expiration time is returned, the system will assume one hour, which is appropriate for most launch scenarios. If one hour is not sufficient for your needs, make sure that your web server  sets the expiration to the time you need.

In addition, when the web server does not send the last modified time, for validation purposes, RPL will request the content to the remote repository with the time that the last content was retrieved.

Note that for url-based content, it is often recommended to use the cleanup flag to remove any html, head, or body tags from the source content, but only if the content contains a proper body tag.

join

<#join>
</join>
or
<#join separator-expression>
</#join>

Parameter

Description

separator-expression

A string expression that specifies the string to be placed instead of new lines.

Strips new line from the output of the block that it encompasses. This is very useful when dealing with blocks that result in text-only output, and proper formatting of RPL is desired.  It is very helpful in conjunction with the compress directive.

Example 1:

<#assign sequence=["a", "b", "c", "d", "e", "f"]>
<#join>
<#compress>
<#list sequence as item>
  ${item}
</#list>
</#compress>
</#join>

produces this output:

abcdef

Example 2:

<#assign sequence=["a", "b", "c", "d", "e", "f"]>
<#join "-">
<#compress>
<#list sequence as item>
  ${item}
</#list>
</#compress>
</#join>

produces this output:

a-b-c-d-e-f

local

<#local name=value>
or
<#local name1=value1 name2=value2 ... nameN=valueN>
or
<#local name>
  capture this
</#local>

Parameter

Description

name

The name of the variable. This is not an expression. However, you can write it as a string literal, which is useful if the variable name contains reserved characters, for example <#assign "foo-bar" = 1>. Note that this string literal does not expand interpolations (as "${foo}").

Value

The value to store. This is an expression.

 

This directive is similar to the assign directive, but it creates or replaces local variables. This directive works only inside macro and function definitions.

macro, nested, return

<#macro name param1 param2 ... paramN>
  ...
  <#nested loopvar1, loopvar2, ..., loopvarN>
  ...
  <#return>
  ...
</#macro>

Parameter

Description

name

The name of the macro variable. This is not an expression. However, it can be written as a string literal, which is useful if the macro name contains reserved characters, for example <#macro "foo-bar">.

Note that this string literal does not expand interpolations (as "${foo}").

param1, param2, ...etc.

The name of the local variables that store the parameter values (not an expression), optionally followed by = and the default value (an expression). The default value can be another parameter, for example <#macro section title label=title>.

paramN

Optionally, the last parameter can include a trailing ellipsis (...). The ellipsis indicate that the macro takes a variable number of parameters. If called using named parameters, paramN will be a hash containing all undeclared key/value pairs passed to the macro. If called using positional parameters, paramN will be a sequence of the extra parameters.

loopvar1, loopvar2, ...etc.

Optional. The values of loop variables that the nested directive should create for the nested content. These are expressions.

Creates a macro variable in the current namespace. For more information about macros, see “Defining Your Own Directives”.

A macro variable stores a template fragment (called macro definition body) that can be used as user-defined directive. The variable also stores the name of allowed parameters to the user-defined directive. When using the variable as a directive, you must give value for all parameters that do not have a default value. The default value will be used only if you do not provide a value for the parameter when calling the macro.

The return and nested directives are optional and can be used anywhere and any number of times between the <#macro ...> and </#macro>.

Parameters without a default value must precede parameters with a default value (paramName=defaultValue).

The variable will be created at the beginning of the template regardless of where the macro directive is placed in the template. For example:

<#-- call the macro; the macro variable is already created: -->
<@test/>
...
 
<#-- create the macro variable: -->
<#macro test>
  Test text
</#macro>  

However, if the macro definitions are inserted with the include directive, they will not be available until RPL has executed the include directive.

Example: Macro without parameters:

<#macro test>
  Test text
</#macro>
<#-- call the macro: -->
<@test/>  

produces this output:

  Test text

Example: Macro with parameters:

<#macro test foo bar baaz>
  Test text, and the params: ${foo}, ${bar}, ${baaz}
</#macro>
<#-- call the macro: -->
<@test foo="a" bar="b" baaz=5*5-2/>  

produces this output:

  Test text, and the params: a, b, 23

Example: Macro with parameters and default parameter values:

<#macro test foo bar="Bar" baaz=-1>
  Test text, and the params: ${foo}, ${bar}, ${baaz}
</#macro>
<@test foo="a" bar="b" baaz=5*5-2/>
<@test foo="a" bar="b"/>
<@test foo="a" baaz=5*5-2/>
<@test foo="a"/>  

produces this output:

  Test text, and the params: a, b, 23
  Test text, and the params: a, b, -1
  Test text, and the params: a, Bar, 23
  Test text, and the params: a, Bar, -1

  Example: A more complex macro:

<#macro list title items>
  <p>${title?cap_first}:
  <ul>
    <#list items as x>
      <li>${x?cap_first}
    </#list>
  </ul>
</#macro>
<@list items=["mouse", "elephant", "python"] title="Animals"/>  

produces this output:

  <p>Animals:
  <ul>
      <li>Mouse
      <li>Elephant
      <li>Python
  </ul>

Example: A macro with support for a variable number of named parameters:

<#macro img src extra...>
  <img src="/context${src?html}" 
  <#list extra?keys as attr>
    ${attr}="${extra[attr]?html}"
  </#list>
  >
</#macro>
<@img src="/images/test.png" width=100 height=50 alt="Test"/>  

produces this output:

  <img src="/context/images/test.png"
    alt="Test"
    height="50"
    width="100"
  >  

nested

Executes the template fragment between the start and end tags of a user-defined directive. The directive can contain anything that is valid in templates, such as interpolations and directives.

This directive is executed in the context from where the macro is called, rather than in the context of the macro definition body. Thus, for example, the local variable of the macro does not appear in the nested part. If you do not call the nested directive, the part between the start and end tags of the user-defined directive will be ignored.

Example:

<#macro do_twice>
  1. <#nested>
  2. <#nested>
</#macro>
<@do_twice>something</@do_twice>  

produces this output:

  1. something
  2. something

The nested directive can create loop variables for the nested content, for example:

<#macro do_thrice>
  <#nested 1>
  <#nested 2>
  <#nested 3>
</#macro>
<@do_thrice ; x>
  ${x} Anything.
</@do_thrice>  

produces this output:

  1 Anything.
  2 Anything.
  3 Anything.

A more complex example:

<#macro repeat count>
  <#list 1..count as x>
    <#nested x, x/2, x==count>
  </#list>
</#macro>
<@repeat count=4 ; c, halfc, last>
  ${c}. ${halfc}<#if last> Last!</#if>
</@repeat>  

produces this output:

  1. 0.5
  2. 1
  3. 1.5
  4. 2 Last!

return

Allows you to leave a macro or function definition body anywhere. For example:

<#macro test>
  Test text
  <#return>
  Will not be printed.
</#macro>
<@test/>  

produces this output:

  Test text

noparse

<#noparse>
  ...
</#noparse>

Prevents RPL from searching RPL tags, interpolations and other special sequences within the body of this directive. For example:

<#noparse>
  <#list animals as being>
  <tr><td>${being.name}<td>${being.price} Euros
  </#list>
</#noparse>  

produces this output:

  <#list animals as being>
  <tr><td>${being.name}<td>${being.price} Euros
  </#list>

Note that HTML readers such as web browsers might not render RPL properly. This is caused by the fact that the HTML reader expects only HTML, and RPL is not properly formed HTML. Specifically, it has been observed that the readers usually omit closing RPL tags such as (</#list>). 

To properly display RPL in an HTML reader, you can write the previous example as:

<#assign unparsed>
<#noparse>
  <#list animals as being>
  <tr><td>${being.name}<td>${being.price} Euros
  </#list>
</#noparse>
</#assign>
${unparsed?html}

This example uses assign to keep the output that will be displayed in a variable called unparsed. It then encodes and outputs this variable as HTML.

nt

<#nt>

Disables white space stripping in the line where it occurs. It also disables the effect of other trim directives occurring in the same line (the effect of t, rt, lt).

rpl

<#rpl param1=value1 param2=value2 ... paramN=valueN>

Parameter

Description

param1, param2, ...etc.

Name of the parameter. This is not an expression. See the “Supported parameters” table below for valid parameters.

value1, value2, ...etc.

The value of the parameter. This must be a constant expression (as true, or "ISO-8859-5", or {x:1, y:2}). It cannot use variables.

Supported parameters

Parameter

Description

encoding

Specifies the encoding (charset) of the template in the template file. This will be the encoding setting of the newly created template, and not even the encoding parameter to Configuration.getTemplate can override it.

Note however, that RPL will try to find and interpret the RPL directive first with the automatically guessed encoding. After that, if the RPL directive dictates something different, RPL will re-read the template with the new encoding. This means that the template must be valid RPL until the end of the RPL tag with the encoding tried first. The valid values of this parameter are MIME-preferred charset names from the IANA Charset Registry, such as ISO-8859-5, UTF-8 or Shift_JIS.

strip_whitespace

Enables or disables white space stripping. Valid values are true and false, and strings "yes", "no", "true", "false"). When this parameter is not specified, the default value is true.

strip_text

When enabled, all top-level text in a template is removed when the template is parsed. This does not affect text within macros, directives, or interpolations. Valid values are true and false. When this parameter is not specified, the default value is false.

ns_prefixes

A hash that associates prefixes with node namespaces. For example: {"e":"http://example.com/ebook", "vg":"http://example.com/vektorGraphics"}.

This is used mostly with XML processing where the prefixes can be used in XML queries, but it also influences the working of the visit and recurse directives. There is a one-to-one relation between prefixes and node namespaces. This means that only one prefix can be registered for the same node namespace; otherwise an error will occur.

Prefixes D and N are reserved. If you register prefix D, then in addition to associating the node namespace with prefix D, you are setting the default node namespace. You cannot register prefix N because it is used to denote nodes with no node namespace in certain places when prefix D is registered. For more information, see XML Processingand the visit and recurse directives.

The effect of ns_prefixes is limited to a single RPL namespace, namely, to the RPL namespace that was created for the template. This also means that ns_prefixes is used only when an RPL namespace is created for the template that contains it; otherwise, this parameter has no effect. An RPL namespace is created for a template when:

the template is the main template, that is, it is not invoked as a result of an <#include ...>) OR

the template is invoked directly with <#import ...>.

Attributes

A hash that associates arbitrary attributes (name/value pairs) to the template. The values of the attributes can be of any type.

This directive provides information about the template for RPL and other tools, and helps programs to automatically detect whether a text file is an RPL file.

IMPORTANT: This directive, if present, must be the very first thing in the template. Any white space before this directive will be ignored.

The settings given here have the highest precedence. This means that they will be used for the template regardless of any other RPL configuration settings.

setting

<#setting name=value>

Parameter

Description

name

The name of the setting. This is not an expression.

value

New value of the setting. This can be an expression.

Sets values that influence RPL behavior for further processing. The new value will be present only in the template processing where it was set, and does not affect the template itself. The initial value is set by the system.

Supported settings

Setting

Description

locale

The locale (language) of the output.

The locale can influence the presentation format of numbers, dates, etc. The value is a string which consists of a language code (lowercase two-letter ISO-639 code) plus an optional county code (uppercase two-letter ISO-3166 code) separated from the language code by an underscore. If you specify the country, you can also specify an optional variant code (not standardized) separated from the country by an underscore. For example: en, en_US, en_US_MAC.

RPL will try to use the most specific available locale. This means that if you specify en_US_MAC and MAC is unknown, RPL will try en_US, then en, then the default locale of the computer (which is set by the system).

number_format

The number format to use to convert numbers to strings when no explicit format is specified.

This can be one of predefined values: number (the default), computer, currency, or percent. Additionally, you can specify an arbitrary format pattern written in Java decimal number format syntax. For more information about format patterns, see the string built-in.

boolean_format

The comma-separated pair of strings to use for representing true and false when converting booleans to strings with no explicitly specified format. The default value is "true,false".

date_format, time_format, datetime_format

The date/time format to use for converting dates to strings when no explicit format is specified, for example ${someDate}.

date_format affects the formatting of date-only dates (year, month, day).

time_format affects the formatting of time-only dates (hour,minute, second, millisecond).

datetime_format affects the formatting of date-time dates (year, month, day, hour, minute, second, millisecond).

The possible values of the settings are similar to the parameters of string built-in of dates, for example, "short", "long_medium", "MM/dd/yyyy".

time_zone

The name of the time zone to use for formatting times for display.

This can be any value that is accepted by Java TimeZone API. For example, "GMT", "GMT+2", "GMT-1:30", "CET", "PST", "America/Los_Angeles".

By default, the system time zone is used.

url_escaping_charset

The charset to use for URL escaping (e.g. for ${foo?url}) to calculate the escaped (%XX) parts.

The framework that encloses RPL usually sets the charset, so this setting is rarely used.

Example: Assuming that the initial locale of template is hu (Hungarian), the following example:

${1.2}
<#setting locale="en_US">
${1.2}  

produces this output, because Hungary uses the comma as their decimal separator:

1,2
1.2  

skip

<#skip>
or
<#skip reason>

Parameter

Description

reason

Informative message about the reason for termination. Expression evaluates to string.

Stops the personalization of a record in an email campaign and, if possible, continues with the next record. The directive will stop executing the record immediately and return control to the personalization engine.

Skip calls are reported as skip events and are added to the events database. The reason is provided in the event itself. For information about the event system, see Interact Help and training materials.

switch, case, default, break

<#switch value>
  <#case refValue1>
    ...
    <#break>
  <#case refValue2>
    ...
    <#break>
  ...
  <#case refValueN>
    ...
    <#break>
  <#default>
    ...
</#switch>

Parameter

Description

value,

refValue1, etc.:

Expressions that evaluate to scalars of the same type.

IMPORTANT: We do not recommend using these directives, as they are error-prone because of the fall-through behavior. Unless you want to exploit the fall-through behavior, use elseif instead.

switch is used to choose a fragment of template depending on the value of an expression. For example:

<#switch being.size>
  <#case "small">
     This will be processed if it is small
     <#break>
  <#case "medium">
     This will be processed if it is medium
     <#break>
  <#case "large">
     This will be processed if it is large
     <#break>
  <#default>
     This will be processed if it is neither
</#switch>  

One or more <#case value> is required inside the switch and, optionally, one <#default> after all case tags.

When RPL reaches a case where refValue equals the value, it processes that case and continues processing the template. If there is no case directive with an appropriate value, RPL continues processing at the default directive if that exists; otherwise, it continues the processing after the end tag of switch. Note that when RPL has chosen a case directive, it will continue processing until it reaches a break directive. That is, it will not automatically leave the switch directive when it reaches another case directive or the <#default> tag.

Example:

<#switch x>
  <#case x = 1>
    1
  <#case x = 2>
    2
  <#default>
    d
</#switch>  

if x is 1, the output will be 1 2 d; if x is 2 , the output will be 2 d; if x is 3, the output will be d. The break tag instructs RPL to immediately skip past the switch end tag.

t, lt, rt

<#t>
 
<#lt>
 
<#rt>
 
<#nt>

These directives instruct RPL to ignore certain whitespace in the line of the tag:

t (trim)
Ignores all leading and trailing white space in this line

lt (left trim)
Ignores all leading white space in this line

rt (right trim)
Ignores all trailing white space in this line

Leading white space is all space and tab characters (and other characters that are white space according to UNICODE, except line breaks) before the first non-white space character of the line.

Trailing white space is all space and tab characters (and other characters that are white space according to UNICODE, except line breaks) after the last non-white space character of the line, and the line break at the end of the line.

You can use these directives anywhere within the line.

These directives examine the template, not the output that the template generates when you merge it with the data model. This means that white space removal happens at parse time.

For example:

--
  1 <#t>
  2<#t>
  3<#lt>
  4
  5<#rt>
  6
--  

produces this output:

--
1 23
  4
  5  6
--  

user-defined directive

<@user_def_dir_exp param1=val1 param2=val2 ... paramN=valN/>
(Note the XML-style / before the >)  
or if you need loop variables (more details...)
<@user_def_dir_exp param1=val1 param2=val2 ... paramN=valN ; lv1, lv2, ..., lvN/>
 
Or the same as the above two but with end-tag (more details...):
 
<@user_def_dir_exp ...>
  ...
</@user_def_dir_exp>
or
<@user_def_dir_exp ...>
  ...
</@>
 
Or all above but with positional parameter passing (more details...):
 
<@user val1, val2, ..., valN/>
...etc.

Parameter

Description

user_def_dir_exp

Expression that evaluates to an user-defined directive such as a macro that will be called.

param1, param2, ...etc.

Parameter names. These are not expressions.

val1, val2, ...etc.

Parameter values. These are expressions.

lv1, lv2, ...etc.

Loop variable names. These are not expressions.

Calls a user-defined directive, for example a macro. The meaning of parameters and the set of supported and required parameters depend on the directive.

The following rules apply to parameters:

  • The call can have zero parameters.

  • Parameters can be specified in any order, unless you use positional parameter passing.

  • Parameter names must be unique.

  • Parameter names are case sensitive.

    Example 1: Call the directive stored in the variable html_escape:

<@html_escape>
  a < b
  Romeo & Juliet
</@html_escape>  

produces this output:

  a &lt; b
  Romeo &amp; Juliet  

Example 2: Call a macro with parameters:

<@list items=["mouse", "elephant", "python"] title="Animals"/>
...
<#macro list title items>
  <p>${title?cap_first}:
  <ul>
    <#list items as x>
      <li>${x?cap_first}
    </#list>
  </ul>
</#macro>  

produces this output:

  <p>Animals:
  <ul>
      <li>Mouse
      <li>Elephant
      <li>Python
  </ul>

End tag

You can omit the user_def_dir_exp in the end tag. That is, you can write </@> instead of </@anything>. This rule is useful mostly when the user_def_dir_exp expression is too complex, because you do not have to repeat the expression in the end tag. Furthermore, if the expression contains anything except simple variable names and dots, you are not allowed to repeat the expression. For example, <@a_hash[a_method()]>...</@a_hash[a_method()]> is an error; you must write <@a_hash[a_method()]>...</@>. But <@a_hash.foo>...</@a_hash.foo> is correct.

Loop variables

Some user-defined directives create loop variables, similarly to the list directive. As with the predefined directives, the name of loop variables is given when you call the directive, while the value of the variable is set by the directive itself. In the case of user-defined directives, the name of loop variables is given after a semicolon. For example:

<@myRepeatMacro count=4 ; x, last>
  ${x}. Something... <#if last> This was the last!</#if>
</@myRepeatMacro>  

Note that the number of loop variable created by the user-defined directive and the number of loop variables specified after the semicolon does not need to match. For example, if you are not interested if the repetition is the last one, you can simply write:

<@myRepeatMacro count=4 ; x>
  ${x}. Something...
</@myRepeatMacro>  

or:

<@myRepeatMacro count=4>
  Something...
</@myRepeatMacro>  

Specifying more loop variables after the semicolon than the user-defined directive creates does not cause an error. In this case, the extra loop variables will not be created (i.e. those will be undefined in the nested content). Trying to use the undefined loop variables, however, will cause error unless you use built-ins such as ?default because you will be trying to access a non-existing variable.

Positional parameter passing

Positional parameter passing is currently supported only for macros.

Positional parameter passing (such as <@heading "Preface", 1/>) is a shorthand form of named parameter passing (such as <@heading title="Preface" level=1/>) where you omit the parameter name. Use positional parameter passing if a user-defined directive has only one parameter, or if it is easy to remember the order of parameters for a frequently used user-defined directive. To use this form, you have to know the order in which the named parameters are declared. For example, if a heading was created as <#macro heading title level>..., then <@heading "Preface", 1/> is equivalent to <@heading title="Preface" level=1/> or <@heading level=1 title="Preface"/>.

visit, recurse, fallback

<#visit node using namespace>
or
<#visit node>
<#recurse node using namespace>
or
<#recurse node>
or
<#recurse using namespace>
or
<#recurse>
<#fallback>

Parameter

Description

node

Expression that evaluates to a node variable.

namespace

A namespace or a sequence of namespaces.

A namespace can be given with the namespace hash (known as the gate hash), or with a string literal that stores the path of template that can be imported. Instead of namespace hashes, you can use plain hashes as well.

The visit and recurse directives are used for the recursive processing of trees. These are used mostly for processing XML.

visit

When you call <#visit node>, it looks for a user-defined directive (such as a macro) to invoke that has the name deducted from the node's name (node?node_name) and namespace (node?node_namespace).

Rules of name deduction

If the node does not support node namespaces (as text nodes in XML), then the directive name is simply the name of the node (node?node_name). A node does not support node namespaces if the getNodeNamespace method returns null.

If the node does support node namespaces (as element nodes in XML), then a prefix deduced from the node namespace may be appended before the node name with a colon (:) used as separator, for example e:book. The prefix, if one is used, depends on which prefixes have been registered with the ns_prefixes parameter of the rpl directive in the RPL namespace where visit looks for the handler directive. This namespace is not necessary the same as the RPL namespace where visit was called from. If a default namespace was not registered with ns_prefixes, no prefix is used for nodes that do not belong to any namespace. If default namespace was registered with ns_prefixes, prefix N is used for nodes that do not belong to any namespace, and no prefix is used for nodes that belong to the default node namespace. Otherwise, in both case, the prefix associated to the node namespace with the ns_prefixes is used. If a prefix is not associated to the node namespace of the node, visit behaves as if no directive was found with the proper name.

The node for which the user-defined directive was invoked is available for it as a special variable .node. For example:

<#-- Assume that nodeWithNameX?node_name is "x" -->
<#visit nodeWithNameX>
Done.
<#macro x>
   Now I'm handling a node that has the name "x".
   Just to show how to access this node: this node has ${.node?children?size} children.
</#macro>  

produces output similar to this:

   Now I'm handling a node that has the name "x".
   Just to show how to access this node: this node has 3 children.
Done.  

If one or more namespaces is specified using the optional using clause, then visit will look for the directives in those namespaces only, with the earlier specified namespaces in the list getting priority. If no using clause is specified, the namespace or sequence of namespaces specified with the using clause of the last uncompleted visit call is reused. If there is no such pending visit call, then the current namespace is used.

For example, if you execute this template:

<#import "n1.htm" as n1>
<#import "n2.htm" as n2>
 
<#-- This will call n2.x (because there is no n1.x): -->
<#visit nodeWithNameX using [n1, n2]>
 
<#-- This will call the x of the current namespace: -->
<#visit nodeWithNameX>
 
<#macro x>
  Simply x
</#macro>  

and this is n1.htm:

<#macro y>
  n1.y
</#macro>  

and this is n2.htm:

<#macro x>
  n2.x
  <#-- This will call n1.y, because it inherits the "using [n1, n2]" from the pending visit call: -->
  <#visit nodeWithNameY>
  <#-- This will call n2.y: -->
  <#visit nodeWithNameY using .namespace>
</#macro>
<#macro y>
  n2.y
</#macro>  

then this will print:

  n2.x
  n1.y
  n2.y
 
  Simply x

If visit does not find a user-defined directive in either RPL namespaces with the name identical to the name deduced with the rules described earlier, then it tries to find an user-defined directive with name @node_type. If the node does not support node type property (i.e. node?node_type returns undefined variable), then with name @default. For the lookup, it uses the same mechanism as was explained earlier. If it still does not find an user-defined directive to handle the node, then visit stops template processing with error. Some XML-specific node types have special handling in this regard.

<#-- Assume that nodeWithNameX?node_name is "x" -->
<#visit nodeWithNameX>
 
<#-- Assume that nodeWithNameY?node_type is "foo" -->
<#visit nodeWithNameY>
 
<#macro x>
Handling node x
</#macro>
 
<#macro @foo>
There was no specific handler for node ${node?node_name}
</#macro>  

produces this output:

Handling node x
  
There was no specific handler for node y

recurse

The <#recurse> directive visits all children nodes of the node (and not the node itself). So, the following:

<#recurse someNode using someLib>  

is equivalent to:

<#list someNode?children as child><#visit child using someLib></#list>  

However, target node is optional in the recurse directive. If the target node is unspecified, it simply uses the .node. Thus, the instruction <#recurse> is equivalent to:

<#list .node?children as child><#visit child></#list>  

Note for those familiar with XSLT: <#recurse> is analogous to the <xsl:apply-templates/> instruction in XSLT.

fallback

The user-defined directive that handles the node may be searched in multiple RPL namespaces. The fallback directive can be used in a user-defined directive that was invoked to handle a node. It directs RPL to continue searching for the user-defined directive in further namespaces (that is, in the name spaces that are after the namespace of the currently invoked user-defined directive in the list of namespaces). If a handler for the node is found then it is invoked; otherwise fallback does nothing.

Typical usage of this to write a customization layer over a handler library that sometimes passes the handling to the customized library:

<#import "docbook.htm" as docbook>
 
<#--
  We use the docbook library, but we override some handlers
  in this namespace.
-->
<#visit document using [.namespace, docbook]>
 
<#--
  Override the "programlisting" handler, but only in the case if
  its "role" attribute is "java"
-->
<#macro programlisting>
  <#if .node.@role[0]!"" == "java">
    <#-- Do something special here... -->
    ...
  <#else>
    <#-- Just use the original (overidden) handler -->
    <#fallback>
  </#if>
</#macro>