Namespaces

The set of variables created in the template with the assign and macro directives and the data from data sources is called a namespace. A namespace is a multi-level structure that uses hashes to store values and other hashes.

Normally, you use only the main namespace. Multiple name spaces are used if you are building a reusable collection of macros, functions and other variables (known as a library). You should use a separate namespace for each library. This is to avoid name clashes in cases when you have a big collection of macros that you use in several projects or want to share with others. In such cases, it is impossible ensure that the library does not have a macro (or other variable) with the same name as a variable in the data model or in another library used in the template.

Creating a library

This section uses examples to illustrate how to create a library.

Assume you commonly need the variables copyright and mail. The following example creates those variables:

<#macro copyright date>
  <p>Copyright (C) ${date} Julia Smith. All rights reserved.</p>
</#macro>
 
<#assign mail = "jsmith@acme.com">  

These variables are stored in the file /contentlibrary/lib/my_test.htm , in the same directory as the templates.

Assume you want to use this in content.htm. If you use <#include "cms://contentlibrary/lib/my_test.htm"> in content.htm, it will create the two variables in the main namespace. Instead, you want to create these variables in a namespace that is used exclusively by the library. To do this, use the import directive instead of the include directive. import is similar to include, but it will create an empty namespace for /contentlibrary/lib/my_test.htm and execute the macro there. The new namespace will include only the variables of the data model (since they are visible from everywhere), and the two variables from the macro. import also creates a new hash variable in the namespace used by the caller of import (in this case,  content.htm , which uses the main namespace). The hash variable provides content.htm access to the new namespace and its variables.content.htm will look like the following example:

<#import "cms://contentlibrary/lib/my_test.htm" as my> <#-- the hash called "my" will provide access to the namespace -->
<@my.copyright date="1999-2002"/>
${my.mail}  

Note how the files accesses the variables in the namespace created for /contentlibrary/lib/my_test.htm using the newly created hash my. The above example will produce this output:

  <p>Copyright (C) 1999-2002 Julia Smith. All rights reserved.</p>
jsmith@acme.com  

If you have a variable called mail or copyright in the main namespace, that would not cause any confusion, since the two templates use separated namespaces. For example, if you modify the copyright macro in /contentlibrary/lib/my_test.htm:

<#macro copyright date>
  <p>Copyright (C) ${date} Julia Smith. All rights reserved.
  <br>Email: ${mail}</p>
</#macro>  
 
<#assign mail = "jsmith@acme.com">  

and then replace content.htm with:

<#import "cms://contentlibrary/lib/my_test.htm" as my>
<#assign mail="fred@acme.com">
<@my.copyright date="1999-2002"/>
${my.mail}
${mail}  

the output is:

  <p>Copyright (C) 1999-2002 Julia Smith. All rights reserved.
  <br>Email: jsmith@acme.com</p>
jsmith@acme.com
fred@acme.com  

This is because when you called the copyright macro, RPL temporarily switched to the namespace that was created by the import directive for /contentlibrary/lib/my_test.htm. Thus, the copyright macro always sees the mail variable that exists there, and not the mail variable that exists in the main namespace.

Writing the variables of imported namespaces

Occasionally, you might want to create or replace a variable in an imported namespace. You can do this with the assign directive with the namespace parameter. For example, the following code:

<#import "/lib/my_test.RPL" as my>
${my.mail}
<#assign mail="jsmith@other.com" in my>
${my.mail}  

produces this output:

jsmith@acme.com
jsmith@other.com  

Namespaces and the data model

The variables of the data model defined in the datasources and campaign variables are visible from everywhere. For example, if you have a field/variable called user in the data model, /contentlibrary/lib/my_test.htm will access that, exactly as content.htm does:

<#macro copyright date>
  <p>Copyright (C) ${date} ${user}. All rights reserved.</p>
</#macro>
 
<#assign mail = "${user}@acme.com">  

If user is “Fred”, the following example:

<#import "cms://contentlibrary/lib/my_test.htm" as my>
<@my.copyright date="1999-2002"/>
${my.mail}  

produces this output:

  <p>Copyright (C) 1999-2002 Fred. All rights reserved.</p>
Fred@acme.com  

The variables in the namespace (the variables you create with assign or macro directives) have precedence over the variables of the data model when you are in that namespace. Thus, the content of the data model does not interfere with the variables created by the library.

NOTE: In some unusual situations, you might need to create variables in the template that are visible from all namespaces. Although you cannot change the data model with templates, you can achieve this with the global directive. For more information about the global directive, see Directive Reference.

Namespace lifecycle

A namespace is identified by the path that was used with the import directive. If you try to import multiple times with the same path, the directive will create the namespace and run the template specified by the path only for the very first invocation of import. The later imports with the same path will only create a  hash in the same namespace. For example, if content.htm is :

<#import "/contentlibrary/lib/my_test.htm" as my>
<#import "/contentlibrary/lib/my_test.htm" as foo>
<#import "/contentlibrary/lib/my_test.htm" as bar>
${my.mail}, ${foo.mail}, ${bar.mail}
<#assign mail="jsmith@other.com" in my>
${my.mail}, ${foo.mail}, ${bar.mail}  

The output is this, since my, foo and bar provide access to the same namespace:

jsmith@acme.com, jsmith@acme.com, jsmith@acme.com
jsmith@other.com, jsmith@other.com, jsmith@other.com  

Note that namespaces are not hierarchical, they exist independently of each other. That is, if you import namespace N2 while in name space N1, N2 will not be inside N1. Instead, N1 gets a hash by which it can access N2. This is the same N2 namespace that you would access if you import N2 while in the main namespace.

Each template processing job has its own private set of namespaces. Each template processing job exists only while the given page is being rendered.

NOTE: When namespaces are used during a launch, they are not preserved across multiple recipients. Namespaces are recreated for each record.

Making a library available to others

You can share a library by making it available in the Content Library. To prevent clashes with the names of libraries used by other authors, and to make it easy to write libraries that import other published libraries, there is a de-facto standard that specifies the format of library paths.

The standard is that the library must be available (importable) for templates and other libraries with a path like this:

/contentlibrary/lib/your_library.htm

For example, if you develop a widget library, then the path of the RPL file to import should be:

/contentlibrary/lib/ widget.htm

IMPORTANT: The path must not contain upper-case letters. To separate words, use _, as in wml_form (not wmlForm).

These are “best-practice” recommendations.  The system will allow other standards.

 

Handling white space

The control of white space in a template is a problem that to some extent haunts every template engine.

In the following example, we marked the components of the template with colors: text, interpolation, RPL tag. With the [BR]-s represent the line breaks.

<p>List of users:[BR]
<#assign users = [{"name":"Joe",        "hidden":false},[BR]
                  {"name":"James Bond", "hidden":true},[BR]
                  {"name":"Julia",      "hidden":false}]>[BR]
<ul>[BR]
<#list users as user>[BR]
  <#if !user.hidden>[BR]
  <li>${user.name}[BR]
  </#if>[BR]
</#list>[BR]
</ul>[BR]
<p>That's all.  

If RPL were to output all text as is, the output would be:

<p>List of users:[BR]
[BR]
<ul>[BR]
[BR]
  [BR]
  <li>Joe[BR]
  [BR]
[BR]
  [BR]
[BR]
  [BR]  
  <li>Julia[BR]
  [BR]
[BR]
</ul>[BR]
<p>That's all.  

This output contains a lot of unwanted spaces and line breaks.

To resolve this problem, RPL provides the tools described in this section.

To ignore certain white space, you can use one of the following methods:

White space stripping
This method automatically ignores typical superfluous white space around RPL tags. It can be enabled or disabled for each template. For more information, see “Stripping white space” later in this section.

Trimmer directives
You can use the following trimmer directives: t, rt, lt, join. With these directives, you can explicitly instruct RPL to ignore certain type of white space. For more information, see Directive Reference.

RPL parameter strip_text
This removes all top level text from the template. It is useful for templates that contain only macro definitions and other directives that do not produce output. This parameter removes the line breaks between the macro definitions and between other top level directives to improve readability of the template.

To remove white space from output, you can use the compress and join directives. For more information, see “Using the compress directive” later in this section.

Stripping white space

If this feature is enabled for a template, the following types of white space are automatically ignored:

Indentation white space, and trailing white space at the end of the line
Indentation and trailing white space, including line breaks, will be ignored in lines that contains only RPL tags and/or RPL comments. For example, if a line contains only an <#if ...>, then the indentation before the tag and the line break after the tag will be stripped. However, if the line contains <#if ...>x, the white space in that line will not be stripped, because the x is not an RPL tag. Note that white space is stripped in a line that contains <#if ...><#list ...>, but not in a line that contains <#if ...> <#list ...>. This is because the white space between the two RPL tags is embedded white space, not indentation or trailing white space.

White space between the macro, function, assign, global, local, rpl, and import directives
With these directives, white space is stripped if there is only white space and/or RPL comments between the directives. This means that you can put empty lines between macro definitions and assignments as spacing for better readability, without printing needless empty lines. For example, white space will be stripped in the following template, except in the highlighted line:

<p>List of users:[BR]
<#assign users = [{"name":"Joe",        "hidden":false},
                  {"name":"James Bond", "hidden":true},
                  {"name":"Julia",      "hidden":false}]>
<ul>[BR]
<#list users as user>
  <#if !user.hidden>
  <li>${user.name}[BR]
  </#if>
</#list>
</ul>[BR]
<p>That's all.  

produces this output:

<p>List of users:[BR]
<ul>[BR]
  <li>Joe[BR]
  <li>Julia[BR]
</ul>[BR]
<p>That's all.  

Note that enabling white space stripping does not degrade the performance of template execution because white space stripping is done during template loading.

You can enable or disable white space stripping for a template using the rpl directive. If you do not specify this with the rpl directive, white space stripping will be enabled.

You can enable or disable white space stripping for a single line using the nt directive.

Using the compress directive

The compress directive works on the generated output, not on the template. The directive inspects the output and removes indentations, empty lines and repeated spaces/tabs. For example:

<#compress>
<#assign users = [{"name":"Joe",        "hidden":false},
                  {"name":"James Bond", "hidden":true},
                  {"name":"Julia",      "hidden":false}]>
List of users:
<#list users as user>
  <#if !user.hidden>
  - ${user.name}
  </#if>
</#list>
That's all.
</#compress>  

produces this output:

List of users:
- Joe
- Julia
That's all.  

Note that compress works independently of white space stripping. So it is possible that the white space of template is stripped, and later the produced output is compressed.

By default, a user-defined directive called compress is available in the data model. This is the same as the pre-defined directive, except that you may optionally set the single_line parameter, which will remove all intervening line breaks. If you replace <#compress>...</#compress> in the last example with <@compress single_line=true>...</@compress>, you will get this output:

List of users: - Joe - Julia That's all.  

For more information about the compress directive, see Directive Reference.

Learn more

Namespace Reference

Directive Reference

Templates