blob: dc6f0808e19b9ecb609b246ec24ce72d090649ca [file] [log] [blame]
 FreeMarker Manual Manual Freemarker 2.3.23 What's FreeMarker? FreeMarker is a template engine: a generic tool to generate text output (HTML web pages, e-mails, configuration files, source code, etc.) based on templates and changing data. It's not an application for end-users in itself, but a Java library, a component that programmers can embed into their products. Templates are written in the FreeMarker Template Language (FTL). It's a simple, specialized language, not a full-blown programming language like PHP. You meant to prepare the data to display in a real programming language, like issue database queries and do business calculations, and then the template displays that already prepared data. In the template you are focusing on how to present the data, and outside the template you are focusing on what data to present. This approach is often referred to as the MVC (Model View Controller) pattern, and is particularly popular for dynamic Web pages. It helps in separating the Web page designers (HTML authors) from the developers (Java programmers usually). Designers won't face complicated logic in templates, and can change the appearance of a page without programmers having to change or recompile code. While FreeMarker was originally created for generating HTML pages in MVC web application frameworks, it isn't bound to servlets or HTML or anything Web-related. It's used in non-web application environments as well. FreeMarker is Free, released under the Apache License, Version 2.0. Template Author's Guide Getting Started This chapter is a very rough introduction to FreeMarker. The chapters after this will go over things in much greater detail. Nonetheless, once you have read this chapter, you will be able to write simple but useful FreeMarker templates.
Template + data-model = output Let's assume that you need a HTML page in a Web shop, similar to this: <html> <head> <title>Welcome!</title> </head> <body> <h1>Welcome John Doe!</h1> <p>Our latest product: <a href="products/greenmouse.html">green mouse</a>! </body> </html> But the user name ("John Doe" above) should depend on who the logged in Web page visitor is, and the latest product should come from a database and thus it potentially changes too. Thus you can't enter these into the HTML directly, you can't use static HTML. Instead, you can use a template of the desired output. The template is the same as the static HTML would be, except that it contains some instructions to FreeMarker that makes it dynamic: <html> <head> <title>Welcome!</title> </head> <body> <h1>Welcome ${user}!</h1> <p>Our latest product: <a href="${latestProduct.url}">${latestProduct.name}</a>! </body> </html> The template is stored on the Web server, usually just like the static HTML page would be. But whenever someone visits this page, FreeMarker will step in and transform the template on-the-fly to plain HTML by replacing the${...}-s with up-to-date content, and send the result to the visitor's Web browser. So the visitor's Web browser will receive something like the first example HTML (i.e., plain HTML without FreeMarker instructions), and it will not perceive that FreeMarker is used on the server. (Of course, the template file stored on the Web server is not changed by this; the substitutions only appear in the Web server's response.) Note that the template doesn't contain the programming logic to find out who the current visitor is, or to query the database to get the latest product. The data to be displayed is prepared outside FreeMarker, usually by parts written in some real programming language like Java. The template author needn't know how these values were calculated. In fact, the way these values are calculated can be completely changed while the templates can remain exactly the same, and also, the look of the page can be completely changed without touching anything but the template. This separation of presentation logic and business logic can be especially useful when the template authors (designers) and the programmers are different individuals, but also helps managing application complexity if they are the same person. Keeping templates focused on presentation issues (visual design, layout and formatting) is a key for using template engines like FreeMarker efficiently. data-model The totality of data that was prepared for the template is called the data-model. As far as the template author is concerned, the data-model is a tree-like structure (like folders and files on your hard disk), which, in this case, could be visualized as: (root) | +- user = "Big Joe" | +- latestProduct | +- url = "products/greenmouse.html" | +- name = "green mouse" The above is just a visualization; the data-model is not in a textual format, it's from Java objects. For the Java programmers, the root is perhaps a Java object with getUser() and getLatestProduct() methods, or maybe a Java Map with "user" and "latestProducts" keys. Similarly, latestProduct is perhaps a Java Object with getUrl() and getName() methods. Earlier, you have picked values from this data-model, with the user and latestProduct.name expressions. If we go on with the analogy that the data model is like a file system, then (root) and latestProduct correspond to directories (folders), and user, url and name are files in those directories. To recapitulate, a template and a data-model is needed for FreeMarker to generate the output (like the HTML shown first): Template + data-model = output
The data-model at a glance As you have seen, the data-model is basically a tree. This tree can be arbitrarily complicated and deep, for example: (root) | +- animals | | | +- mouse | | | | | +- size = "small" | | | | | +- price = 50 | | | +- elephant | | | | | +- size = "large" | | | | | +- price = 5000 | | | +- python | | | +- size = "medium" | | | +- price = 4999 | +- message = "It is a test" | +- misc | +- foo = "Something" The variables that act like directories (the root, animals, mouse, elephant, python, misc) are called hashes. Hashes store other variables (the so called sub variables) by a lookup name (e.g., animals, mouse or price). The variables that store a single value (size, price, message and foo) are called scalars. When you want to use a subvariable in a template, you specify its path from the root, and separate the steps with dots. To access the price of a mouse, you start from the root and go into animals, and then go into mouse then go into price. So you write animals.mouse.price. Another important kind of variables are sequences. They store subvariables like hashes, but here subvariables doesn't have a name, they are just items in a list. For example, in this data-model, animals and misc.fruits are sequences: (root) | +- animals | | | +- (1st) | | | | | +- name = "mouse" | | | | | +- size = "small" | | | | | +- price = 50 | | | +- (2nd) | | | | | +- name = "elephant" | | | | | +- size = "large" | | | | | +- price = 5000 | | | +- (3rd) | | | +- name = "python" | | | +- size = "medium" | | | +- price = 4999 | +- misc | +- fruits | +- (1st) = "orange" | +- (2nd) = "banana" To access a subvariable of a sequence you use a numerical index in square brackets. Indexes start from 0 (it's a programmer tradition to start with 0), thus the index of the 1st item is 0, the index of the 2nd item is 1, and so on. So to get the name of the first animal you write animals[0].name. To get the second item in misc.fruits (the string "banana") you write misc.fruits[1]. (In practice, you usually just walk through sequences in order, not caring about the index, but that will be shown later.) Scalars can be further divided into these categories: String: Text, that is, an arbitrary sequence of characters such as ''m'', ''o'', ''u'', ''s'', ''e'' above. For example the name-s and size-s are strings above. Number: It's a numerical value, like the price-s above. The string "50" and the number 50 are two totally different things in FreeMarker. The former is just a sequence of two characters (which happens to be readable as a number for humans), while the latter is a numerical value that you can use in arithmetical calculations. Date-like: Either a date-time (stores a date with time of the day), or a date (no time of day), or a time (time of day, no date). Boolean: A true/false (yes/no, on/off, etc.) thing. Like animals could have a protected subvariable, which store if the animal is protected or not. Summary: The data-model can be visualized as a tree. Scalars store a single value. The value can be a string or a number or a date-time/date/time or a boolean. Hashes are containers that store other variables and associate them with a unique lookup name. Sequences are containers that store other variables in an ordered sequence. The stored variables can be retrieved via their numerical index, starting from 0. There are other, more advanced value types that we don't cover here, such as methods and directives.
The template at a glance The simplest template is a plain HTML file (or whatever text file; FreeMarker is not confined to HTML). When the client visits that page, FreeMarker will send that HTML to the client as is. However if you want that page to be more dynamic then you begin to put special parts into the HTML which will be understood by FreeMarker: ${...}: FreeMarker will replace it in the output with the actual value of the expression inside the curly brackets. They are called interpolations. FTL tags (for FreeMarker Template Language tags): FTL tags are a bit similar to HTML tags, but they are instructions to FreeMarker and will not be printed to the output. The name of these tags start with #. (User-defined FTL tags use @ instead of #, but they are an advanced topic.) Comments: Comments are similar to HTML comments, but they are delimited by <#-- and -->. Unlike HTML comments, FTL comments won't get into the output (won't be visible in the page source for the visitor), because FreeMarker skips them. Anything not an FTL tag or an interpolation or comment is considered as static text, and will not be interpreted by FreeMarker; it is just printed to the output as is. With FTL tags you refer to so-called directives. This is the same kind of relationship as between HTML tags (e.g.: <table> and </table>) and HTML elements (e.g., the table element) to which you refer to with the HTML tags. (If you don't feel this difference then just take "FTL tag" and "directive" as synonyms.) You can easily try writing templates on http://freemarker-online.kenshoo.com/ Some basic directives Here we will look at some of the most commonly used directives (but there are much more). The if directive With the if directive you can conditionally skip a section of the template. For example, assume that in the very first example you want to greet your boss, Big Joe, differently than other users: <html> <head> <title>Welcome!</title> </head> <body> <h1> Welcome${user}<#if user == "Big Joe">, our beloved leader</#if>! </h1> <p>Our latest product: <a href="${latestProduct.url}">${latestProduct.name}</a>! </body> </html> Here you have told FreeMarker that the , our beloved leader should be there only if the value of the variable user is equal to the string "Big Joe". In general, things between <#if condition> and </#if> tags are skipped if condition is false (the boolean value). Let's look at condition more closely: == is an operator that tests if the values at its left and right side are equivalent, and the results is a boolean value, true or false accordingly. On the left side of == I have referenced a variable with the syntax that should be already familiar; this will be replaced with the value of the variable. In general, unquoted words inside directives or interpolations are treated as references to variables. On the right side I have specified a literal string. Literal strings in templates must always be put inside quotation marks. This will print Pythons are free today! if their price is 0: <#if animals.python.price == 0> Pythons are free today! </#if> Similarly as earlier when a string was specified directly, here a number is specified directly (0). Note that the number is not quoted. If you quoted it ("0"), FreeMarker were misinterpret it as a string literal, and because the price to compare it to is number, you get an error. This will print "Pythons are not free today!" if their price is not 0: <#if animals.python.price != 0> Pythons are not free today! </#if> As you probably guessed, != means not equals. You can write things like this too (using the data-model used to demonstrate hashes): <#if animals.python.price < animals.elephant.price> Pythons are cheaper than elephants today. </#if> With the <#else> tag you can specify what to do if the condition is false. For example: <#if animals.python.price < animals.elephant.price> Pythons are cheaper than elephants today. <#else> Pythons are not cheaper than elephants today. </#if> This prints Pythons are cheaper than elephants today. if the price of python is less than the price of elephant, or else it prints Pythons are not cheaper than elephants today. You can refine this further by using elseif: <#if animals.python.price < animals.elephant.price> Pythons are cheaper than elephants today. <#elseif animals.elephant.price < animals.python.price> Elephants are cheaper than pythons today. <#else> Elephants and pythons cost the same today. </#if> If you have a variable with boolean value (a true/false thing) then you can use it directly as the condition of if: <#if animals.python.protected> Pythons are protected animals! </#if>
The list directive This is needed when you want to list something. For example if you merge this template with the data-model used earlier to demonstrate sequences: <p>We have these animals: <table border=1> <#list animals as animal> <tr><td>${animal.name}<td>${animal.price} Euros </#list> </table> then the output will be: <p>We have these animals: <table border=1> <tr><td>mouse<td>50 Euros <tr><td>elephant<td>5000 Euros <tr><td>python<td>4999 Euros </table> The generic form of the list directive is: <#list sequence as loopVariable>repeatThis</#list>. The repeatThis part will be repeated for each item in the sequence that you have specified with sequence, one after the other, starting from the first item. In all repetitions loopVariable will hold the value of the current item. This variable exists only between the <#list ...> and </#list> tags. The sequence can be any kind of expression, like we could list the fruits of the example data model like this: <ul> <#list misc.fruits as fruit> <li>${fruit} </#list> </ul> The misc.fruits expression should be familiar to you; it references a variable in the data-model. A problem with the above example is that if we happen to have 0 fruits, it will still print an empty <ul></ul> instead of just nothing. To avoid that, you can use this form of list: <#list misc.fruits> <ul> <#items as fruit> <li>${fruit} </#items> </ul> </#list> Here, the list directive represents the listing as a whole, and only the part inside the items directive is repeated for each fruit. If we have 0 fruits, everything inside list is skipped, hence we will not have ul tags in case. Another frequent listing-related task: let's list the fruits separating them with something, like comma: <p>Fruits: <#list misc.fruits as fruit>${fruit}<#sep>, </#list> <p>Fruits: orange, banana The section covered by sep (which we could be written like this too: ...<#sep>, </#sep></#list>) will be only executed when there will be a next item. Hence there's no comma after the last fruit. Here again, what's if we have 0 fruits? Just printing Fruits: and then nothing is awkward. A list, just like an if, can have an else, which is executed if there were 0 list items: <p>Fruits: <#list misc.fruits as fruit>${fruit}<#sep>, <#else>None</#list> As a matter of fact, this simplistic example could be written like this, but it uses language devices that are off topic here: <p>Fruits: ${fruits?join(", ", "None")} All these directives (list, items, sep, else) can be used together: <#list misc.fruits> <p>Fruits: <ul> <#items as fruit> <li>${fruit}<#sep> and</#sep> </#items> </ul> <#else> <p>We have no fruits. </#list> You can read more about these directives in the Reference.
Using directives together You can use directives as many times on a page as you want, and you can nest directives into each other freely. For example, here you nest if directive inside a list directive: <#list animals as animal> <div<#if animal.protected> class="protected"</#if>> ${animal.name} for${animal.price} Euros </div> </#list> Note that since FreeMarker does not interpret text outside FTL tags, interpolations and FTL comments, above you could use the FTL tags inside a HTML attributes without problem.
Using built-ins The so called built-ins are like subvariables (or rather like methods, if you know that Java term) that aren't coming coming from the data-model, but added by FreeMarker to the values. To make it unambiguous where the subvarable comes from, to access them you have to use ? (question mark) instead of . (dot). Examples with some of the most commonly used built-ins: user?html gives the HTML-escaped version of user, like & will be replaced with &amp; user?upper_case gives the upper case version of the value of user (like JOHN DOE instead of John Doe) animal.name?cap_first give the animal.name with its first letter converted to upper case (like Mouse instead of mouse) user?length gives the number of characters in the value of user (8 for John Doe) animals?size gives the number of items in the animals sequence (3 in our example data-model) If you are between <#list animals as animal> and the corresponding </#list> tag: animal?index gives the 0-based index of animal inside animals animal?counter is like index, but gives the 1-based index animal?item_parity gives the strings odd or even, depending on the current counter parity. This is commonly used for coloring rows with alternating colors, like in <td class="${animal?item_parity}Row">. Some built-ins require parameters to specify the behavior more, for example: animal.protected?string("Y", "N") return the string Y or N depending on the boolean value of animal.protected. animal?item_cycle('lightRow', 'darkRow') is the more generic variant of item_parity from earlier. fruits?join(", "): converts the list to a string by concatenating items, and inserting the parameter separator between each items (like orange, banana) user?starts_with("J") gives boolean true of false depending on if user starts with the letter J or not. Built-in applications can be chained, like user?upper_case?html will first convert the user name to upper case, then HTML-escapes it. (This is just like you can chain .-s (dots) too.) You can find the full set of built-ins in the Reference. Dealing with missing variables The data-model often has variables that are optional (i.e., sometimes missing). To spot some typical human mistakes, FreeMarker doesn't tolerate the referring to missing variables, unless you tell explicitly what to do if the variable is missing. Here we will show the two most typical ways of doing that. Note for programmers: A non-existent variable and a variable with null value is the same for FreeMarker, so the "missing" term used here covers both cases. Wherever you refer to a variable, you can specify a default value for the case the variable is missing, by following the variable name with a ! and the default value. Like in the following example, when user is missing from data model, the template will behave like if user's value were the string "visitor". (When user isn't missing, this template behaves exactly like with${user}): <h1>Welcome ${user!"visitor"}!</h1> You can ask whether a variable isn't missing by putting ?? after its name. Combining this with the already introduced if directive you can skip the whole greeting if the user variable is missing: <#if user??><h1>Welcome${user}!</h1></#if> Regarding variable accessing with multiple steps, like animals.python.price, writing animals.python.price!0 is correct only if animals.python is never missing and only the last subvariable, price, is possibly missing (in which case here we assume it's 0). If animals or python is missing, the template processing will stop with an "undefined variable" error. To prevent that, you have to write (animals.python.price)!0. In that case the expression will be 0 even if animals or python is missing. Same logic goes for ??; animals.python.price?? versus (animals.python.price)??.
Values, Types
Basics It is assumed that you have already read the chapter. Understanding the concept of values and types is crucial for the understanding of data-models. However, the concept of values and types is not confined to data-models, as you will see.
What is a value? value Real programmers can safely skip this section. Examples of values as you know the term from the everyday math are 16, 0.5, and so on, i.e. numbers. In the case of computer languages the value term has a wider meaning, as a value needn't be a number. For example, take this data-model: (root) | +- user = "Big Joe" | +- today = Jul 6, 2007 | +- todayHoliday = false | +- lotteryNumbers | | | +- (1st) = 20 | | | +- (2st) = 14 | | | +- (3rd) = 42 | | | +- (4th) = 8 | | | +- (5th) = 15 | +- cargo | +- name = "coal" | +- weight = 40 We say that the value of the the user variable is "Big Joe" (a string), the value of today is Jul 6, 2007 (a date), the value of todayHoliday is false (a boolean, ie. a yes/no thing). The value of lotteryNumbers is the sequence that contains 20, 14, 42, 8, 15. Surely lotteryNumbers is multiple values in the sense that it contains multiple values (for example, the 2nd item in it is a the value 14), but still, lotteryNumbers itself is a single value. It's like a box that contains many other items; the whole box can be seen as a single item. Last not least we also have the value of cargo, which is a hash (a box-like thing again).So, a value is something that can be stored in a variable (e.g., in user or cargo or cargo.name). But a value need not be stored in a variable to be called a value, for example we have the value 100 here: <#if cargo.weight < 100>Light cargo</#if> The temporaly result of a calculations are also called values, like 20 and 120 when this template is executed (it will print 120): ${cargo.weight / 2 + 100} Explanation for this last: As the result of dividing the two values, 40 (the weight of the cargo) and 2, a new value 20 is created. Then 100 is added to it, so the value 120 is created. Then 120 is printed (${...}), and the template execution goes on and all these values gone. Certainly now you feel what the value term means.
What is type? Values have an important aspect, their type. For example the type of the value of the user variable is string, and the type of the value of the lotteryNumbers variable is sequence. The type of a value is important because it determines to a large extent how and where you can use the value. Like ${user / 2} is an error, but${cargo.weight / 2} works and prints 20, since division only does make sense for a number, but not for a string. Or, using dot like in cargo.name does make sense only if cargo is a hash. Or, you can list with <#list ...> sequences only. Or, the condition of <#if ...> must be a boolean. And so on. A little terminology... Saying "a boolean" or "a boolean value" or "a value of type boolean" are all the same. Multi-typed value A value can have multiple types at the same time, although it's rarely utilized. For example in the data-model below mouse is both a string and a hash: (root) | +- mouse = "Yerri" | +- age = 12 | +- color = "brown" If you merge this template with the above data-model: ${mouse} <#-- uses mouse as a string -->${mouse.age} <#-- uses mouse as a hash --> ${mouse.color} <#-- uses mouse as a hash --> the output will be: Yerri 12 brown The data-model is a hash Looking at the various data-model examples you may already realized: the thing marked as "(root)" is just a value of type hash. When you write something like user, that means that you want the "user" variable stored in the root hash. Like if you were writing root.user, except that there is no variable called "root" so that wouldn't work. Some may get confused by the fact that our example data-model, that is, the root hash, contains further hashes and sequences (lotteryNumbers and cargo). There is nothing special in that. A hash contains other variables, and those variables have a value, which can be a string, a number, etc., and of course it can be a hash or sequence as well. Because, as it was explained earlier, a sequence or a hash is just a value, like a string or a number is. The types The suppored types are: Scalars: String Number Boolean Date-like (date, time, or date-time) Containers: Hash Sequence Collection Subroutines: Methods and functions User-defined directives Miscellaneous/seldom used: Node Scalars These are the basic, simple kind of values. They can be: string the FTL value type String: It is simple text, e.g., the name of a product. If you want to give a string value directly in the template, rather than use a variable that comes from the data model, you write the text between quotation marks, e.g., "green mouse" or 'green mouse'. (More details regarding the syntax can be found later.) number the FTL value type Number: For example the price of a product. Whole numbers and non-whole numbers are not distinguished; there is only a single number type. So for example 3/2 will be always 1.5, and never 1. Just like if you are using a calculator. If you want to give a numerical value directly in the template, then you write for example: 150 or -90.05 or 0.001. (More details regarding the syntax can be found later.) boolean the FTL value type Boolean: A boolean value represents a logical true or false (yes or no). For example, if a the visitor has been logged in or not. Typically you use booleans as the condition of the if directive, like <#if loggedIn >...</#if> or <#if price == 0>...</#if>; in the last case the result of the price == 0 part is a boolean value. In the templates you can directly specify a boolean with the reserved words true and false. date the FTL value type time the FTL value type date-time the FTL value type Date: A date-like value stores date/time related data. It has three variations: Date: Like April 4, 2003. Day precision, no time of day part. Time: Like 10:19:18 PM. Millisecond precision, no date part. Date-time (sometimes called "time stamp") as April 4, 2003 10:19:18 PM. Both date and time, with millisecond precision. Unfortunately, because of the limitations of the Java platform, FreeMarker sometimes can't decide which parts of the date are in use (i.e., if it is date-time, a date or a time). The solution for this problem is an advanced topic that will be discussed later. It is possible to define date-like values directly in templates, but this is an advanced topic that will be explained later. Bear in mind that FreeMarker distinguishes strings from numbers, booleans and date-like values. For example, while the string "150" looks like the number 150, a string is still just arbitrary sequence of characters, and you can't do arithmetic with it, can't compare it with another number, etc. Containers Re-explanation of hashes and sequences from a more ''professional'' viewpoint as earlier, and some meditation about them. These are the values whose purpose is to contain other variables; they are just containers. The contained variables are often referred as sub variables. The container types are: hash the FTL value type Hash: Associates a unique lookup name with each of its sub variables. The name is an unrestricted string. A hash doesn't define an ordering for the sub variables in it. That is, there is no such thing as the first subvariable, and the second subvariable, etc.; the variables are just accessed by name. sequence the FTL value type Sequence: Associates an integer number with each of its sub variables. The first subvariable is associated with 0, the second with 1, the third to 2, and so on; the sub variables are ordered. These numbers are often called the indexes of the sub variables. Sequences are usually dense, i.e., all indexes up to the index of the last subvariable have an associated subvariable, but it's not strictly necessary. The type of the subvariable values need not be the same. collection the FTL value type Collection: A collection, from the viewpoint of the template author, is a restricted sequence. You cannot access its size or retrieve its sub variables by index, but they can be still listed with the list directive. Note that since a value can have multiple types, it is possible for a value to be both a hash and a sequence, in which case it would support index-based access as well as access by lookup name. However, typically a container will be either a hash or a sequence, not both. As the value of the variables stored in hashes and sequences (and collections) can be anything, it can be a hash or sequence (or collection) as well. This way you can build arbitrarily deep structures. The data-model itself (or better said the root of it) is a hash. Subroutines Methods and functions method the FTL value type A value that is a method or a function is used to calculate another value, influenced by the parameters you give to it. For programmer types: Methods/functions are first-class values, just like in functional programming languages. This means that functions/methods can be the parameters or return values of other functions/methods, you can assign them to variables, and so on. Suppose that programmers have put the method variable avg in the data-model that can be used to calculate the average of numbers. If you give the 3 and 5 as parameters when you access avg, then you get the value 4. The usage of methods will be explained later, but perhaps this example helps to understand what methods are: The average of 3 and 5 is:${avg(3, 5)} The average of 6 and 10 and 20 is: ${avg(6, 10, 20)} The average of the price of a python and an elephant is:${avg(animals.python.price, animals.elephant.price)} this will output: The average of 3 and 5 is: 4 The average of 6 and 10 and 20 is: 12 The average of the price of a python and an elephant is: 4999.5 What is the difference between a method and a function? As far as the template author is concerned, nothing. Well not really nothing, as methods typically come from the data-model (as they reflect the methods of Java objects), and functions are defined in templates (with the function directive -- an advanced topic), but both can be used on the same way.
User-defined directives macro the FTL value type directive the FTL value type user-defined directive the FTL value type A value of this type can be used as user-defined directive (with other words, as FreeMarker tag). An user-defined directive is a subroutine, something like a little reusable template fragment. But this is an advanced topic that will be explained later in its own chapter. For programmer types: user-defined directives (such as macros), are first-class values too, just like functions/methods are. Just to get an idea about user-defined directives (so just ignore this if you won't understand), assume we have a variable, box, whose value is a user-defined directive that prints some kind of fancy HTML message box with a title bar and a message in it. The box variable could be used in the template like this (for example): <@box title="Attention!"> Too much copy-pasting may leads to maintenance headaches. </@box>
Function/method versus user-defined directive This is for advanced users again (so ignore it if you don't understand). It's a frequent dilemma if you should use a function/method or an user-defined directive to implement something. The rule of thumb is: Implement the facility as user-defined directive instead of as function/method if: ... the output (the return value) is markup (HTML, XML, etc.). The main reason is that the result of functions are subject to automatic XML-escaping (due to the nature of ${...}), while the output of user-defined directives are not (due to the nature of <@...>; its output is assumed to be markup, and hence already escaped). ... it's the side-effect that is important and not the return value. For example, a directive whose purpose is to add an entry to the server log is like that. (In fact you can't have a return value for a user-defined directive, but some kind of feedback is still possible by setting non-local variables.) ... it will do flow control (like for example list or if directives do). You just can't do that with a function/method anyway. The Java methods of FreeMarker-unaware Java objects are normally visible as methods in templates, regardless of the nature of the Java method. That said, you have no choice there. Miscellaneous Nodes node the FTL value type Node variables represent a node in a tree structure, and are used mostly with XML processing, which is an advanced, and specialized topic. Still, a quick overview for advanced users: A node is similar to a sequence that stores other nodes, which are often referred as the children nodes. A node stores a reference to its container node, which is often referred as the parent node. The main point of being a node is the topological information; other data must be stored by utilizing that a value can have multiple types. Like, a value may be both a node and a number, in which case it can store a number as the "pay-load". Apart from the topological information, a node can store some metainformation as well: a node name, a node type (string), and a node namespace (string). For example, if the node symbolizes a h1 element in an XHTML document, then its name could be "h1", it's node type could be "element", and it's namespace could be "http://www.w3.org/1999/xhtml". But it's up to the designer of the data-model if what meaning these metainformations have, and if they are used at all. The way of retrieving the topological and metainformations is described in a later chapter (that you don't have to understand at this point). The Template template It is assumed that you have already read the and the chapter. Overall structure Templates are in fact programs you write in a language called FTL FTL (for FreeMarker Template Language). This is a quite simple programming language designed for writing templates and nothing else. A template (= FTL program) is a mix of the following sections: Text text : Text that will be printed to the output as is. Interpolation interpolation : These sections will be replaced with a calculated value in the output. Interpolations are delimited by${ and } (or with #{ and }, but that shouldn't be used anymore; see more here). FTL tags FTL tag : FTL tags are a bit similar to HTML tags, but they are instructions to FreeMarker and will not be printed to the output. Comments comment <#--...--> # : Comments are similar to HTML comments, but they are delimited by <#-- and -->. Comments will be ignored by FreeMarker, and will not be written to the output. Let's see a concrete template. I have marked the template's components with colors: text, interpolation, FTL tag, comment. With the [BR]-s I intend to visualize the line breaks. <html>[BR] <head>[BR] <title>Welcome!</title>[BR] </head>[BR] <body>[BR] <#-- Greet the user with his/her name -->[BR] <h1>Welcome ${user}!</h1>[BR] <p>We have these animals:[BR] <ul>[BR] <#list animals as animal>[BR] <li>${animal.name} for ${animal.price} Euros[BR] </#list>[BR] </ul>[BR] </body>[BR] </html> FTL distinguishes upper case and lower case letters. So list is good directive name, while List is not. Similarly${name} is not the same as ${Name} or${NAME} It is important to realize that interpolations can be used in text (and in string literal expressions; see later) only. An FTL tag can't be inside another FTL tag nor inside an interpolation. For example this is WRONG: <#if <#include 'foo'>='bar'>...</#if> Comments can be placed inside FTL tags and interpolations. For example: <h1>Welcome ${user <#-- The name of user -->}!</h1>[BR] <p>We have these animals:[BR] <ul>[BR] <#list <#-- some comment... --> animals as <#-- again... --> animal>[BR] ... For those of you who have tried the above examples: You may notice that some of spaces, tabs and line breaks are missing from the template output, even though we said that text is printed as is. Don't bother with it now. This is because the feature called ''white-space stripping'' is turned on, and that automatically removes some superfluous spaces, tabs and line breaks. This will be explained later. Directives <#...> # Note that the Expressions chapter depends on this chapter, and Interpolations chapter depends on Expressions chapter. Thus Directives must be the first chapter after Basics. directive You use FTL tags to call directives. In the example you have called the list directive. Syntactically you have done it with two tags: <#list animals as animal> and </#list>. FTL tag There are two kind of FTL tags: Start-tag: <#directivename parameters> End-tag: </#directivename> This is similar to HTML or XML syntax, except that the tag name starts with #. If the directive doesn't have nested content (content between the start-tag and the end-tag), you must use the start-tag with no end-tag. For example you write <#if something>...</#if>, but just <#include something> as FreeMarker knows that the include directive can't have nested content. The format of the parameters depends on the directivename. In fact there are two types of directives: predefined directives and user-defined directives. For user-defined directives you use @ instead of #, for example <@mydirective parameters>...</@mydirective>. Further difference is that if the directive has no nested content, you must use a tag like <@mydirective parameters />, similarly as in XML (e.g. <img ... />). But user-defined directives is an advanced topic that will be discussed later. FTL tags, like HTML tags, must be properly nested. So the code below is wrong, as the if directive is both inside and outside of the nested content of the list directive: <ul> <#list animals as animal> <li>${animal.name} for ${animal.price} Euros <#if user == "Big Joe"> (except for you) </#list> <#-- WRONG! The "if" has to be closed first. --> </#if> </ul> Note that FreeMarker doesn't care about the nesting of HTML tags, only about the nesting of FTL tags. It just sees HTML as flat text, it doesn't interpret it in any way. If you try to use a non-existing directive (e.g., you mistype the directive name), FreeMarker will decline to use the template and produce an error message. FreeMarker ignores superfluous white-space inside FTL tags. So you can write this: <#list[BR] animals as[BR] animal[BR] >[BR]${animal.name} for ${animal.price} Euros[BR] </#list > You may not, however, insert white-space between the < or </ and the directive name. The complete list and description of all directives can be found in the (but I recommend that you look at the chapter about expressions first). FreeMarker can be configured to use [ and ] instead of < and > in the FTL tags and FTL comments, like [#if user == "Big Joe"]...[/#if]. For more information read: . FreeMarker can be configured so that it understands predefined directives without # (like <if user == "Big Joe">...</if>). However we don't recommend the usage of this mode. For more information read: Expressions expression When you supply values for interpolations or directive parameters you can use variables or more complex expressions. For example, if x is the number 8 and y is 5, the value of (x + y)/2 resolves to the numerical value 6.5. Before we go into details, let's see some concrete examples: When you supply value for interpolations: The usage of interpolations is${expression} where expression gives the value you want to insert into the output as text. So ${(5 + 8)/2} prints 6.5'' to the output (or possibly 6,5'' if the language of your output is not US English). When you supply a value for the directive parameter: You have already seen the if directive in the Getting Started section. The syntax of this directive is: <#if expression>...</#if>. The expression here must evaluate to a boolean value. For example in <#if 2 < 3> the 2 < 3 (2 is less than 3) is an expression which evaluates to true. Quick overview (cheat sheet) This is a reminder for those of you who already know FreeMarker or are just experienced programmers: Specify values directly Strings: "Foo" or 'Foo' or "It's \"quoted\"" or 'It\'s "quoted"' or r"C:\raw\string" Numbers: 123.45 Booleans: true, false Sequences: ["foo", "bar", 123.45]; Ranges: 0..9, 0..<10 (or 0..!10), 0.. Hashes: {"name":"green mouse", "price":150} Retrieving variables Top-level variables: user Retrieving data from a hash: user.name, user["name"] Retrieving data from a sequence: products[5] Special variable: .main String operations Interpolation (or concatenation): "Hello${user}!" (or "Hello " + user + "!") Getting a character: name[0] String slice: Inclusive end: name[0..4], Exclusive end: name[0..<5], Length-based (lenient): name[0..*5], Remove starting: name[5..] Sequence operations Concatenation: users + ["guest"] Sequence slice: Inclusive end: products[20..29], Exclusive end: products[20..<30], Length-based (lenient): products[20..*10], Remove starting: products[20..] Hash operations Concatenation: passwords + { "joe": "secret42" } Arithmetical calculations: (x * 1.5 + 10) / 2 - y % 100 Comparison: x == y, x != y, x < y, x > y, x >= y, x <= y, x lt y, x lte y, x gt y, x gte y, ...etc. Logical operations: !registered && (firstVisit || fromEurope) Built-ins: name?upper_case, path?ensure_starts_with('/') Method call: repeat("What", 3) Missing value handler operators: Default value: name!"unknown" or (user.name)!"unknown" or name! or (user.name)! Missing value test: name?? or (user.name)?? Assignment operators: =, +=, -=, *=, /=, %=, ++, -- See also: Operator precedence
Specify values directly literal constant Often you want to specify a value directly and not as a result of some calculations.
Strings string literal To specify a string value directly you give the text in quotation marks, e.g.: "some text" or in apostrophe-quote, e.g. 'some text'. The two forms are equivalent. If the text itself contains the character used for the quoting (either " or ') or backslashes, you have to precede them with a backslash; this is called escaping. You can type any other character, including line breaks, in the text directly. Example: ${"It's \"quoted\" and this is a backslash: \\"}${'It\'s "quoted" and this is a backslash: \\'} will print: It's "quoted" and this is a backslash: \ It's "quoted" and this is a backslash: \ Of course, you could simply type the above text into the template, without using ${...}. But we do it here just for the sake of example, to demonstrate expressions. escape sequences This is the list of all supported escape sequences. All other usage of backlash in string literals is an error and any attempt to use the template will fail. Escape sequence Meaning \" Quotation mark (u0022) \' Apostrophe (a.k.a. apostrophe-quote) (u0027) \{ Opening curly brace: { \\ Back slash (u005C) \n Line feed (u000A) \r Carriage return (u000D) \t Horizontal tabulation (a.k.a. tab) (u0009) \b Backspace (u0008) \f Form feed (u000C) \l Less-than sign: < \g Greater-than sign: > \a Ampersand: & \xCode Character given with its hexadecimal Unicode code (UCS code) The Code after the \x is 1 to 4 hexadecimal digits. For example this all put a copyright sign into the string: "\xA9 1999-2001", "\x0A9 1999-2001", "\x00A9 1999-2001". When the character directly after the last hexadecimal digit can be interpreted as hexadecimal digit, you must use all 4 digits or else FreeMarker will misunderstand you. Note that the character sequence${ (and #{) has special meaning. It's used to insert the value of expressions (typically: the value of variables, as in "Hello ${user}!"). This will be explained later. If you want to print${ or #{, you should either use raw string literals as explained below, or escape the { like in "foo $\{bar}". raw string literal A special kind of string literals is the raw string literals. In raw string literals, backslash and${ have no special meaning, they are considered as plain characters. To indicate that a string literal is a raw string literal, you have to put an r directly before the opening quotation mark or apostrophe-quote. Example: ${r"${foo}"} ${r"C:\foo\bar"} will print:${foo} C:\foo\bar
Numbers number literal To specify a numerical value directly you type the number without quotation marks. You have to use the dot as your decimal separator and must not use any grouping separator symbols. You can use - or + to indicate the sign (+ is redundant). Scientific notation is not yet supported (so 1E3 is wrong). Also, you cannot omit the 0 before the decimal separator (so .5 is wrong). Examples of valid number literals: 0.08, -5.013, 8, 008, 11, +11 Note that numerical literals like 08, +8, 8.00 and 8 are totally equivalent as they all symbolize the number eight. Thus, ${08},${+8}, ${8.00} and${8} will all print exactly same.
Booleans boolean literal literal boolean To specify a boolean value you write true or false. Don't use quotation marks.
Sequences sequence literal numerical sequence numerical range expression range expression To specify a literal sequence, you list the sub variables separated by commas, and put the whole list into square brackets. For example: <#list ["foo", "bar", "baz"] as x> ${x} </#list> will print: foo bar baz The items in the list are expressions, so you can do this for example: [2 + 2, [1, 2, 3, 4], "foo"]. Here the first subvariable will be the number 4, the second will be another sequence, and the third subvariable will be the string foo. Ranges Ranges are just sequences, but they are created by specifying what range of whole numbers they contain, instead of specifying their items one by one. For example, 0..<m, assuming the m variable stores 5, will give a sequence that contains [0, 1, 2, 3, 4]. Ranges are primarily used for iterating over a range of numbers with <#list ...> and for slicing sequences and slicing strings. The generic forms of range expressions are (where start and end can be any expression that evaluates to a number): start..end: Range with inclusive end. For example, 1..4 gives [1, 2, 3, 4], and 4..1 gives [4, 3, 2, 1]. Beware, ranges with inclusive end never give an empty sequence, so 0..length-1 is WRONG, because when length is 0 it gives [0, -1]. start..<end or start..!end: Range with exclusive end. For example, 1..<4 gives [1, 2, 3], 4..<1 gives [4, 3, 2], and 1..<1 gives []. Note the last example; the result can be an empty sequence. There's no difference between ..< and ..!; the last form is used in applications where using the < character causes problems (for HTML editors and such). start..*length: Length limited range. For example, 10..*4 gives [10, 11, 12, 13], 10..*-4 gives [10, 9, 8, 7], and 10..*0 gives []. When these kind of ranges are used for slicing, the slice will end without error if the end of the sliced sequence or string is reached before the specified range length was reached; see slicing sequences for more. Length limited ranges were introduced in FreeMarker 2.3.21. start..: Right-unbounded range. This are like length limited ranges with infinite length. For example 1.. gives [1, 2, 3, 4, 5, 6, ... ], up to infinity. Be careful when processing (like listing) such ranges, as processing all items of it it would take forever or until the application runs out of memory and crashes. Just like with length limited ranges, when these kind of ranges are used for slicing, the slice will end when the end of the sliced sequence or string is reached. Right-unbounded ranges before FreeMarker 2.3.21 were only used for slicing, and behaved like an empty sequence for other purposes. To activate the new behavior, it's not enough to use FreeMarker 2.3.21, the programmer also have to set the incompatible_improvements configuration setting to at least 2.3.21. Further notes on ranges: Range expressions themselves don't have square brackets, for example, you write <#assign myRange = 0..<x, NOT <#assign myRange = [0..<x]>. The last would create a sequence that contains an item that's a range. The square brackets are part of the slicing syntax, like seq[myRange]. You can write arithmetical expression on the sides of the .. without parenthesis, like n + 1 ..< m / 2 - 1. .., ..<, ..! and ..* are operators, so you can't have space inside them. Like n .. <m is WRONG, but n ..< m is good. The reported size of right-unbounded ranges is 2147483647 (or 0 if incompatible_improvements is less than 2.3.21) due to a technical limitation (32 bits). However, when listing them, their actual size is infinite. Ranges don't really store the numbers they consist of, thus for example 0..1 and 0..100000000 is equally fast to create and takes the same amount of memory. Hashes hash literal literal hash To specify a hash in a template, you list the key/value pairs separated by commas, and put the list into curly brackets. The key and value within a key/value pair are separated with a colon. Here is an example: { "name": "green mouse", "price": 150 }. Note that both the names and the values are expressions. The keys must be strings. The values can be if any type. Retrieving variables Top-level variables subvariable accessing To access a top-level variable, you simply use the variable name. For example, the expression user will evaluate to the value of variable stored with name user in the root. So this will print what you store there:${user} If there is no such top-level variable, then an error will result when FreeMarker tries to evaluate the expression, and it aborts template processing (unless programmers has configured FreeMarker differently). In this kind of expression, the variable name can only contain letters (including non-Latin letters), digits (including non-Latin digits), underline (_), dollar ($), at sign (@). Furthermore, the first character can't be a ASCII digit (0-9). Starting from FreeMarker 2.3.22, the variable name can also contain minus (-), dot (.), and colon (:) at any position, but these must be escaped with a preceding backslash (\), or else they would be interpreted as operators. For example, to read the variable whose name is data-id, the expression is data\-id, as data-id would be interpreted as data minus id. (Note that these escapes only work in identifiers, not in string literals.) Retrieving data from a hash subvariable accessing hash accessing subvariable If we already have a hash as a result of an expression, then we can get its subvariable with a dot and the name of the subvariable. Assume that we have this data-model: (root) | +- book | | | +- title = "Breeding green mouses" | | | +- author | | | +- name = "Julia Smith" | | | +- info = "Biologist, 1923-1985, Canada" | +- test = "title" Now we can read the title with book.title, since the book expression will return a hash (as explained in the last chapter). Applying this logic further, we can read the name of the author with this expression: book.author.name. There is an alternative syntax if we want to specify the subvariable name with an expression: book["title"]. In the square brackets you can give any expression as long as it evaluates to a string. So with this data-model you can also read the title with book[test]. More examples; these are all equivalent: book.author.name, book["author"].name, book.author.["name"], book["author"]["name"]. When you use the dot syntax, the same restrictions apply regarding the variable name as with top-level variables (name can contain only letters, digits, _,$, @ but can't start with 0-9, also starting from 2.3.22 you can also use \-, \. and \:). There are no such restrictions when you use the square bracket syntax, since the name is the result of an arbitrary expression. (Note, that to help the FreeMarker XML support, if the subvariable name is * (asterisk) or **, then you do not have to use square bracket syntax.) As with the top-level variables, trying to access a non-existent subvariable causes an error and aborts the processing of the template (unless programmers has configured FreeMarker differently).
Retrieving data from a sequence subvariable accessing sequence accessing subvariable This is the same as for hashes, but you can use the square bracket syntax only, and the expression in the brackets must evaluate to a number, not a string. For example to get the name of the first animal of the example data-model (remember that the number of the first item is 0, not 1): animals[0].name
Special variables special variables Special variables are variables defined by the FreeMarker engine itself. To access them, you use the .variable_name syntax. Normally you don't need to use special variables. They are for expert users. The complete list of special variables can be found in the reference.
String operations string operations
Interpolation (or concatenation) interpolation concatenate strings joining strings string concatenate string interpolation adding strings If you want to insert the value of an expression into a string, you can use ${...} (and the deprecated #{...}) in string literals.${...} in string literals behaves as in text sections (so it goes through the same locale sensitive number and date/time formatting), except that it never go through automatic escaping. Example (assume that user is Big Joe''): <#assign s = "Hello ${user}!">${s} <#-- Just to see what the value of s is --> This will print: Hello Big Joe! A frequent mistake of users is the usage of interpolations in places where they needn't/shouldn't/can't be used. Interpolations work only in text sections (e.g. <h1>Hello ${name}!</h1>) and in string literals (e.g. <#include "/footer/${company}.html">). A typical WRONG usage is <#if ${big}>...</#if>, which will cause a syntactical error. You should simply write <#if big>...</#if>. Also, <#if "${big}">...</#if> is WRONG, since it converts the parameter value to string and the if directive wants a boolean value, so it will cause a runtime error. Alternatively, you can use the + operator to achieve similar result: <#assign s = "Hello " + user + "!"> This gives the same result as the example with the ${...}. Because + follows the same rules as${...}, the appended string is influenced by the locale, number_format, date_format, time_format, datetime_format and boolean_format, etc. settings, and thus the result targets humans and isn't in generally machine parsable. This mostly leads to problems with numbers, as many locales use grouping (thousands separators) by default, and so "someUrl?id=" + id becomes to something like "someUrl?id=1 234". To prevent this, use the ?c (for Computer audience) built-in, like in "someUrl?id=" + id?c or "someUrl?id=${id?c}", which will evaluate to something like "someUrl?id=1234", regardless of locale and format settings. Getting a character charAt get character You can get a single character of a string at a given index similarly as you can read the subvariable of a sequence, e.g. user[0]. The result will be a string whose length is 1; FTL doesn't have a separate character type. As with sequence sub variables, the index must be a number that is at least 0 and less than the length of the string, or else an error will abort the template processing. Since the sequence subvariable syntax and the character getter syntax clashes, you can use the character getter syntax only if the variable is not a sequence as well (which is possible because FTL supports multi-typed values), since in that case the sequence behavior prevails. (To work this around, you can use the string built-in, e.g. user?string[0]. Don't worry if you don't understand this yet; built-ins will be discussed later.) Example (assume that user is Big Joe):${user[0]} ${user[4]} will print (note that the index of the first character is 0): B J String slicing (substrings) string slicing substring string slice string substring You can a slice a string in the same way as you slice a sequence (see there), only here instead of sequence items you work with characters. Some differences are: Decreasing ranges aren't allowed for string slicing. (That's because unlike sequences, you seldom if ever want to show a string reversed, so if that happens, that's almost always the result of an oversight.) If a value is both a string and a sequence (a multi-typed value), then slicing will slice the sequence instead of the string. When you are processing XML, such values are common. In such cases you can use someXMLnode?string[range]. There's a legacy bug where a range with inclusive end that's one less than the starting index and is non-negative (like in "abc"[1..0]) will give an empty string instead of an error. (It should be an error as it's a decreasing range.) Currently this bug is emulated for backward compatibility, but you shouldn't utilize it, as in the future it will be certainly an error. Example: <#assign s = "ABCDEF">${s[2..3]} ${s[2..<4]}${s[2..*3]} ${s[2..*100]}${s[2..]} will print: CD CD CDE CDEF CDEF Some of the typical use-cases of string slicing is covered by convenient built-ins: remove_beginning, remove_ending, keep_before, keep_after, keep_before_last, keep_after_last
Sequence operations sequence operations
Concatenation concatenate sequences joining sequences sequence concatenate adding sequences You can concatenate sequences in the same way as strings, with +. Example: <#list ["Joe", "Fred"] + ["Julia", "Kate"] as user> - \${user} </#list> will print: - Joe - Fred - Julia - Kate Note that sequence concatenation is not to be used for many repeated concatenations, like for appending items to a sequence inside a loop. It's just for things like <#list users + admins as person>. Although concatenating sequences is fast and its speed is independently of the size of the concatenated sequences, the resulting sequence will be always a little bit slower to read than the original two sequences were. This way the result of many repeated concatenations is a sequence that is slow to read.
Sequence slicing