blob: a04c8b7c65866070ee757a13e3c167bd1d01d8fb [file] [log] [blame]
What is FreeMarker? FreeMarker is a template engine: a generic tool to generate text output (anything from HTML to autogenerated source code) based on templates. It's a Java package, a class library for Java programmers. It's not an application for end-users in itself, but something that programmers can embed into their products. FreeMarker is designed to be practical for the generation of HTML Web pages, particularly by servlet-based applications following the MVC (Model View Controller) pattern. The idea behind using the MVC pattern for dynamic Web pages is that you separate the designers (HTML authors) from the programmers. Everybody works on what they are good at. Designers can change the appearance of a page without programmers having to change or recompile code, because the application logic (Java programs) and page design (FreeMarker templates) are separated. Templates do not become polluted with complex program fragments. This separation is useful even for projects where the programmer and the HTML page author is the same person, since it helps to keep the application clear and easily maintainable. Although FreeMarker has some programming capabilities, it is not a full-blown programming language like PHP. Instead, Java programs prepare the data to be displayed (like issue SQL queries), and FreeMarker just generates textual pages that display the prepared data using templates. FreeMarker is not a Web application framework. It is suitable as a component in a Web application framework, but the FreeMarker engine itself knows nothing about HTTP or servlets. It simply generates text. As such, it is perfectly usable in non-web application environments as well. Note, however, that we provide out-of-the-box solutions for using FreeMarker as the view component of Model 2 frameworks such as Struts. FreeMarker is Free, released under a BSD-style license. It is OSI Certified Open Source Software. OSI Certified is a certification mark of the Open Source Initiative.
What should I read? If you are a ... designer, then you should read the and then you can look into the on an as-needed basis for more specific details. programmer, then you should read the guide first, then the and then you can look into the on an as-needed basis for more specific details.
Document conventions Variable names, template fragments, Java class names, etc. are written like this: foo. If something should be replaced with a concrete value then it is written in italics, as follows: Hello yourName!. Template examples are written like this: something Data-model examples are written like this: something Output examples are written like this: something Program examples are written like this: something This paragraph is for the editors, and not visible for the public In chapters this section is for the editors toowritten for both designers and programmers fragments addressed to programmers are written like this: This is for programmers only. New terms are emphasized like this: some new term
Contact help homepage download contact For the latest version of FreeMarker and to subscribe to the mailing lists visit the FreeMarker homepage: If you need help or you have suggestions, use the mailing lists (mail archives can be searched without subscription) or the Web based forums. If you want to report a bug, use the Web based bug tracker, or the mailing lists. To find all of these visit . Also, note that we have a FAQ and index; use them.
About this document If you find any mistakes (including grammatical mistakes, typos, typographical mistakes) or you find something misleading or confusing in the documentation, or you have other suggestions, please let me know! Email: ddekany at users.sourceforge.net
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 Assume you need a HTML page in an e-shop application, similar to this: <html> <head> <title>Welcome!</title> </head> <body> <h1>Welcome Big Joe!</h1> <p>Our latest product: <a href="products/greenmouse.html">green mouse</a>! </body> </html> Let's say that the user name ("Big Joe" 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 at any moment. In this situation you can't just enter the user name nor the URL and name of the latest product into the HTML, you can't use static HTML. FreeMarker's solution for this problem is using a template instead of the static HTML. The template is the same as the static HTML, 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 (e.g., replacing ${user} with Big Joe or whoever the visitor is) 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. The template file itself (which is, again, stored on the Web server) is not changed during this, so the transformation will happen again and again for each visiting. This ensures that the displayed information is always up-to-date. Now, you already may have noticed that the template contains no instructions regarding how to find out who the current visitor is, or how to query the database to find out what the latest product is. It seems it just already know these values. And indeed that's the case. An important idea behind FreeMarker (actually, behind Web MVC) is that presentation logic and "business logic" should be separated. In the template you only deal with presentation issues, that is, visual design issues, formatting issues. The data that will be displayed (such as the user name and so on) is prepared outside FreeMarker, usually by routines written in Java language or other general purpose language. So the template author doesn't have to know how these values are calculated. In fact, the way these values are calculated can be completely changed while the templates can remain the same, and also, the look of the page can be completely changed without touching anything but the template. This separation can be especially useful when the template authors (designers) and the programmers are different individuals. data-model While for FreeMarker (and for the template author) it's not interesting how the data was calculated, FreeMarker still have to know what the actual data is. All the data that the template can use is packed into the so called data-model. It's created by the already mentioned routines that calculate the data. As far as the template author is concerned, the data-model is a tree-like structure (like folders and files on your hard disk), that in this case could be visualized as: (root) | +- user = "Big Joe" | +- latestProduct | +- url = "products/greenmouse.html" | +- name = "green mouse" (To prevent misunderstandings: The data-model is not a text file, the above is just a visualization of a data-model for you. It's from Java objects, but let that be the problem of the Java programmers.) Compare this with what you saw in the template earlier:${user} and ${latestProduct.name}. As an analogy, the data model is something like the file system of computers: the root and latestProduct correspond to directories (folders) and the user, url and name correspond to files. url and name are in the latestProduct directory. So latestProduct.name is like saying name in the latestProduct directory. But as I said, it was just a simile; there are no files or directories here. 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 | +- test = "It is a test" | +- whatnot | +- because = "don't know" The variables that act as directories (the root, animals, mouse, elephant, python, whatnot) are called hashes. Hashes store other variables (the so called subvariables) by a lookup name (e.g., "animals", "mouse" or "price"). The variables that store a single value (size, price, test and because) 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. When you put the special${...} codes around an expression like this, you are telling FreeMarker to output the corresponding text at that point. There is one more important kind of variable: sequences. They are similar to hashes, but they don't store names for the variables they contain. Instead, they store the subvariables sequentially, and you can access them with a numerical index. For example, in this data-model, animals and whatnot.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 | +- whatnot | +- 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 first item is 0, the index of the second 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 whatnot.fruits (which is the string "banana") you write whatnot.fruits[1]. 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, say, in arithmetical calculations. Date/time: A date or time. Like the date an animal were captured, or the time the shop opens. 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 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.
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 thing inside the curly brackets. They are called interpolations. As an example see the very first example. 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 -->. Anything between these delimiters and the delimiter itself will be ignored by FreeMarker, and will not be written to the output. 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.) Examples of directives Though FreeMarker has far more directives, in this quick overview we will only look at three of the most commonly used ones. 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 from 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 detail the condition used here: The == 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. 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 may have guessed, != means not equivalent. 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.'' 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> Warning! Pythons are protected animals! </#if>
The list directive This is useful when you want to list something. For example if you merge this template with the data-model I used earlier to demonstrate sequences: <p>We have these animals: <table border=1> <tr><th>Name<th>Price <#list animals as being> <tr><td>${being.name}<td>${being.price} Euros </#list> </table> then the output will be: <p>We have these animals: <table border=1> <tr><th>Name<th>Price <tr><td>mouse<td>50 Euros <tr><td>elephant<td>5000 Euros <tr><td>python<td>4999 Euros </table> The generic format 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 given 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. As another example, we list the fruits of that example data model: <p>And BTW we have these fruits: <ul> <#list whatnot.fruits as fruit> <li>${fruit} </#list> <ul> The whatnot.fruits expression should be familiar to you; it references a variable in the data-model. The include directive With the include directive you can insert the content of another file into the template. Suppose you have to show the same copyright notice on several pages. You can create a file that contains the copyright notice only, and insert that file everywhere where you need that copyright notice. Say, you store this copyright notice in copyright_footer.html: <hr> <i> Copyright (c) 2000 <a href="http://www.acmee.com">Acmee Inc</a>, <br> All Rights Reserved. </i> Whenever you need that file you simply insert it with the include directive: <html> <head> <title>Test page</title> </head> <body> <h1>Test page</h1> <p>Blah blah... <#include "/copyright_footer.html"> </body> </html> and the output will be: <html> <head> <title>Test page</title> </head> <body> <h1>Test page</h1> <p>Blah blah... <hr> <i> Copyright (c) 2000 <a href="http://www.acmee.com">Acmee Inc</a>, <br> All Rights Reserved. </i> </body> </html> If you change the copyright_footer.html, then the visitor will see the new copyright notice on all pages. Using directives together You can use directives as many times on a page as you want, and you can nest directives into each other similarly as you can nest HTML elements into each other. For example this will list the animals and print the name of large animals with bigger font: <p>We have these animals: <table border=1> <tr><th>Name<th>Price <#list animals as being> <tr> <td> <#if being.size == "large"><font size="+1"></#if>${being.name} <#if being.size == "large"></font></#if> <td>${being.price} Euros </#list> </table> Note that since FreeMarker does not interpret text outside FTL tags, interpolations and comments, it doesn't see the above font tags as badly nested ones. Dealing with missing variables In practice 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 them 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 "Anonymous". (When user isn't missing, this template behaves exactly like if !"Anonymous" were not there): <h1>Welcome${user!"Anonymous"}!</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 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 variable stores date/time related data. It has three variations: A date with day precision (often referred simply as "date") as April 4, 2003 Time of day (without the date part), as 10:19:18 PM. Time is stored with millisecond precision. Date-time (sometimes called "time stamp") as April 4, 2003 10:19:18 PM. The time part is stored 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, or a time of day, etc.). The solution for this problem is an advanced topic that will be discussed later. It is possible to define date values directly in templates, but this is an advanced topic that will be explained later. Bear in mind that FreeMarker distinguishes strings from numbers and booleans, so the string "150" and the number 150 are totally different. A number holds a numerical value. A boolean holds a logical true or false. A string holds an arbitrary sequence of characters.
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 subvariables. The container types are: hash the FTL value type Hash: Associates a unique lookup name with each of its subvariables. The name is an unrestricted string. A hash doesn't define an ordering for the subvariables 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 subvariables. The first subvariable is associated with 0, the second with 1, the third to 2, and so on; the subvariables are ordered. These numbers are often called the indexes of the subvariables. 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 subvariables 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 being>[BR] <li>${being.name} for${being.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... --> being>[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 being> 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 being> <li>${being.name} for${being.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] being[BR] >[BR] ${being.name} for${being.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 r"C:\raw\string" Numbers: 123.45 Booleans: true, false Sequences: ["foo", "bar", 123.45], 1..100 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 "Free" + "Marker") Getting a character: name[0] Sequence operations Concatenation: users + ["guest"] Sequence slice: products[10..19] or products[5..] 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, ...etc. Logical operations: !registered && (firstVisit || fromEurope) Built-ins: name?upper_case 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)?? 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)
\\ 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 be confused. 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 ${, you should use raw string literals as explained below. 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 subvariables separated by commas, and put the whole list into square brackets. For example: <#list ["winter", "spring", "summer", "autumn"] as x> ${x} </#list> will print: winter spring summer autumn The items in the list are expressions, so you can do this for example: [2 + 2, [1, 2, 3, 4], "whatnot"]. Here the first subvariable will be the number 4, the second will be another sequence, and the third subvariable will be the string "whatnot". You can define sequences that store a numerical range with start..end, where start and end are expressions that resolve to numerical values. For example 2..5 is the same as [2, 3, 4, 5], but the former is much more efficient (occupies less memory and faster). Note that the square brackets are missing. You can define decreasing numerical ranges too, e.g.: 5..2. (Furthermore, you can omit the end, for example 5.., in which case the sequence will contain 5, 6, 7, 8, ...etc up to the infinity.) 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. However, the lookup names must be strings. 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 expression the variable name can contain only letters (including non-Latin letters), digits (including non-Latin digits), underline (_), dollar ($), at sign (@) and hash (#). Furthermore, the name must not start with digit. 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, _,$, @, etc.). 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 #{...}) in string literals.${...} behaves similarly as in text sections. For example (assume that user is Big Joe''): ${"Hello${user}!"} ${"${user}${user}${user}${user}"} will print: Hello Big Joe! Big JoeBig JoeBig JoeBig Joe Alternatively, you can use the + operator to achieve similar result. This is the old method, and it is called string concatenation. Example:${"Hello " + user + "!"} ${user + user + user + user} This will print the same as the example with the${...}-s. A frequent mistake of users is the usage of interpolations in places where it 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 bad usage is <#if ${isBig}>Wow!</#if>, which is syntactically WRONG. You should simply write <#if isBig>Wow!</#if>. Also, <#if "${isBig}">Wow!</#if> is WRONG too, since the parameter value will be a string, and the if directive wants a boolean value, so it will cause a runtime error.
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 subvariables, 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 You can get a range of characters in the same way as you get a sequence slice, e.g ${user[1..4]} and${user[4..]}. However, it's now depreacted to utilize this, and instead you should use the substring built-in; built-ins will be discussed later.
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 slice sequence slice sequence slice subsequence With [firstindex..lastindex] you can get a slice of a sequence, where firstindex and lastindex are expressions evaluate to number. For example, if seq stores the sequence "a", "b", "c", "d", "e", "f" then the expression seq[1..4] will evaluate to a sequence that contains "b", "c", "d", "e" (since the item at index 1 is "b", and the item at index 4 is "e"). The lastindex can be omitted, in which case it defaults to the index of the last item of the sequence. For example, if seq stores the sequence "a", "b", "c", "d", "e", "f" again, then seq[3..] will evaluate to a sequence that contains "d", "e", "f". lastindex can be omitted only since FreeMarker 2.3.3. An attempt to access a subvariable past the last subvariable or before the first subvariable of the sequence will cause an error and abort the processing of the template. Hash operations hash operations Concatenation concatenate hashes joining hashes hash concatenate adding hashes You can concatenate hashes in the same way as strings, with +. If both hashes contain the same key, the hash on the right-hand side of the + takes precedence. Example: <#assign ages = {"Joe":23, "Fred":25} + {"Joe":30, "Julia":18}> - Joe is${ages.Joe} - Fred is ${ages.Fred} - Julia is${ages.Julia} will print: - Joe is 30 - Fred is 25 - Julia is 18 Note that hash concatenation is not to be used for many repeated concatenations, like for adding items to a hash inside a loop. It's the same as with the sequence concatenation.
Arithmetical calculations arithmetic math addition subtraction division modulus This is the basic 4-function calculator arithmetic plus the modulus operator. So the operators are: Addition: + Subtraction: - Multiplication: * Division: / Modulus (remainder): % Information about the precision? Example: ${100 - x * x}${x / 2} ${12 % 10} Assuming that x is 5, it will print: 75 2.5 2 Both operands must be expressions which evaluate to a numerical value. So the example below will cause an error when FreeMarker tries to evaluate it, since "5" is a string and not the number 5:${3 * "5"} <#-- WRONG! --> There is an exception to the above rule. The + operator, is used to concatenate strings as well. If on one side of + is a string and on the other side of + is a numerical value, then it will convert the numerical value to string (using the format appropriate for language of the page) and then use the + as string concatenation operator. Example: ${3 + "5"} will output this: 35 Generally, FreeMarker never converts a string to a number automatically, but it may convert a number to a string automatically. integer division integer part People often want only the integer part of the result of a division (or of other calculations). This is possible with the int built-in. (Built-ins are explained later):${(x/2)?int} ${1.1?int}${1.999?int} ${-1.1?int}${-1.999?int} Assuming that x is 5, it will print: 2 1 1 -1 -1
Comparison comparison operators Sometimes you want to know if two values are equal or not, or which value is the greater. To show concrete examples I will use the if directive here. The usage of if directive is: <#if expression>...</#if>, where expression must evaluate to a boolean value or else an error will abort the processing of the template. If the value of expression is true then the things between the begin and end-tag will be processed, otherwise they will be skipped. To test two values for equality you use = (or == as in Java or C; the two are absolutely equivalent.) To test two values for inequality you use !=. For example, assume that user is Big Joe'': <#if user = "Big Joe"> It is Big Joe </#if> <#if user != "Big Joe"> It is not Big Joe </#if> The user = "Big Joe" expression in the <#if ...> will evaluate to the boolean true, so the above will say It is Big Joe''. The expressions on both sides of the = or != must evaluate to a scalar. Furthermore, the two scalars must have the same type (i.e. strings can only be compared to strings and numbers can only be compared to numbers, etc.) or else an error will abort template processing. For example <#if 1 = "1"> will cause an error. Note that FreeMarker does exact comparison, so string comparisons are case and white-space sensitive: "x" and "x " and "X" are not equal values. For numerical and date values you can also use <, <=, >= and >. You can't use them for strings! Example: <#if x <= 12> x is less or equivalent with 12 </#if> There is a little problem with >= and >. FreeMarker interprets the > as the closing character of the FTL tag. To prevent this, you have to put the expression into parentheses: <#if (x > y)>. Or, you can use &gt; and &lt; on the place of the problematic relation marks: <#if x &gt; y>. (Note that in general FTL does not support entity references (those &...; things) in FTL tags; it is just an exception with the arithmetical comparisons.). Also, as an alternative you can use lt instead of <, lte instead of <=, gt instead of > and gte instead of >=. And, for historical reasons FTL also understands \lt, \lte, \gt and \gte which are the same as the ones without the backslash.
Logical operations boolean operations logical operations or and not Just the usual logical operators: Logical or: || Logical and: && Logical not: ! The operators will work with boolean values only. Otherwise an error will abort the template processing. Example: <#if x < 12 && color = "green"> We have less than 12 things, and they are green. </#if> <#if !hot> <#-- here hot must be a boolean --> It's not hot. </#if>
Built-ins built-in Built-ins provide, as the name suggest, certain built-in functionality that is always available. Typically, a built-in provides a different version of a variable, or some information about the variable in question. The syntax for accessing a built-in is like that of accessing a subvariable in a hash, except that you use the question mark instead of a dot. For example, to get the upper case version of a string: user?upper_case. You can find the complete list of built-ins in the Reference. For now, just a few of the more important ones: Built-ins to use with strings: