| <?xml version="1.0" encoding="UTF-8"?> |
| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| --> |
| <book conformance="docgen" version="5.0" xml:lang="en" |
| xmlns="http://docbook.org/ns/docbook" |
| xmlns:xlink="http://www.w3.org/1999/xlink" |
| xmlns:ns5="http://www.w3.org/1999/xhtml" |
| xmlns:ns4="http://www.w3.org/2000/svg" |
| xmlns:ns3="http://www.w3.org/1998/Math/MathML" |
| xmlns:ns="http://docbook.org/ns/docbook"> |
| <info> |
| <title>Apache FreeMarker Manual</title> |
| |
| <titleabbrev>Manual</titleabbrev> |
| |
| <productname>Freemarker 2.3.33</productname> |
| </info> |
| |
| <preface role="index.html" xml:id="preface"> |
| <title>What is Apache FreeMarker?</title> |
| |
| <para>FreeMarker is a <emphasis>template engine</emphasis>: 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.</para> |
| |
| <para>Templates are written in the FreeMarker Template Language (FTL). |
| It's a simple, specialized language, <emphasis>not</emphasis> a full-blown |
| programming language like PHP. You are 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.</para> |
| |
| <mediaobject> |
| <imageobject> |
| <imagedata fileref="figures/overview.png"/> |
| </imageobject> |
| </mediaobject> |
| |
| <para>This approach is often referred to as the <link |
| linkend="gloss.MVC">MVC (Model View Controller) pattern</link>, and is |
| particularly popular for dynamic web pages. It helps in separating web |
| page designers (HTML authors) from 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.</para> |
| |
| <para>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.</para> |
| |
| <para>FreeMarker is <link |
| xlink:href="http://www.fsf.org/philosophy/free-sw.html">Free</link>, |
| released under the Apache License, Version 2.0.</para> |
| </preface> |
| |
| <part xml:id="dgui"> |
| <title>Template Author's Guide</title> |
| |
| <chapter xml:id="dgui_quickstart"> |
| <title>Getting Started</title> |
| |
| <para>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.</para> |
| |
| <section xml:id="dgui_quickstart_basics"> |
| <title>Template + data-model = output</title> |
| |
| <para>Let's assume that you need a HTML page on a website, similar to |
| this:</para> |
| |
| <programlisting role="output"><html> |
| <head> |
| <title>Welcome!</title> |
| </head> |
| <body> |
| <h1>Welcome <emphasis>John Doe</emphasis>!</h1> |
| <p>Our latest product: |
| <a href="<emphasis>products/greenmouse.html</emphasis>"><emphasis>green mouse</emphasis></a>! |
| </body> |
| </html></programlisting> |
| |
| <para>But the user's name ("John Doe" above) depends on who the |
| logged-in user is, and the latest product information should come from |
| a database. Because this data changes, you cannot use static HTML. |
| Instead, you can use a <emphasis role="term">template</emphasis> 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:</para> |
| |
| <programlisting role="template" xml:id="example.first"><html> |
| <head> |
| <title>Welcome!</title> |
| </head> |
| <body> |
| <h1>Welcome <emphasis>${user}</emphasis>!</h1> |
| <p>Our latest product: |
| <a href="<emphasis>${latestProduct.url}</emphasis>"><emphasis>${latestProduct.name}</emphasis></a>! |
| </body> |
| </html></programlisting> |
| |
| <para>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 |
| <literal>${<replaceable>...</replaceable>}</literal>-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.)</para> |
| |
| <para>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 <quote>real</quote> |
| 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.</para> |
| |
| <para><indexterm> |
| <primary>data-model</primary> |
| </indexterm>The totality of data that was prepared for the template |
| is called the <emphasis role="term">data-model</emphasis>. 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:</para> |
| |
| <programlisting role="dataModel">(root) |
| | |
| +- <emphasis>user</emphasis> = "Big Joe" |
| | |
| +- <emphasis>latestProduct</emphasis> |
| | |
| +- <emphasis>url</emphasis> = "products/greenmouse.html" |
| | |
| +- <emphasis>name</emphasis> = "green mouse"</programlisting> |
| |
| <note> |
| <para>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 <literal>getUser()</literal> |
| and <literal>getLatestProduct()</literal> methods, or maybe a Java |
| <literal>Map</literal> with <literal>"user"</literal> and |
| <literal>"latestProducts"</literal> keys. Similarly, |
| <literal>latestProduct</literal> is perhaps a Java Object with |
| <literal>getUrl()</literal> and <literal>getName()</literal> |
| methods.</para> |
| </note> |
| |
| <para>Earlier, you have picked values from this data-model, with the |
| <literal>user</literal> and <literal>latestProduct.name</literal> |
| expressions. If we go on with the analogy that the data model is like |
| a file system, then <quote>(root)</quote> and |
| <literal>latestProduct</literal> correspond to directories (folders), |
| and <literal>user</literal>, <literal>url</literal> and |
| <literal>name</literal> are files in those directories.</para> |
| |
| <para>To recapitulate, a template and a data-model is needed for |
| FreeMarker to generate the output (like the HTML shown first):</para> |
| |
| <para><phrase role="markedTemplate">Template</phrase> + <phrase |
| role="markedDataModel">data-model</phrase> = <phrase |
| role="markedOutput">output</phrase></para> |
| </section> |
| |
| <section xml:id="dgui_quickstart_datamodel"> |
| <title>The data-model at a glance</title> |
| |
| <para>As you have seen, the data-model is basically a tree. This tree |
| can be arbitrarily complicated and deep, for example:</para> |
| |
| <programlisting role="dataModel" |
| xml:id="example.qStart.dataModelWithHashes">(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"</programlisting> |
| |
| <para>The variables that act like directories (the root, |
| <literal>animals</literal>, <literal>mouse</literal>, |
| <literal>elephant</literal>, <literal>python</literal>, |
| <literal>misc</literal>) are called <emphasis |
| role="term">hashes</emphasis>. Hashes store other variables (the so |
| called <anchor xml:id="topic.dataModel.subVar"/><emphasis>sub |
| variables</emphasis>) by a lookup name (e.g., <quote>animals</quote>, |
| <quote>mouse</quote> or <quote>price</quote>).</para> |
| |
| <para>The variables that store a single value |
| (<literal>size</literal>, <literal>price</literal>, |
| <literal>message</literal> and <literal>foo</literal>) are called |
| <emphasis role="term">scalars</emphasis>.</para> |
| |
| <para><anchor xml:id="topic.qStart.accessVariables"/>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 |
| <literal>price</literal> of a <literal>mouse</literal>, you start from |
| the root and go into <literal>animals</literal>, and then go into |
| <literal>mouse</literal> then go into <literal>price</literal>. So you |
| write <literal>animals.mouse.price</literal>.</para> |
| |
| <para>Another important kind of variables are <emphasis |
| role="term">sequences</emphasis>. 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, <literal>animals</literal> and |
| <literal>misc.fruits</literal> are sequences:</para> |
| |
| <programlisting role="dataModel" |
| xml:id="example.qStart.dataModelWithSequences">(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"</programlisting> |
| |
| <para>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 <literal>animals[0].name</literal>. To get the second item |
| in <literal>misc.fruits</literal> (the string |
| <literal>"banana"</literal>) you write |
| <literal>misc.fruits[1]</literal>. (In practice, you usually just walk |
| through sequences in order, not caring about the index, but that will |
| be <link linkend="topic.tutorial.list">shown later</link>.)</para> |
| |
| <para>Scalars can be further divided into these categories:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>String: Text, that is, an arbitrary sequence of characters |
| such as ''m'', ''o'', ''u'', ''s'', ''e'' above. For example the |
| <literal>name</literal>-s and <literal>size</literal>-s are |
| strings above.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Number: It's a numerical value, like the |
| <literal>price</literal>-s above. The string |
| <literal>"50"</literal> and the number <literal>50</literal> 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.</para> |
| </listitem> |
| |
| <listitem> |
| <para>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).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Boolean: A true/false (yes/no, on/off, etc.) thing. Like |
| animals could have a <literal>protected</literal> subvariable, |
| which store if the animal is protected or not.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Summary:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The data-model can be visualized as a tree.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Scalars store a single value. The value can be a string or a |
| number or a date-time/date/time or a boolean.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Hashes are containers that store other variables and |
| associate them with a unique lookup name.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Sequences are containers that store other variables in an |
| ordered sequence. The stored variables can be retrieved via their |
| numerical index, starting from 0.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <note> |
| <para>There are other, more advanced value types that we don't cover |
| here, such as methods and directives.</para> |
| </note> |
| </section> |
| |
| <section xml:id="dgui_quickstart_template"> |
| <title>The template at a glance</title> |
| |
| <para>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:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>${<replaceable>...</replaceable>}</literal>: |
| FreeMarker will replace it in the output with the actual value of |
| the expression inside the curly brackets. They are called |
| <emphasis role="term">interpolation</emphasis>s.</para> |
| </listitem> |
| |
| <listitem> |
| <para><emphasis role="term">FTL tags</emphasis> (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 |
| <literal>#</literal>. (User-defined FTL tags use |
| <literal>@</literal> instead of <literal>#</literal>, but they are |
| an advanced topic.)</para> |
| </listitem> |
| |
| <listitem> |
| <para><emphasis role="term">Comments:</emphasis> Comments are |
| similar to HTML comments, but they are delimited by |
| <literal><#--</literal> and <literal>--></literal>. 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.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Anything not an FTL tag or an interpolation or comment is |
| considered static text and will not be interpreted by FreeMarker; it |
| is just printed to the output as-is.</para> |
| |
| <para>With FTL tags you refer to so-called <emphasis |
| role="term">directives</emphasis>. This is the same kind of |
| relationship as between HTML tags (e.g.: |
| <literal><table></literal> and |
| <literal></table></literal>) and HTML elements (e.g., the |
| <literal>table</literal> element) to which you refer to with the HTML |
| tags. (If you don't understand this difference then consider "FTL tag" |
| and "directive" synonyms.)</para> |
| |
| <note> |
| <para>You can easily try writing templates on <olink |
| targetdoc="onlineTemplateTester"/></para> |
| </note> |
| |
| <section> |
| <title>Some basic directives</title> |
| |
| <para>Here we will look at some of the most commonly used directives |
| (<link linkend="ref_directives">but there are much |
| more</link>).</para> |
| |
| <section> |
| <title>The if directive</title> |
| |
| <para>With the <literal>if</literal> directive you can |
| conditionally skip a section of the template. For example, assume |
| that in the <link linkend="example.first">very first |
| example</link> you want to greet your boss, Big Joe, differently |
| than other users:</para> |
| |
| <programlisting role="template"><html> |
| <head> |
| <title>Welcome!</title> |
| </head> |
| <body> |
| <h1> |
| Welcome ${user}<emphasis><#if user == "Big Joe"></emphasis>, our beloved leader<emphasis></#if></emphasis>! |
| </h1> |
| <p>Our latest product: |
| <a href="${latestProduct.url}">${latestProduct.name}</a>! |
| </body> |
| </html></programlisting> |
| |
| <para>Here you have told FreeMarker that the <quote>, our beloved |
| leader</quote> should be there only if the value of the variable |
| <literal>user</literal> is equal to the string <literal>"Big |
| Joe"</literal>. In general, things between <literal><#if |
| <replaceable>condition</replaceable>></literal> and |
| <literal></#if></literal> tags are skipped if |
| <literal><replaceable>condition</replaceable></literal> is false |
| (the boolean value).</para> |
| |
| <para>Let's look at |
| <literal><replaceable>condition</replaceable></literal> more |
| closely: <literal>==</literal> 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 |
| <literal>==</literal> I have <link |
| linkend="topic.qStart.accessVariables">referenced a |
| variable</link> 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 |
| <emphasis>always</emphasis> be put inside quotation marks.</para> |
| |
| <para>This will print <quote>Pythons are free today!</quote> if |
| their price is 0:</para> |
| |
| <programlisting role="template"><#if animals.python.price == <emphasis>0</emphasis>> |
| Pythons are free today! |
| </#if></programlisting> |
| |
| <para>Similarly as earlier when a string was specified directly, |
| here a number is specified directly (<literal>0</literal>). Note |
| that the number is <emphasis>not</emphasis> quoted. If you quoted |
| it (<literal>"0"</literal>), FreeMarker would misinterpret it as a |
| string literal, and because the price to compare it to is a |
| number, you get an error.</para> |
| |
| <para>This will print "Pythons are not free today!" if their price |
| is not 0:</para> |
| |
| <programlisting role="template"><#if animals.python.price <emphasis>!=</emphasis> 0> |
| Pythons are not free today! |
| </#if></programlisting> |
| |
| <para>As you probably guessed, <literal>!=</literal> means |
| <quote>not equals</quote>.</para> |
| |
| <para>You can write things like this too (using <link |
| linkend="example.qStart.dataModelWithHashes">the data-model used |
| to demonstrate hashes</link>):</para> |
| |
| <programlisting role="template"><#if <emphasis>animals.python.price < animals.elephant.price</emphasis>> |
| Pythons are cheaper than elephants today. |
| </#if></programlisting> |
| |
| <para>With the <literal><#else></literal> tag you can |
| specify what to do if the condition is false. For example:</para> |
| |
| <programlisting role="template"><#if animals.python.price < animals.elephant.price> |
| Pythons are cheaper than elephants today. |
| <emphasis><#else></emphasis> |
| Pythons are not cheaper than elephants today. |
| </#if></programlisting> |
| |
| <para>This prints <quote>Pythons are cheaper than elephants |
| today.</quote> if the price of python is less than the price of |
| elephant, or else it prints <quote>Pythons are not cheaper than |
| elephants today.</quote> You can refine this further by using |
| <literal>elseif</literal>:</para> |
| |
| <programlisting role="template"><#if animals.python.price < animals.elephant.price> |
| Pythons are cheaper than elephants today. |
| <emphasis><#elseif animals.elephant.price < animals.python.price></emphasis> |
| Elephants are cheaper than pythons today. |
| <#else> |
| Elephants and pythons cost the same today. |
| </#if></programlisting> |
| |
| <para>If you have a variable with boolean value (a true/false |
| thing) then you can use it directly as the |
| <literal><replaceable>condition</replaceable></literal> of |
| <literal>if</literal>:</para> |
| |
| <programlisting role="template"><#if animals.python.protected> |
| Pythons are protected animals! |
| </#if></programlisting> |
| </section> |
| |
| <section> |
| <title>The list directive</title> |
| |
| <anchor xml:id="topic.tutorial.list"/> |
| |
| <para>This is needed when you want to list something. For example |
| if you merge this template with the <link |
| linkend="example.qStart.dataModelWithSequences">data-model used |
| earlier to demonstrate sequences</link>:</para> |
| |
| <programlisting role="template"><p>We have these animals: |
| <table border=1> |
| <emphasis><#list animals as animal></emphasis> |
| <tr><td>${<emphasis>animal</emphasis>.name}<td>${<emphasis>animal</emphasis>.price} Euros |
| <emphasis></#list></emphasis> |
| </table></programlisting> |
| |
| <para>then the output will be:</para> |
| |
| <programlisting role="output"><p>We have these animals: |
| <table border=1> |
| <emphasis><tr><td>mouse<td>50 Euros |
| <tr><td>elephant<td>5000 Euros |
| <tr><td>python<td>4999 Euros</emphasis> |
| </table></programlisting> |
| |
| <para>The generic form of the <literal>list</literal> directive |
| is:<literal> <#list <replaceable>sequence</replaceable> as |
| <replaceable>loopVariable</replaceable>><replaceable>repeatThis</replaceable></#list></literal>. |
| The <literal><replaceable>repeatThis</replaceable></literal> part |
| will be repeated for each item in the sequence that you have |
| specified with |
| <literal><replaceable>sequence</replaceable></literal>, one after |
| the other, starting from the first item. In all repetitions |
| <literal><replaceable>loopVariable</replaceable></literal> will |
| hold the value of the current item. This variable exists only |
| between the <literal><#list |
| <replaceable>...</replaceable>></literal> and |
| <literal></#list></literal> tags.</para> |
| |
| <para>The <literal><replaceable>sequence</replaceable></literal> |
| can be any kind of expression. For example we could list the |
| fruits of the example data model like this:</para> |
| |
| <programlisting role="template"><ul> |
| <emphasis><#list misc.fruits as fruit></emphasis> |
| <li>${fruit} |
| <emphasis></#list></emphasis> |
| </ul></programlisting> |
| |
| <para>The <literal>misc.fruits</literal> expression should be |
| familiar to you; it <link |
| linkend="topic.qStart.accessVariables">references a variable in |
| the data-model</link>.</para> |
| |
| <para>A problem with the above example is that if we happen to |
| have 0 fruits, it will still print an empty |
| <literal><ul></ul></literal> instead of just nothing. |
| To avoid that, you can use this form of |
| <literal>list</literal>:</para> |
| |
| <programlisting role="template"><#list misc.fruits> |
| <ul> |
| <emphasis> <#items as fruit></emphasis> |
| <li>${fruit} |
| <emphasis> </#items></emphasis> |
| </ul> |
| </#list></programlisting> |
| |
| <para>Here, the <literal>list</literal> directive represents the |
| listing as a whole, and only the part inside the |
| <literal>items</literal> directive is repeated for each fruit. If |
| we have 0 fruits, everything inside <literal>list</literal> is |
| skipped, hence we will not have <literal>ul</literal> tags in |
| case.</para> |
| |
| <para>Another frequent listing-related task: let's list the fruits |
| separating them with something, like a comma:</para> |
| |
| <programlisting role="template"><p>Fruits: <#list misc.fruits as fruit>${fruit}<emphasis><#sep>, </emphasis></#list></programlisting> |
| |
| <programlisting role="output"><p>Fruits: orange, banana</programlisting> |
| |
| <para>The section covered by <literal>sep</literal> (which we |
| could be written like this too: |
| <literal><replaceable>...</replaceable><#sep>, |
| </#sep></#list></literal>) will be only executed when |
| there will be a next item. Hence there's no comma after the last |
| fruit.</para> |
| |
| <para>Here again, what if we have 0 fruits? Just printing |
| <quote>Fruits:</quote> and then nothing is awkward. A |
| <literal>list</literal>, just like an <literal>if</literal>, can |
| have an <literal>else</literal>, which is executed if there were 0 |
| list items:</para> |
| |
| <programlisting role="template"><p>Fruits: <#list misc.fruits as fruit>${fruit}<#sep>, <emphasis><#else>None</emphasis></#list></programlisting> |
| |
| <note> |
| <para>As a matter of fact, this simplistic example could be |
| written like this, but it uses language devices that are off |
| topic here:</para> |
| |
| <programlisting role="template"><p>Fruits: ${fruits?join(", ", "None")}</programlisting> |
| </note> |
| |
| <para>All these directives (<literal>list</literal>, |
| <literal>items</literal>, <literal>sep</literal>, |
| <literal>else</literal>) can be used together:</para> |
| |
| <programlisting role="template"><#list misc.fruits> |
| <p>Fruits: |
| <ul> |
| <#items as fruit> |
| <li>${fruit}<#sep> and</#sep> |
| </#items> |
| </ul> |
| <#else> |
| <p>We have no fruits. |
| </#list></programlisting> |
| |
| <note> |
| <para>You can read more about these directives <link |
| linkend="ref_directive_list">in the Reference</link>.</para> |
| </note> |
| </section> |
| |
| <section> |
| <title>The include directive</title> |
| |
| <para>With the <literal>include</literal> directive you can insert |
| the content of another file into the template.</para> |
| |
| <para>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 |
| <literal>copyright_footer.html</literal>:</para> |
| |
| <programlisting role="template"><hr> |
| <i> |
| Copyright (c) 2000 <a href="http://www.acmee.com">Acmee Inc</a>, |
| <br> |
| All Rights Reserved. |
| </i></programlisting> |
| |
| <para>Whenever you need that file you simply insert it with the |
| <literal>include</literal> directive:</para> |
| |
| <programlisting role="template"><html> |
| <head> |
| <title>Test page</title> |
| </head> |
| <body> |
| <h1>Test page</h1> |
| <p>Blah blah... |
| <emphasis> <#include "/copyright_footer.html"></emphasis> |
| </body> |
| </html></programlisting> |
| |
| <para>and the output will be:</para> |
| |
| <programlisting role="output"><html> |
| <head> |
| <title>Test page</title> |
| </head> |
| <body> |
| <h1>Test page</h1> |
| <p>Blah blah... |
| <emphasis><hr> |
| <i> |
| Copyright (c) 2000 <a href="http://www.acmee.com">Acmee Inc</a>, |
| <br> |
| All Rights Reserved. |
| </i></emphasis> |
| </body> |
| </html></programlisting> |
| |
| <para>If you change the <literal>copyright_footer.html</literal>, |
| then the visitor will see the new copyright notice on all |
| pages.</para> |
| |
| <note> |
| <para>A much more powerful way of reusing snippets is using |
| macros, but that's an advanced topic <link |
| linkend="dgui_misc_userdefdir">discussed later</link>.</para> |
| </note> |
| </section> |
| </section> |
| |
| <section> |
| <title>Using directives together</title> |
| |
| <para>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 <literal>if</literal> directive inside a |
| <literal>list</literal> directive:</para> |
| |
| <programlisting role="template"><emphasis><#list animals as animal></emphasis> |
| <div<emphasis><#if animal.protected></emphasis><emphasis> </emphasis>class="protected"<emphasis></#if></emphasis>> |
| ${animal.name} for ${animal.price} Euros |
| </div> |
| <emphasis></#list></emphasis></programlisting> |
| |
| <para>Note that since FreeMarker does not interpret text outside FTL |
| tags, interpolations and FTL comments, above you could use the FTL |
| tags inside HTML attributes without problem.</para> |
| </section> |
| |
| <section> |
| <title>Using built-ins</title> |
| |
| <para>The so-called built-ins are like subvariables (or rather like |
| methods, if you know that Java term) that aren't coming from the |
| data-model, but added by FreeMarker to the values. In order to make |
| it clear where subvariables comes from, you have to use |
| <literal>?</literal> (question mark) instead of <literal>.</literal> |
| (dot) to access them. <anchor |
| xml:id="topic.commonlyUsedBuiltIns"/>Examples with some of the most |
| commonly used built-ins:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>user?upper_case</literal> gives the upper case |
| version of the value of <literal>user</literal> (like |
| <quote>JOHN DOE</quote> instead of <quote>John |
| Doe</quote>)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>animal.name?cap_first</literal> give the |
| <literal>animal.name</literal> with its first letter converted |
| to upper case (like <quote>Mouse</quote> instead of |
| <quote>mouse</quote>)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>user?length</literal> gives the number of |
| <emphasis>characters</emphasis> in the value of |
| <literal>user</literal> (8 for <quote>John Doe</quote>)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>animals?size</literal> gives the number of |
| <emphasis>items</emphasis> in the <literal>animals</literal> |
| sequence (3 in our example data-model)</para> |
| </listitem> |
| |
| <listitem> |
| <para>If you are between <literal><#list animals as |
| animal></literal> and the corresponding |
| <literal></#list></literal> tag:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>animal?index</literal> gives the 0-based |
| index of <literal>animal</literal> inside |
| <literal>animals</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>animal?counter</literal> is like |
| <literal>index</literal>, but gives the 1-based index</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>animal?item_parity</literal> gives the |
| strings <quote>odd</quote> or <quote>even</quote>, depending |
| on the current counter parity. This is commonly used for |
| coloring rows with alternating colors, like in |
| <literal><td |
| class="${animal?item_parity}Row"></literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para><literal>product.id?c</literal> formats |
| <literal>product.id</literal> (let's say that's a number, the |
| technical ID of the product in our database) so that it can be |
| safely parsed by a computer process. This is important, as |
| <literal>${product.id}</literal> would format it for human |
| audience, which may contains more complicated (like localized, |
| grouped, etc.) formatting.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Some built-ins require parameters to specify the behavior |
| more, for example:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>animal.protected?string("Y", "N")</literal> |
| return the string <quote>Y</quote> or <quote>N</quote> depending |
| on the boolean value of |
| <literal>animal.protected</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>animal?item_cycle('lightRow', |
| 'darkRow')</literal> is the more generic variant of |
| <literal>item_parity</literal> from earlier.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>fruits?join(", ")</literal>: converts the list to |
| a string by concatenating items, and inserting the parameter |
| separator between each items (like <quote>orange, |
| banana</quote>)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>user?starts_with("J")</literal> gives boolean |
| true of false depending on if <literal>user</literal> starts |
| with the letter <quote>J</quote> or not.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>animals?filter(it -> it.protected)</literal> |
| gives the list of protected animals. To list protected animals |
| only, you could use <literal><#list animals?filter(it -> |
| it.protected) as |
| animal><replaceable>...</replaceable></#list></literal>.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Built-in applications can be chained, like |
| <literal>fruits?join(", ")?upper_case</literal> will first convert |
| the list a to a string, then converts it to upper case. (This is |
| just like you can chain <literal>.</literal>-s (dots) too.)</para> |
| |
| <para>You can find the <link linkend="ref_builtins">full set of |
| built-ins in the Reference</link>.</para> |
| </section> |
| |
| <section> |
| <title>Dealing with missing variables</title> |
| |
| <para>The data-model often has variables that are optional (i.e., |
| sometimes missing). To spot some typical human mistakes, FreeMarker |
| doesn't tolerate references 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.</para> |
| |
| <para><phrase role="forProgrammers">Note for programmers: A |
| non-existent variable and a variable with <literal>null</literal> |
| value is the same for FreeMarker. The "missing" term used here |
| covers both cases.</phrase></para> |
| |
| <para>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 <literal>!</literal> and the default value. Like in the |
| following example, when <literal>user</literal> is missing from data |
| model, the template will behave like if <literal>user</literal>'s |
| value were the string <literal>"visitor"</literal>. (When |
| <literal>user</literal> isn't missing, this template behaves exactly |
| like with <literal>${user}</literal>):</para> |
| |
| <programlisting role="template"><h1>Welcome ${user<emphasis>!"visitor"</emphasis>}!</h1></programlisting> |
| |
| <para>You can ask whether a variable isn't missing by putting |
| <literal>??</literal> after its name. Combining this with the |
| already introduced <literal>if</literal> directive you can skip the |
| whole greeting if the <literal>user</literal> variable is |
| missing:</para> |
| |
| <programlisting role="template"><#if <emphasis>user??</emphasis>><h1>Welcome ${user}!</h1></#if></programlisting> |
| |
| <para>Regarding variable accessing with multiple steps, like |
| <literal>animals.python.price</literal>, writing |
| <literal>animals.python.price!0</literal> is correct only if |
| <literal>animals.python</literal> is never missing and only the last |
| subvariable, <literal>price</literal>, is possibly missing (in which |
| case here we assume it's <literal>0</literal>). If |
| <literal>animals</literal> or <literal>python</literal> is missing, |
| the template processing will stop with an "undefined variable" |
| error. To prevent that, you have to write |
| <literal>(animals.python.price)!0</literal>. In that case the |
| expression will be <literal>0</literal> even if |
| <literal>animals</literal> or <literal>python</literal> is missing. |
| Same logic goes for <literal>??</literal>; |
| <literal>animals.python.price??</literal> versus |
| <literal>(animals.python.price)??</literal>.</para> |
| </section> |
| |
| <section xml:id="dgui_quickstart_template_autoescaping"> |
| <title>Escaping for HTML, XML and other markup</title> |
| |
| <para>Let's say the template generates HTML, and you insert values |
| with <literal>${<replaceable>...</replaceable>}</literal> that are |
| plain text (not HTML), like company names coming from a database. |
| Characters that has special meaning in HTML must be |
| <emphasis>escaped</emphasis> in such values, like if |
| <literal>name</literal> is <quote>Someone & Co.</quote> then |
| <literal>${name}</literal> should print <quote>Someone |
| <emphasis>&amp;</emphasis> Co.</quote>.</para> |
| |
| <para>FreeMarker automatically escapes all values printed with |
| <literal>${<replaceable>...</replaceable>}</literal> <emphasis>if |
| it's properly configured</emphasis> (that's the responsibility of |
| the programmers; <link |
| linkend="pgui_config_outputformatsautoesc">see here how</link>). The |
| recommended practice is using <literal>ftlh</literal> file extension |
| to activate HTML auto-escaping, and <literal>ftlx</literal> file |
| extension to activate XML auto-escaping.</para> |
| |
| <para>You can try if auto-escaping is on like |
| <literal>${"<"}</literal> and then checking the raw output (for |
| HTML or XML escaping). If it's not, and the configuration won't be |
| adjusted, add this as the very first line of the template:</para> |
| |
| <programlisting role="template"><#ftl output_format="HTML"></programlisting> |
| |
| <para>(Use <literal>"XML"</literal> instead of |
| <literal>"HTML"</literal> above if you generate XML.)</para> |
| |
| <para>If the string value to print deliberately contains markup, |
| auto-escaping must be prevented like |
| <literal>${<replaceable>value</replaceable>?no_esc}</literal>.</para> |
| |
| <para>You can find out much more about auto-escaping and output |
| formats <link linkend="dgui_misc_autoescaping">here...</link></para> |
| |
| <note> |
| <para>The kind of automatic escaping described here requires at |
| least FreeMarker 2.3.24. If you have to use an earlier version, |
| use the deprecated <link |
| linkend="ref_directive_escape"><literal>escape</literal> |
| directive</link> instead.</para> |
| </note> |
| </section> |
| </section> |
| </chapter> |
| |
| <chapter xml:id="dgui_datamodel"> |
| <title>Values, Types</title> |
| |
| <section xml:id="dgui_datamodel_basics"> |
| <title>Basics</title> |
| |
| <note> |
| <para>It is assumed that you have already read the <xref |
| linkend="dgui_quickstart"/> chapter.</para> |
| </note> |
| |
| <para>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.</para> |
| |
| <section xml:id="topic.value"> |
| <title>What is a value?</title> |
| |
| <indexterm> |
| <primary>value</primary> |
| </indexterm> |
| |
| <para><phrase role="forProgrammers">Real programmers can safely skip |
| this section.</phrase></para> |
| |
| <para>Examples of <emphasis>values</emphasis> 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:</para> |
| |
| <programlisting role="dataModel" xml:id="example.stdDataModel">(root) |
| | |
| +- user = "Big Joe" |
| | |
| +- today = Jul 6, 2007 |
| | |
| +- todayHoliday = false |
| | |
| +- lotteryNumbers |
| | | |
| | +- (1st) = 20 |
| | | |
| | +- (2nd) = 14 |
| | | |
| | +- (3rd) = 42 |
| | | |
| | +- (4th) = 8 |
| | | |
| | +- (5th) = 15 |
| | |
| +- cargo |
| | |
| +- name = "coal" |
| | |
| +- weight = 40 |
| </programlisting> |
| |
| <para>We say that the <emphasis>value</emphasis> of the the |
| <literal>user</literal> variable is "Big Joe" (a string), the |
| <emphasis>value</emphasis> of <literal>today</literal> is Jul 6, |
| 2007 (a date), the <emphasis>value</emphasis> of |
| <literal>todayHoliday</literal> is false (a boolean, ie. a yes/no |
| thing). The <emphasis>value</emphasis> of |
| <literal>lotteryNumbers</literal> is the sequence that contains 20, |
| 14, 42, 8, 15. Surely <literal>lotteryNumbers</literal> is multiple |
| values in the sense that it <emphasis>contains</emphasis> multiple |
| values (for example, the 2nd item in it is a the |
| <emphasis>value</emphasis> 14), but still, |
| <literal>lotteryNumbers</literal> 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 |
| <emphasis>value</emphasis> of <literal>cargo</literal>, which is a |
| hash (a box-like thing again).So, a value is something that can be |
| stored in a variable (e.g., in <literal>user</literal> or |
| <literal>cargo</literal> or <literal>cargo.name</literal>). But a |
| value need not be stored in a variable to be called a value, for |
| example we have the value 100 here:</para> |
| |
| <programlisting role="template"><#if cargo.weight < <emphasis>100</emphasis>>Light cargo</#if></programlisting> |
| |
| <para>The temporaly result of a calculations are also called values, |
| like 20 and 120 when this template is executed (it will print |
| 120):</para> |
| |
| <programlisting role="template">${cargo.weight / 2 + 100}</programlisting> |
| |
| <para>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 |
| (<literal>${<replaceable>...</replaceable>}</literal>), and the |
| template execution goes on and all these values gone.</para> |
| |
| <para>Certainly now you feel what the value term means.</para> |
| </section> |
| |
| <section> |
| <title>What is type?</title> |
| |
| <para>Values have an important aspect, their type. For example the |
| type of the value of the <literal>user</literal> variable is string, |
| and the type of the value of the <literal>lotteryNumbers</literal> |
| 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 <literal>${user / 2}</literal> is an error, but |
| <literal>${cargo.weight / 2}</literal> works and prints 20, since |
| division only does make sense for a number, but not for a string. |
| Or, using dot like in <literal>cargo.name</literal> does make sense |
| only if <literal>cargo</literal> is a hash. Or, you can list with |
| <literal><#list <replaceable>...</replaceable>></literal> |
| sequences only. Or, the condition of <literal><#if |
| ...></literal> must be a boolean. And so on.</para> |
| |
| <note> |
| <para>A little terminology... Saying "a boolean" or "a boolean |
| value" or "a value of type boolean" are all the same.</para> |
| </note> |
| |
| <para xml:id="topic.multitype"><indexterm> |
| <primary>Multi-typed value</primary> |
| </indexterm>A value can have multiple types at the same time, |
| although it's rarely utilized. For example in the data-model below |
| <literal>mouse</literal> is both a string and a hash:</para> |
| |
| <programlisting role="dataModel">(root) |
| | |
| +- mouse = "Yerri" |
| | |
| +- age = 12 |
| | |
| +- color = "brown"</programlisting> |
| |
| <para>If you merge this template with the above data-model:</para> |
| |
| <programlisting role="template">${mouse} <#-- uses mouse as a string --> |
| ${mouse.age} <#-- uses mouse as a hash --> |
| ${mouse.color} <#-- uses mouse as a hash --></programlisting> |
| |
| <para>the output will be:</para> |
| |
| <programlisting role="output">Yerri |
| 12 |
| brown</programlisting> |
| </section> |
| |
| <section> |
| <title>The data-model is a hash</title> |
| |
| <para>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 <literal>user</literal>, that means |
| that you want the "user" variable stored in the root hash. Like if |
| you were writing <literal>root.user</literal>, except that there is |
| no variable called "root" so that wouldn't work.</para> |
| |
| <para>Some may get confused by the fact that our example data-model, |
| that is, the root hash, contains further hashes and sequences |
| (<literal>lotteryNumbers</literal> and <literal>cargo</literal>). |
| 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.</para> |
| </section> |
| </section> |
| |
| <section xml:id="dgui_datamodel_types"> |
| <title>The types</title> |
| |
| <para>The suppored types are:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><link linkend="dgui_datamodel_scalar" |
| os="">Scalars:</link></para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>String</para> |
| </listitem> |
| |
| <listitem> |
| <para>Number</para> |
| </listitem> |
| |
| <listitem> |
| <para>Boolean</para> |
| </listitem> |
| |
| <listitem> |
| <para>Date-like (date, time, or date-time)</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="dgui_datamodel_container">Containers:</link></para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>Hash</para> |
| </listitem> |
| |
| <listitem> |
| <para>Sequence</para> |
| </listitem> |
| |
| <listitem> |
| <para>Collection</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Subroutines:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><link linkend="dgui_datamodel_method">Methods and |
| functions</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="dgui_datamodel_userdefdir">User-defined |
| directives</link></para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Miscellaneous/seldom used:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><link linkend="dgui_datamodel_node">Node</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="dgui_datamodel_markupoutput">Markup |
| output</link></para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| </itemizedlist> |
| |
| <section xml:id="dgui_datamodel_scalar"> |
| <title>Scalars</title> |
| |
| <anchor xml:id="topic.designer.scalarVariable"/> |
| |
| <para>These are the basic, simple kind of values. They can |
| be:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><indexterm> |
| <primary>string</primary> |
| |
| <secondary>the FTL value type</secondary> |
| </indexterm>String: It is simple text, e.g., the name of a |
| product.</para> |
| |
| <para>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., |
| <literal>"green mouse"</literal> or <literal>'green |
| mouse'</literal>. (More details regarding the syntax can be |
| found <link linkend="dgui_template_exp_direct_string" |
| xml:lang="">later</link>.)</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>number</primary> |
| |
| <secondary>the FTL value type</secondary> |
| </indexterm>Number: For example the price of a product. |
| <phrase role="forProgrammers">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.</phrase></para> |
| |
| <para>If you want to give a numerical value directly in the |
| template, then you write for example: <literal>150</literal> or |
| <literal>-90.05</literal> or <literal>0.001</literal>. (More |
| details regarding the syntax can be found <link |
| linkend="dgui_template_exp_direct_number" |
| xml:lang="">later</link>.)</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>boolean</primary> |
| |
| <secondary>the FTL value type</secondary> |
| </indexterm>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 <literal>if</literal> directive, like <literal><#if |
| loggedIn |
| ><replaceable>...</replaceable></#if></literal> or |
| <literal><#if price == |
| 0><replaceable>...</replaceable></#if></literal>; in |
| the last case the result of the <literal>price == 0</literal> |
| part is a boolean value.</para> |
| |
| <para>In the templates you can directly specify a boolean with |
| the reserved words <literal>true</literal> and |
| <literal>false</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>date</primary> |
| |
| <secondary>the FTL value type</secondary> |
| </indexterm><indexterm> |
| <primary>time</primary> |
| |
| <secondary>the FTL value type</secondary> |
| </indexterm><indexterm> |
| <primary>date-time</primary> |
| |
| <secondary>the FTL value type</secondary> |
| </indexterm>Date: A date-like value stores date/time related |
| data. It has three variations:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Date: Like April 4, 2003. Day precision, no time of |
| day part.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Time: Like 10:19:18 PM. Millisecond precision, no date |
| part.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Date-time (sometimes called "time stamp") as April 4, |
| 2003 10:19:18 PM. Both date and time, with millisecond |
| precision.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>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 <link |
| linkend="ref_builtin_date_datetype">later</link>.</para> |
| |
| <para>It is possible to define date-like values directly in |
| templates, but this is an advanced topic that will be explained |
| <link linkend="ref_builtin_string_date">later</link>.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Bear in mind that FreeMarker distinguishes strings from |
| numbers, booleans and date-like values. For example, while the |
| string <literal>"150"</literal> looks like the number |
| <literal>150</literal>, 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.</para> |
| </section> |
| |
| <section xml:id="dgui_datamodel_container"> |
| <title>Containers</title> |
| |
| <remark>Re-explanation of hashes and sequences from a more |
| ''professional'' viewpoint as earlier, and some meditation about |
| them.</remark> |
| |
| <para>These are the values whose purpose is to contain other |
| variables; they are just containers. The contained variables are |
| often referred as <emphasis>sub variables</emphasis>. The container |
| types are:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><indexterm> |
| <primary>hash</primary> |
| |
| <secondary>the FTL value type</secondary> |
| </indexterm>Hash: Associates a unique lookup name with each of |
| its sub variables. The name is an unrestricted string. A hash |
| <emphasis>doesn't define an ordering</emphasis> 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.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>sequence</primary> |
| |
| <secondary>the FTL value type</secondary> |
| </indexterm>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 |
| <emphasis>indexes</emphasis> 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.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>collection</primary> |
| |
| <secondary>the FTL value type</secondary> |
| </indexterm>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 <link |
| linkend="ref.directive.list"><literal>list</literal> |
| directive</link>. Furthermore, very often they can only be |
| listed once. (If you are a Java programmer, |
| <quote>iterable</quote> would be a more fitting name than |
| collection.)</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Note that since <link linkend="topic.multitype">a value can |
| have multiple types</link>, 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.</para> |
| |
| <para>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.</para> |
| |
| <para>The data-model itself (or better said the root of it) is a |
| hash.</para> |
| |
| <para>FreeMarker templates don't support modifying the contents of |
| containers (such as adding, removing or replacing sub variables), |
| and it assumes that their content won't change during template |
| processing. (But you can make new container values by adding |
| together two existing container values with <literal>+</literal>; |
| see that in the <link linkend="exp_cheatsheet">chapter about |
| expressions</link>, and please note the performance |
| consequences.)</para> |
| </section> |
| |
| <section> |
| <title>Subroutines</title> |
| |
| <section xml:id="dgui_datamodel_method"> |
| <title>Methods and functions</title> |
| |
| <anchor xml:id="topic.designer.methodVariable"/> |
| |
| <indexterm> |
| <primary>method</primary> |
| |
| <secondary>the FTL value type</secondary> |
| </indexterm> |
| |
| <para>A value that is a method or a function is used to calculate |
| another value, influenced by the parameters you give to it.</para> |
| |
| <para><phrase role="forProgrammers">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.</phrase></para> |
| |
| <para>Suppose that programmers have put the method variable |
| <literal>avg</literal> 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 <literal>avg</literal>, then you get |
| the value 4.</para> |
| |
| <para>The usage of methods will be explained <link |
| linkend="dgui_template_exp_methodcall">later</link>, but perhaps |
| this example helps to understand what methods are:</para> |
| |
| <programlisting role="template">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)}</programlisting> |
| |
| <para>this will output:</para> |
| |
| <programlisting role="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</programlisting> |
| |
| <para>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 (<phrase |
| role="forProgrammers">as they reflect the methods of Java |
| objects</phrase>), and functions are defined in templates (with |
| the <link |
| linkend="ref.directive.function"><literal>function</literal> |
| directive</link> -- an advanced topic), but both can be used on |
| the same way.</para> |
| </section> |
| |
| <section xml:id="dgui_datamodel_userdefdir"> |
| <title>User-defined directives</title> |
| |
| <indexterm> |
| <primary>macro</primary> |
| |
| <secondary>the FTL value type</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>directive</primary> |
| |
| <secondary>the FTL value type</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>user-defined directive</primary> |
| |
| <secondary>the FTL value type</secondary> |
| </indexterm> |
| |
| <para>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 |
| <link linkend="dgui_misc_userdefdir">later</link> in its own |
| chapter.</para> |
| |
| <para><phrase role="forProgrammers">For programmer types: |
| user-defined directives (such as macros), are first-class values |
| too, just like functions/methods are.</phrase></para> |
| |
| <para>Just to get an idea about user-defined directives (so just |
| ignore this if you won't understand), assume we have a variable, |
| <literal>box</literal>, 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 <literal>box</literal> variable could be |
| used in the template like this (for example):</para> |
| |
| <programlisting role="template"><@<emphasis>box</emphasis> title="Attention!"> |
| Too much copy-pasting may leads to |
| maintenance headaches. |
| </@<emphasis>box</emphasis>></programlisting> |
| </section> |
| |
| <section> |
| <title>Function/method versus user-defined directive</title> |
| |
| <para>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:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>... the purpose of it is generating a piece of the |
| output that's not just a single value, and typically involves |
| markup. The template language was designed for printing to the |
| output directly, piece by piece, as it goes though |
| <literal>list</literal> loops, <literal>if</literal>-s, etc. |
| Building up a string value in a variable then returning it is |
| much less convenient.</para> |
| </listitem> |
| |
| <listitem> |
| <para>... 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.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>... it will do flow control on the caller side (like for |
| example <literal>list</literal> or <literal>if</literal> |
| directives do). You just can't do that with a |
| function/method.</para> |
| </listitem> |
| |
| <listitem> |
| <para>... you are using legacy escaping via the |
| <literal>escape</literal> directive (instead of <link |
| linkend="dgui_misc_autoescaping">auto-escaping</link>), and |
| the result contains markup. When you print the result with |
| <literal>${<replaceable>...</replaceable>}</literal>, the |
| markup will be escaped and thus ruined, but if it's printed by |
| a directive call |
| (<literal><@<replaceable>...</replaceable>></literal>), |
| it won't be.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>The Java methods of FreeMarker-unaware Java objects are |
| normally visible as methods in templates, regardless of the nature |
| of the Java method; you have no choice there.</para> |
| </section> |
| </section> |
| |
| <section> |
| <title>Miscellaneous</title> |
| |
| <section xml:id="dgui_datamodel_node"> |
| <title>Nodes</title> |
| |
| <indexterm> |
| <primary>node</primary> |
| |
| <secondary>the FTL value type</secondary> |
| </indexterm> |
| |
| <para>Node variables represent a node in a tree structure, and are |
| used mostly with <link linkend="xgui">XML processing</link>, which |
| is an advanced, and specialized topic.</para> |
| |
| <para>Still, a quick overview <emphasis>for advanced |
| users</emphasis>: 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 <literal>h1</literal> element in an XHTML document, |
| then its name could be <literal>"h1"</literal>, it's node type |
| could be <literal>"element"</literal>, and it's namespace could be |
| <literal>"http://www.w3.org/1999/xhtml"</literal>. 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 <link |
| linkend="ref_builtins_node">in a later chapter</link> (that you |
| don't have to understand at this point).</para> |
| </section> |
| |
| <section xml:id="dgui_datamodel_markupoutput"> |
| <title>Markup output</title> |
| |
| <indexterm> |
| <primary>markup output</primary> |
| |
| <secondary>the FTL value type</secondary> |
| </indexterm> |
| |
| <para>This type is related to <link |
| linkend="dgui_misc_autoescaping">auto-escaping mechanism</link> |
| introduced FreeMarker 2.3.24; you can <link |
| linkend="dgui_misc_autoescaping_movalues">read about this type |
| there</link>. But in short, this is a value that stores text |
| that's already in the output markup format (like HTML, XML, RTF, |
| etc.), and hence must not be auto-escaped.</para> |
| |
| <para>Values of this type are usually produced inside the |
| templates (like with <link |
| linkend="ref_builtin_no_esc"><literal>no_esc</literal> |
| built-in</link> or <link linkend="ref_directive_assign">output |
| capturing assignments</link>), but can also be part of the |
| data-model. Such values in the data-model are useful for example |
| if you have message resources that sometimes contain the message |
| in HTML format, rather than in plain text. If the data-model uses |
| HTML markup output values for those messages instead of strings, |
| then the template author need not know which messages contain HTML |
| and which plain text, as double escaping will be avoided |
| automatically when the message is inserted with |
| <literal>${<replaceable>...</replaceable>}</literal>.</para> |
| </section> |
| </section> |
| </section> |
| </chapter> |
| |
| <chapter xml:id="dgui_template"> |
| <title>The Template</title> |
| |
| <indexterm> |
| <primary>template</primary> |
| </indexterm> |
| |
| <note> |
| <para>It is assumed that you have already read the <xref |
| linkend="dgui_quickstart"/> and the <xref linkend="dgui_datamodel"/> |
| chapter.</para> |
| </note> |
| |
| <section xml:id="dgui_template_overallstructure"> |
| <title>Overall structure</title> |
| |
| <para>Templates are in fact programs you write in a language called |
| <indexterm> |
| <primary>FTL</primary> |
| </indexterm><emphasis role="term">FTL</emphasis> (for FreeMarker |
| Template Language). This is a quite simple programming language |
| designed for writing templates and nothing else.</para> |
| |
| <para>A template (= FTL program) is a mix of the following |
| sections:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><emphasis role="term">Text</emphasis><indexterm> |
| <primary>text</primary> |
| </indexterm>: Text that will be printed to the output as |
| is.</para> |
| </listitem> |
| |
| <listitem> |
| <para><emphasis role="term">Interpolation</emphasis><indexterm> |
| <primary>interpolation</primary> |
| </indexterm>: These sections will be replaced with a calculated |
| value in the output. Interpolations are delimited by |
| <literal>${</literal> and <literal>}</literal> (or with |
| <literal>#{</literal> and <literal>}</literal>, but that shouldn't |
| be used anymore; <link |
| linkend="ref_depr_numerical_interpolation">see more |
| here</link>).</para> |
| </listitem> |
| |
| <listitem> |
| <para><emphasis role="term">FTL tags</emphasis><indexterm> |
| <primary>FTL tag</primary> |
| </indexterm>: FTL tags are a bit similar to HTML tags, but they |
| are instructions to FreeMarker and will not be printed to the |
| output.</para> |
| </listitem> |
| |
| <listitem> |
| <para><emphasis role="term">Comments</emphasis><indexterm> |
| <primary>comment</primary> |
| </indexterm><indexterm> |
| <primary><#--...--></primary> |
| </indexterm><indexterm> |
| <primary>#</primary> |
| </indexterm>: Comments are similar to HTML comments, but they |
| are delimited by <literal><#--</literal> and |
| <literal>--></literal>. Comments will be ignored by FreeMarker, |
| and will not be written to the output.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Let's see a concrete template. I have marked the template's |
| components with colors: <phrase role="markedText">text</phrase>, |
| <phrase role="markedInterpolation">interpolation</phrase>, <phrase |
| role="markedFTLTag">FTL tag</phrase>, <phrase |
| role="markedComment">comment</phrase>. With the <phrase |
| role="markedInvisibleText">[BR]</phrase>-s I intend to visualize the |
| <link linkend="gloss.lineBreak">line breaks</link>.</para> |
| |
| <programlisting role="template"><phrase role="markedText"><html><phrase |
| role="markedInvisibleText">[BR]</phrase> |
| <head><phrase role="markedInvisibleText">[BR]</phrase> |
| Â Â <title>Welcome!</title><phrase role="markedInvisibleText">[BR]</phrase> |
| </head><phrase role="markedInvisibleText">[BR]</phrase> |
| <body><phrase role="markedInvisibleText">[BR]</phrase> |
|   <phrase role="markedComment"><#-- Greet the user with his/her name --></phrase><phrase |
| role="markedInvisibleText">[BR]</phrase> |
|   <h1>Welcome <phrase role="markedInterpolation">${user}</phrase>!</h1><phrase |
| role="markedInvisibleText">[BR]</phrase> |
|   <p>We have these animals:<phrase role="markedInvisibleText">[BR]</phrase> |
| Â Â <ul><phrase role="markedInvisibleText">[BR]</phrase> |
|   <phrase role="markedFTLTag"><#list animals as animal></phrase><phrase |
| role="markedInvisibleText">[BR]</phrase> |
|     <li><phrase role="markedInterpolation">${animal.name}</phrase> for <phrase |
| role="markedInterpolation">${animal.price}</phrase> Euros<phrase |
| role="markedInvisibleText">[BR]</phrase> |
| Â Â <phrase role="markedFTLTag"></#list></phrase><phrase |
| role="markedInvisibleText">[BR]</phrase> |
| Â Â </ul><phrase role="markedInvisibleText">[BR]</phrase> |
| </body><phrase role="markedInvisibleText">[BR]</phrase> |
| </html></phrase></programlisting> |
| |
| <para>FTL distinguishes upper case and lower case letters. So |
| <literal>list</literal> is good directive name, while |
| <literal>List</literal> is not. Similarly <literal>${name}</literal> |
| is not the same as <literal>${Name}</literal> or |
| <literal>${NAME}</literal></para> |
| |
| <para>It is important to realize that <phrase |
| role="markedInterpolation">interpolations</phrase> can be used in |
| <phrase role="markedText">text</phrase> (and in string literal |
| expressions; see <link |
| linkend="dgui_template_exp_stringop_interpolation">later</link>) |
| only.</para> |
| |
| <para>An <phrase role="markedFTLTag">FTL tag</phrase> can't be inside |
| another <phrase role="markedFTLTag">FTL tag</phrase> nor inside an |
| <phrase role="markedInterpolation">interpolation</phrase>. For example |
| this is <emphasis>WRONG</emphasis>: <literal><#if <#include |
| 'foo'>='bar'>...</#if></literal></para> |
| |
| <para><phrase role="markedComment">Comments</phrase> can be placed |
| inside <phrase role="markedFTLTag">FTL tags</phrase> and <phrase |
| role="markedInterpolation">interpolations</phrase>. For |
| example:</para> |
| |
| <programlisting role="template"><phrase role="markedText"><h1>Welcome <phrase |
| role="markedInterpolation">${user <phrase role="markedComment"><#-- The name of user --></phrase>}</phrase>!</h1><phrase |
| role="markedInvisibleText">[BR]</phrase> |
| <p>We have these animals:<phrase role="markedInvisibleText">[BR]</phrase> |
| <ul><phrase role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedFTLTag"><#list <phrase role="markedComment"><#-- some comment... --></phrase> animals as <phrase |
| role="markedComment"><#-- again... --></phrase> animal></phrase><phrase |
| role="markedInvisibleText">[BR]</phrase></phrase> |
| <replaceable>...</replaceable></programlisting> |
| |
| <note> |
| <para>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 <phrase |
| role="markedText">text</phrase> 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 <link |
| linkend="dgui_misc_whitespace">later</link>.</para> |
| </note> |
| </section> |
| |
| <section xml:id="dgui_template_directives"> |
| <title>Directives</title> |
| |
| <indexterm> |
| <primary><#...></primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>#</primary> |
| </indexterm> |
| |
| <anchor xml:id="term.designer.directive"/> |
| |
| <remark>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.</remark> |
| |
| <para><indexterm> |
| <primary>directive</primary> |
| </indexterm>You use FTL tags to call <emphasis |
| role="term">directives</emphasis>. In the example you have called the |
| <literal>list</literal> directive. Syntactically you have done it with |
| two tags: <literal><#list animals as animal></literal> and |
| <literal></#list></literal>.</para> |
| |
| <para><indexterm> |
| <primary>FTL tag</primary> |
| </indexterm>There are two kind of FTL tags:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Start-tag: |
| <literal><#<replaceable>directivename</replaceable> |
| <replaceable>parameters</replaceable>></literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>End-tag: |
| <literal></#<replaceable>directivename</replaceable>></literal></para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>This is similar to HTML or XML syntax, except that the tag name |
| starts with <literal>#</literal>. 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 <literal><#if |
| <replaceable>something</replaceable>><replaceable>...</replaceable></#if></literal>, |
| but just <literal><#include |
| <replaceable>something</replaceable>></literal> as FreeMarker knows |
| that the <literal>include</literal> directive can't have nested |
| content.</para> |
| |
| <para>The format of the |
| <literal><replaceable>parameters</replaceable></literal> depends on |
| the |
| <literal><replaceable>directivename</replaceable></literal>.</para> |
| |
| <para>In fact there are two types of directives: <link |
| linkend="gloss.predefinedDirective">predefined directives</link> and |
| <link linkend="gloss.userDefinedDirective">user-defined |
| directives</link>. For user-defined directives you use |
| <literal>@</literal> instead of <literal>#</literal>, for example |
| <literal><@mydirective |
| <replaceable>parameters</replaceable>><replaceable>...</replaceable></@mydirective></literal>. |
| Further difference is that if the directive has no nested content, you |
| must use a tag like <literal><@mydirective |
| <replaceable>parameters</replaceable> /></literal>, similarly as in |
| XML (e.g. <literal><img <replaceable>...</replaceable> |
| /></literal>). But user-defined directives is an advanced topic |
| that will be discussed <link |
| linkend="dgui_misc_userdefdir">later</link>.</para> |
| |
| <para>FTL tags, like HTML tags, must be properly nested. So the code |
| below is wrong, as the <literal>if</literal> directive is both inside |
| and outside of the nested content of the <literal>list</literal> |
| directive:</para> |
| |
| <programlisting role="template"><ul> |
| <emphasis><#list animals as animal></emphasis> |
| <li>${animal.name} for ${animal.price} Euros |
| <emphasis><#if user == "Big Joe"></emphasis> |
| (except for you) |
| <emphasis></#list></emphasis> <#-- WRONG! The "if" has to be closed first. --> |
| <emphasis></#if></emphasis> |
| </ul></programlisting> |
| |
| <para>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.</para> |
| |
| <para>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.</para> |
| |
| <para>FreeMarker ignores superfluous <link |
| linkend="gloss.whiteSpace">white-space</link> inside FTL tags. So you |
| can write this:</para> |
| |
| <programlisting role="template"><phrase role="markedText"><phrase |
| role="markedFTLTag"><#list<phrase role="markedInvisibleText">[BR]</phrase> |
|   animals       as<phrase role="markedInvisibleText">[BR]</phrase> |
| Â Â Â Â Â animal<phrase role="markedInvisibleText">[BR]</phrase> |
| ></phrase><phrase role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedInterpolation">${animal.name}</phrase> for <phrase |
| role="markedInterpolation">${animal.price}</phrase>Â Euros<phrase |
| role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedFTLTag"></#list    ></phrase></phrase></programlisting> |
| |
| <para>You may not, however, insert white-space between the |
| <literal><</literal> or <literal></</literal> and the directive |
| name.</para> |
| |
| <para>The complete list and description of all directives can be found |
| in the <xref linkend="ref_directives"/> (but I recommend that you look |
| at the chapter about expressions first).</para> |
| |
| <note> |
| <para>FreeMarker can be configured to use <literal>[</literal> and |
| <literal>]</literal> instead of <literal><</literal> and |
| <literal>></literal> in the FTL tags and FTL comments, like |
| <literal>[#if user == "Big |
| Joe"]<replaceable>...</replaceable>[/#if]</literal>. For more |
| information read: <xref |
| linkend="dgui_misc_alternativesyntax"/>.</para> |
| </note> |
| |
| <note> |
| <para>FreeMarker can be configured so that it understands predefined |
| directives without <literal>#</literal> (like <literal><if user |
| == "Big |
| Joe"><replaceable>...</replaceable></if></literal>). |
| However we don't recommend the usage of this mode. For more |
| information read: <xref linkend="ref_depr_oldsyntax"/></para> |
| </note> |
| </section> |
| |
| <section xml:id="dgui_template_exp"> |
| <title>Expressions</title> |
| |
| <para><indexterm> |
| <primary>expression</primary> |
| </indexterm>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 <literal>(x + |
| y)/2</literal> resolves to the numerical value 6.5.</para> |
| |
| <para>Before we go into details, let's see some concrete |
| examples:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>When you supply value for interpolations: The usage of |
| interpolations is |
| <literal>${<replaceable>expression</replaceable>}</literal> where |
| expression gives the value you want to insert into the output as |
| text. So <literal>${(5 + 8)/2}</literal> prints <quote>6.5</quote> |
| to the output (or possibly <quote>6,5</quote> if the language of |
| your output is not US English).</para> |
| </listitem> |
| |
| <listitem> |
| <para>When you supply a value for the directive parameter: You |
| have already seen the <literal>if</literal> directive in the |
| Getting Started section. The syntax of this directive is: |
| <literal><#if |
| <replaceable>expression</replaceable>><replaceable>...</replaceable></#if></literal>. |
| The expression here must evaluate to a boolean value. For example |
| in <literal><#if 2 < 3></literal> the <literal>2 < |
| 3</literal> (2 is less than 3) is an expression which evaluates to |
| <literal>true</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <section xml:id="exp_cheatsheet"> |
| <title>Quick overview (cheat sheet)</title> |
| |
| <para>This is a reminder for those of you who already know |
| FreeMarker or are just experienced programmers:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><link linkend="dgui_template_exp_direct">Specify values |
| directly</link></para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><link |
| linkend="dgui_template_exp_direct_string">Strings</link>: |
| <literal>"Foo"</literal> or <literal>'Foo'</literal> or |
| <literal>"It's \"quoted\""</literal> or <literal>'It\'s |
| "quoted"'</literal> or |
| <literal>r"C:\raw\string"</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="dgui_template_exp_direct_number">Numbers</link>: |
| <literal>123.45</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="dgui_template_exp_direct_boolean">Booleans</link>: |
| <literal>true</literal>, <literal>false</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="dgui_template_exp_direct_seuqence">Sequences</link>: |
| <literal>["foo", "bar", 123.45]</literal>; Ranges: |
| <literal>0..9</literal>, <literal>0..<10</literal> (or |
| <literal>0..!10</literal>), <literal>0..</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="dgui_template_exp_direct_hash">Hashes</link>: |
| <literal>{"name":"green mouse", |
| "price":150}</literal></para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="dgui_template_exp_var">Retrieving |
| variables</link></para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><link |
| linkend="dgui_template_exp_var_toplevel">Top-level |
| variables</link>: <literal>user</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="dgui_template_exp_var_hash">Retrieving |
| data from a hash</link>: <literal>user.name</literal>, |
| <literal>user["name"]</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="dgui_template_exp_var_sequence">Retrieving data |
| from a sequence</link>: |
| <literal>products[5]</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="dgui_template_exp_var_special">Special |
| variable</link>: <literal>.main</literal></para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="dgui_template_exp_stringop">String |
| operations</link></para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><link |
| linkend="dgui_template_exp_stringop_interpolation">Interpolation |
| and concatenation</link>: |
| <literal>"Hello ${user}!"</literal> (or <literal>"Hello |
| "Â +Â user + "!"</literal>)</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="dgui_template_exp_get_character">Getting a |
| character</link>: <literal>name[0]</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="dgui_template_exp_stringop_slice">String |
| slice:</link> Inclusive end: <literal>name[0..4]</literal>, |
| Exclusive end: <literal>name[0..<5]</literal>, |
| Length-based (lenient): <literal>name[0..*5]</literal>, |
| Remove starting: <literal>name[5..]</literal></para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="dgui_template_exp_sequenceop">Sequence |
| operations</link></para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><link |
| linkend="dgui_template_exp_sequenceop_cat">Concatenation</link>: |
| <literal>users + ["guest"]</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="dgui_template_exp_seqenceop_slice">Sequence |
| slice</link>: Inclusive end: |
| <literal>products[20..29]</literal>, Exclusive end: |
| <literal>products[20..<30]</literal>, Length-based |
| (lenient): <literal>products[20..*10]</literal>, Remove |
| starting: <literal>products[20..]</literal></para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="dgui_template_exp_hashop">Hash |
| operations</link></para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><link |
| linkend="dgui_template_exp_hashop_cat">Concatenation</link>: |
| <literal>passwords + { "joe": "secret42" }</literal></para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="dgui_template_exp_arit">Arithmetical |
| calculations</link>: <literal>(x * 1.5 + 10) / 2 - y % |
| 100</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="dgui_template_exp_comparison">Comparison</link>: |
| <literal>x == y</literal>, <literal>x != y</literal>, |
| <literal>x < y</literal>, <literal>x > y</literal>, |
| <literal>x >= y</literal>, <literal>x <= y</literal>, |
| <literal>x lt y</literal>, <literal>x lte y</literal>, |
| <literal>x gt y</literal>, <literal>x gte y</literal>, |
| ...etc.</para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="dgui_template_exp_logicalop">Logical |
| operations</link>: <literal>!registered && (firstVisit |
| || fromEurope)</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="dgui_template_exp_builtin">Built-ins</link>: |
| <literal>name?upper_case</literal>, |
| <literal>path?ensure_starts_with('/')</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="dgui_template_exp_methodcall">Method |
| call</link>: <literal>repeat("What", 3)</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="dgui_template_exp_missing">Missing value |
| handler operators</link>:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><link |
| linkend="dgui_template_exp_missing_default">Default |
| value</link>: <literal>name!"unknown"</literal> or |
| <literal>(user.name)!"unknown"</literal> or |
| <literal>name!</literal> or |
| <literal>(user.name)!</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="dgui_template_exp_missing_test">Missing |
| value test</link>: <literal>name??</literal> or |
| <literal>(user.name)??</literal></para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="dgui_template_exp_assignment">Assignment |
| operators</link>: <literal>=</literal>, <literal>+=</literal>, |
| <literal>-=</literal>, <literal>*=</literal>, |
| <literal>/=</literal>, <literal>%=</literal>, |
| <literal>++</literal>, <literal>--</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="dgui_template_exp_lambda">Local |
| lambdas</link>: <literal>x -> x + 1</literal>, <literal>(x, |
| y) -> x + y</literal></para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>See also: <link |
| linkend="dgui_template_exp_precedence">Operator |
| precedence</link></para> |
| </section> |
| |
| <section xml:id="dgui_template_exp_direct"> |
| <title>Specify values directly</title> |
| |
| <indexterm> |
| <primary>literal</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>constant</primary> |
| </indexterm> |
| |
| <para>Often you want to specify a value directly and not as a result |
| of some calculations.</para> |
| |
| <section xml:id="dgui_template_exp_direct_string"> |
| <title>Strings</title> |
| |
| <indexterm> |
| <primary>string</primary> |
| |
| <secondary>literal</secondary> |
| </indexterm> |
| |
| <para>To specify a string value directly you give the text in |
| quotation marks, e.g.: <literal>"some text"</literal> or in |
| apostrophe-quote, e.g. <literal>'some text'</literal>. The two |
| forms are equivalent. If the text itself contains the character |
| used for the quoting (either <literal>"</literal> or |
| <literal>'</literal>) or backslashes, you have to precede them |
| with a backslash; this is called escaping. You can type any other |
| character, including <link linkend="gloss.lineBreak">line |
| breaks</link>, in the text directly. Example:</para> |
| |
| <programlisting role="template">${"It's \"quoted\" and |
| this is a backslash: \\"} |
| |
| ${'It\'s "quoted" and |
| this is a backslash: \\'}</programlisting> |
| |
| <para>will print:</para> |
| |
| <programlisting role="output">It's "quoted" and |
| this is a backslash: \ |
| |
| It's "quoted" and |
| this is a backslash: \</programlisting> |
| |
| <note> |
| <para>Of course, you could simply type the above text into the |
| template, without using |
| <literal>${<replaceable>...</replaceable>}</literal>. But we do |
| it here just for the sake of example, to demonstrate |
| expressions.</para> |
| </note> |
| |
| <anchor xml:id="topic.escapeSequence"/> |
| |
| <indexterm> |
| <primary>escape sequences</primary> |
| </indexterm> |
| |
| <para>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.</para> |
| |
| <informaltable border="1"> |
| <thead> |
| <tr> |
| <th>Escape sequence</th> |
| |
| <th>Meaning</th> |
| </tr> |
| </thead> |
| |
| <tbody> |
| <tr> |
| <td><literal>\"</literal></td> |
| |
| <td>Quotation mark (u0022)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>\'</literal></td> |
| |
| <td>Apostrophe (a.k.a. apostrophe-quote) (u0027)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>\{</literal></td> |
| |
| <td>Opening curly brace: <literal>{</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>\=</literal></td> |
| |
| <td>Equals character: <literal>=</literal> (Supported since |
| FreeMarker 2.3.28.)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>\\</literal></td> |
| |
| <td>Back slash (u005C)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>\n</literal></td> |
| |
| <td>Line feed (u000A)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>\r</literal></td> |
| |
| <td>Carriage return (u000D)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>\t</literal></td> |
| |
| <td>Horizontal tabulation (a.k.a. tab) (u0009)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>\b</literal></td> |
| |
| <td>Backspace (u0008)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>\f</literal></td> |
| |
| <td>Form feed (u000C)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>\l</literal></td> |
| |
| <td>Less-than sign: <literal><</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>\g</literal></td> |
| |
| <td>Greater-than sign: <literal>></literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>\a</literal></td> |
| |
| <td>Ampersand: <literal>&</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>\x<replaceable>Code</replaceable></literal></td> |
| |
| <td>Character given with its hexadecimal <link |
| linkend="gloss.unicode">Unicode</link> code (<link |
| linkend="gloss.UCS">UCS</link> code)</td> |
| </tr> |
| </tbody> |
| </informaltable> |
| |
| <para>The <literal><replaceable>Code</replaceable></literal> after |
| the <literal>\x</literal> is 1 to 4 hexadecimal digits. For |
| example this all put a copyright sign into the string: |
| <literal>"\xA9Â 1999-2001"</literal>, |
| <literal>"\x0A9Â 1999-2001"</literal>, |
| <literal>"\x00A9Â 1999-2001"</literal>. 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.</para> |
| |
| <para>Note that the character sequence <literal>${</literal> and |
| <literal>#{</literal> (and rarely <literal>[=</literal> instead, |
| depending on <link linkend="dgui_misc_alternativesyntax">the |
| configured syntax</link>) has special meaning. They are used to |
| insert the value of expressions (typically: the value of |
| variables, as in <literal>"Hello ${user}!"</literal>). This will |
| be explained <link |
| linkend="dgui_template_exp_stringop_interpolation">later</link>. |
| If you want to print <literal>${</literal> or |
| <literal>#{</literal> (or <literal>[=</literal>), you should |
| either use raw string literals as explained below, or escape the |
| <literal>{</literal> like in <literal>"foo $\{bar}"</literal> (or |
| the <literal>=</literal> like in <literal>"foo |
| [\=bar]"</literal>).</para> |
| |
| <indexterm> |
| <primary>raw string literal</primary> |
| </indexterm> |
| |
| <para>A special kind of string literals is the raw string |
| literals. In raw string literals, backslash and |
| <literal>${</literal> 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 <literal>r</literal> directly |
| before the opening quotation mark or apostrophe-quote. |
| Example:</para> |
| |
| <programlisting role="template">${r"${foo}"} |
| ${r"C:\foo\bar"}</programlisting> |
| |
| <para>will print:</para> |
| |
| <programlisting role="output">${foo} |
| C:\foo\bar</programlisting> |
| </section> |
| |
| <section xml:id="dgui_template_exp_direct_number"> |
| <title>Numbers</title> |
| |
| <indexterm> |
| <primary>number</primary> |
| |
| <secondary>literal</secondary> |
| </indexterm> |
| |
| <para>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 <literal>-</literal> or <literal>+</literal> to indicate the |
| sign (<literal>+</literal> is redundant). Scientific notation is |
| not yet supported (so <literal>1E3</literal> is wrong). Also, you |
| cannot omit the 0 before the decimal separator (so |
| <literal>.5</literal> is wrong).</para> |
| |
| <para>Examples of valid number literals: <literal>0.08</literal>, |
| <literal>-5.013</literal>, <literal>8</literal>, |
| <literal>008</literal>, <literal>11</literal>, |
| <literal>+11</literal></para> |
| |
| <para>Note that numerical literals like <literal>08</literal>, |
| <literal>+8</literal>, <literal>8.00</literal> and |
| <literal>8</literal> are totally equivalent as they all symbolize |
| the number eight. Thus, <literal>${08}</literal>, |
| <literal>${+8}</literal>, <literal>${8.00}</literal> and |
| <literal>${8}</literal> will all print exactly same.</para> |
| </section> |
| |
| <section xml:id="dgui_template_exp_direct_boolean"> |
| <title>Booleans</title> |
| |
| <indexterm> |
| <primary>boolean</primary> |
| |
| <secondary>literal</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>literal</primary> |
| |
| <secondary>boolean</secondary> |
| </indexterm> |
| |
| <para>To specify a boolean value you write <literal>true</literal> |
| or <literal>false</literal>. Don't use quotation marks.</para> |
| </section> |
| |
| <section xml:id="dgui_template_exp_direct_seuqence"> |
| <title>Sequences</title> |
| |
| <indexterm> |
| <primary>sequence</primary> |
| |
| <secondary>literal</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>numerical sequence</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>numerical range expression</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>range expression</primary> |
| </indexterm> |
| |
| <para>To specify a literal sequence, you list the <link |
| linkend="topic.dataModel.subVar">sub variables</link> separated by |
| commas, and put the whole list into square brackets. For |
| example:</para> |
| |
| <programlisting role="template"><#list <emphasis>["foo", "bar", "baz"]</emphasis> as x> |
| ${x} |
| </#list></programlisting> |
| |
| <para>will print:</para> |
| |
| <programlisting role="output">foo |
| bar |
| baz |
| </programlisting> |
| |
| <para>The items in the list are expressions, so you can do this |
| for example: <literal>[2 + 2, [1, 2, 3, 4], "foo"]</literal>. Here |
| the first subvariable will be the number 4, the second will be |
| another sequence, and the third subvariable will be the string |
| <quote>foo</quote>.</para> |
| </section> |
| |
| <section xml:id="dgui_template_exp_direct_ranges"> |
| <title>Ranges</title> |
| |
| <para>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, |
| <literal>0..<m</literal>, assuming the <literal>m</literal> |
| variable stores 5, will give a sequence that contains <literal>[0, |
| 1, 2, 3, 4]</literal>. Ranges are primarily used for iterating |
| over a range of numbers with <literal><#list |
| <replaceable>...</replaceable>></literal> and for <link |
| linkend="dgui_template_exp_seqenceop_slice">slicing |
| sequences</link> and <link |
| linkend="dgui_template_exp_stringop_slice">slicing |
| strings</link>.</para> |
| |
| <para>The generic forms of range expressions are (where |
| <literal><replaceable>start</replaceable></literal> and |
| <literal><replaceable>end</replaceable></literal> can be any |
| expression that evaluates to a number):</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal><replaceable>start</replaceable>..<replaceable>end</replaceable></literal>: |
| Range with inclusive end. For example, <literal>1..4</literal> |
| gives <literal>[1, 2, 3, 4]</literal>, and |
| <literal>4..1</literal> gives <literal>[4, 3, 2, 1]</literal>. |
| Beware, ranges with inclusive end never give an empty |
| sequence, so <literal>0..length-1</literal> is |
| <emphasis>WRONG</emphasis>, because when length is |
| <literal>0</literal> it gives <literal>[0, |
| -1]</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>start</replaceable>..<<replaceable>end</replaceable></literal> |
| or |
| <literal><replaceable>start</replaceable>..!<replaceable>end</replaceable></literal>: |
| Range with exclusive end. For example, |
| <literal>1..<4</literal> gives <literal>[1, 2, |
| 3]</literal>, <literal>4..<1</literal> gives <literal>[4, |
| 3, 2]</literal>, and <literal>1..<1</literal> gives |
| <literal>[]</literal>. Note the last example; the result can |
| be an empty sequence. There's no difference between |
| <literal>..<</literal> and <literal>..!</literal>; the last |
| form is used in applications where using the |
| <literal><</literal> character causes problems (for HTML |
| editors and such).</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>start</replaceable>..*<replaceable>length</replaceable></literal>: |
| Length limited range. For example, <literal>10..*4</literal> |
| gives <literal>[10, 11, 12, 13]</literal>, |
| <literal>10..*-4</literal> gives <literal>[10, 9, 8, |
| 7]</literal>, and <literal>10..*0</literal> gives |
| <literal>[]</literal>. 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 <link |
| linkend="dgui_template_exp_seqenceop_slice">slicing |
| sequences</link> for more.</para> |
| |
| <note> |
| <para>Length limited ranges were introduced in FreeMarker |
| 2.3.21.</para> |
| </note> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>start</replaceable>..</literal>: |
| Right-unbounded range. This are like length limited ranges |
| with infinite length. For example <literal>1..</literal> gives |
| <literal>[1, 2, 3, 4, 5, 6, ... ]</literal>, 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.</para> |
| |
| <warning> |
| <para>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 <literal>incompatible_improvements</literal> |
| configuration setting to at least 2.3.21.</para> |
| </warning> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Further notes on ranges:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Range expressions themselves don't have square brackets, |
| for example, you write <literal><#assign myRange = |
| 0..<x</literal>, NOT <literal><#assign myRange = |
| [0..<x]></literal>. The last would create a sequence |
| that contains an item that's a range. The square brackets are |
| part of the slicing syntax, like |
| <literal><replaceable>seq</replaceable>[<replaceable>myRange</replaceable>]</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>You can write arithmetical expression on the sides of |
| the <literal>..</literal> without parenthesis, like <literal>n |
| + 1 ..< m / 2 - 1</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>..</literal>, <literal>..<</literal>, |
| <literal>..!</literal> and <literal>..*</literal> are |
| operators, so you can't have space inside them. Like |
| <literal>n .. <m</literal> is WRONG, but <literal>n ..< |
| m</literal> is good.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The reported size of right-unbounded ranges is |
| 2147483647 (or 0 if |
| <literal>incompatible_improvements</literal> is less than |
| 2.3.21) due to a technical limitation (32 bits). However, when |
| listing them, their actual size is infinite.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Ranges don't really store the numbers they consist of, |
| thus for example <literal>0..1</literal> and |
| <literal>0..100000000</literal> is equally fast to create and |
| takes the same amount of memory.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section xml:id="dgui_template_exp_direct_hash"> |
| <title>Hashes</title> |
| |
| <indexterm> |
| <primary>hash</primary> |
| |
| <secondary>literal</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>literal</primary> |
| |
| <secondary>hash</secondary> |
| </indexterm> |
| |
| <para>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: <literal>{ "name": "green mouse", |
| "price": 150 }</literal>. Note that both the names and the values |
| are expressions. The keys must be strings. The values can be if |
| any type.</para> |
| </section> |
| </section> |
| |
| <section xml:id="dgui_template_exp_var"> |
| <title>Retrieving variables</title> |
| |
| <section xml:id="dgui_template_exp_var_toplevel"> |
| <title>Top-level variables</title> |
| |
| <indexterm> |
| <primary>subvariable</primary> |
| |
| <secondary>accessing</secondary> |
| </indexterm> |
| |
| <para>To access a top-level variable, you simply use the variable |
| name. For example, the expression <literal>user</literal> will |
| evaluate to the value of variable stored with name |
| <quote>user</quote> in the root. So this will print what you store |
| there:</para> |
| |
| <programlisting role="template">${user}</programlisting> |
| |
| <para>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).</para> |
| |
| <para>In this kind of expression, the variable name can only |
| contain letters (including non-Latin letters), digits (including |
| non-Latin digits), underline (<literal>_</literal>), dollar |
| (<literal>$</literal>), at sign (<literal>@</literal>). |
| Furthermore, the first character can't be an ASCII digit |
| (<literal>0</literal>-<literal>9</literal>). Since FreeMarker |
| 2.3.22 the variable name can also contain minus |
| (<literal>-</literal>), dot (<literal>.</literal>), and colon |
| (<literal>:</literal>) at any position, but these must be escaped |
| with a preceding backslash (<literal>\</literal>), otherwise they |
| are interpreted as operators. For example, to read the variable |
| whose name is <quote>data-id</quote>, the expression is |
| <literal>data\-id</literal>, as <literal>data-id</literal> would |
| be interpreted as <quote>data minus id</quote>. (Note that these |
| escapes only work in identifiers, not in string literals.) |
| Furthermore, since FreeMarker 2.3.31, hash mark |
| (<literal>#</literal>) can also be used, but must be escaped with |
| a preceding backslash (<literal>\</literal>).</para> |
| </section> |
| |
| <section xml:id="dgui_template_exp_var_hash"> |
| <title>Retrieving data from a hash</title> |
| |
| <indexterm> |
| <primary>subvariable</primary> |
| |
| <secondary>accessing</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>hash</primary> |
| |
| <secondary>accessing subvariable</secondary> |
| </indexterm> |
| |
| <para>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:</para> |
| |
| <programlisting role="dataModel">(root) |
| | |
| +- book |
| | | |
| | +- title = "Breeding green mouses" |
| | | |
| | +- author |
| | | |
| | +- name = "Julia Smith" |
| | | |
| | +- info = "Biologist, 1923-1985, Canada" |
| | |
| +- test = "title"</programlisting> |
| |
| <para>Now we can read the <literal>title</literal> with |
| <literal>book.title</literal>, 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: <literal>book.author.name</literal>.</para> |
| |
| <para>There is an alternative syntax if we want to specify the |
| subvariable name with an expression: |
| <literal>book["title"]</literal>. 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 |
| <literal>book[test]</literal>. More examples; these are all |
| equivalent: <literal>book.author.name</literal>, |
| <literal>book["author"].name</literal>, |
| <literal>book.author["name"]</literal>, |
| <literal>book["author"]["name"]</literal>.</para> |
| |
| <para>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, <literal>_</literal>, |
| <literal>$</literal>, <literal>@</literal> but can't start with |
| <literal>0</literal>-<literal>9</literal>, also starting from |
| 2.3.22 you can also use <literal>\-</literal>, |
| <literal>\.</literal> and <literal>\:</literal>). 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 |
| <literal>*</literal> (asterisk) or <literal>**</literal>, then you |
| do not have to use square bracket syntax.)</para> |
| |
| <para>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).</para> |
| </section> |
| |
| <section xml:id="dgui_template_exp_var_sequence"> |
| <title>Retrieving data from a sequence</title> |
| |
| <indexterm> |
| <primary>subvariable</primary> |
| |
| <secondary>accessing</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>sequence</primary> |
| |
| <secondary>accessing subvariable</secondary> |
| </indexterm> |
| |
| <para>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 <link |
| linkend="example.stdDataModel">example data-model</link> (remember |
| that the number of the first item is 0, not 1): |
| <literal>animals[0].name</literal></para> |
| </section> |
| |
| <section xml:id="dgui_template_exp_var_special"> |
| <title>Special variables</title> |
| |
| <indexterm> |
| <primary>special variables</primary> |
| </indexterm> |
| |
| <para>Special variables are variables defined by the FreeMarker |
| engine itself. To access them, you use the |
| <literal>.<replaceable>variable_name</replaceable></literal> |
| syntax.</para> |
| |
| <para>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 <link linkend="ref_specvar">reference</link>.</para> |
| </section> |
| </section> |
| |
| <section xml:id="dgui_template_exp_stringop"> |
| <title>String operations</title> |
| |
| <indexterm> |
| <primary>string</primary> |
| |
| <secondary>operations</secondary> |
| </indexterm> |
| |
| <section xml:id="dgui_template_exp_stringop_interpolation"> |
| <title>Interpolation and concatenation</title> |
| |
| <indexterm> |
| <primary>interpolation</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>concatenate strings</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>joining strings</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>string</primary> |
| |
| <secondary>concatenate</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>string</primary> |
| |
| <secondary>interpolation</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>adding strings</primary> |
| </indexterm> |
| |
| <para>If you want to insert the value of an expression into a |
| string, you can use |
| <literal>${<replaceable>...</replaceable>}</literal> (and the |
| deprecated <literal>#{<replaceable>...</replaceable>}</literal>) |
| in string literals. |
| <literal>${<replaceable>...</replaceable>}</literal> in string |
| literals <link linkend="dgui_template_valueinsertion">behaves |
| similarly as in <phrase role="markedText">text</phrase> |
| sections</link> (so it goes through the same <emphasis>locale |
| sensitive</emphasis> number and date/time formatting).</para> |
| |
| <note> |
| <para>It's possible to configure FreeMarker's interpolation |
| syntax to use |
| <literal>[=<replaceable>...</replaceable>]</literal> instead; |
| <link linkend="dgui_misc_alternativesyntax_interpolation">see |
| here</link>.</para> |
| </note> |
| |
| <para>Example (assume that user is <quote>Big Joe</quote>):</para> |
| |
| <programlisting role="template"><#assign s = "Hello ${user}!"> |
| ${s} <#-- Just to see what the value of s is --> |
| </programlisting> |
| |
| <para>This will print:</para> |
| |
| <programlisting role="output">Hello Big Joe!</programlisting> |
| |
| <warning> |
| <para>A frequent mistake of users is the usage of interpolations |
| in places where they needn't/shouldn't/can't be used. |
| Interpolations work <emphasis>only</emphasis> in <link |
| linkend="dgui_template_overallstructure"><phrase |
| role="markedText">text</phrase> sections</link> (e.g. |
| <literal><h1>Hello ${name}!</h1></literal>) and in |
| string literals (e.g. <literal><#include |
| "/footer/${company}.html"></literal>). A typical |
| <emphasis>WRONG</emphasis> usage is <literal><#if |
| ${big}>...</#if></literal>, which will cause a |
| syntactical error. You should simply write <literal><#if |
| big>...</#if></literal>. Also, <literal><#if |
| "${big}">...</#if></literal> is |
| <emphasis>WRONG</emphasis>, since it converts the parameter |
| value to string and the <literal>if</literal> directive wants a |
| boolean value, so it will cause a runtime error.</para> |
| </warning> |
| |
| <para |
| xml:id="dgui_template_exp_stringop_concatenation">Alternatively, |
| you can use the <literal>+</literal> operator to achieve similar |
| result:</para> |
| |
| <programlisting role="template"><#assign s = "Hello " + user + "!"></programlisting> |
| |
| <para>This gives the same result as the earlier example with the |
| <literal>${<replaceable>...</replaceable>}</literal>.</para> |
| |
| <warning> |
| <para>Because <literal>+</literal> follows similar rules as |
| <literal>${<replaceable>...</replaceable>}</literal>, the |
| appended string is influenced by the <literal>locale</literal>, |
| <literal>number_format</literal>, |
| <literal>date_format</literal>, <literal>time_format</literal>, |
| <literal>datetime_format</literal> and |
| <literal>boolean_format</literal>, etc. settings, and thus the |
| result targets humans and isn't in generally machine parseable. |
| This mostly leads to problems with numbers, as many locales use |
| grouping (thousands separators) by default, and so |
| <literal>"someUrl?id=" + id</literal> becomes to something like |
| <literal>"someUrl?id=1Â 234"</literal>. To prevent this, use the |
| <literal>?c</literal> (for Computer audience) built-in, like in |
| <literal>"someUrl?id=" + id?c</literal> or |
| <literal>"someUrl?id=${id?c}"</literal>, which will evaluate to |
| something like <literal>"someUrl?id=1234"</literal>, regardless |
| of locale and format settings.</para> |
| </warning> |
| |
| <para>As when <literal>${<replaceable>...</replaceable>}</literal> |
| is used inside string <emphasis>expressions</emphasis> it's just a |
| shorthand of using the <literal>+</literal> operator, <link |
| linkend="dgui_misc_autoescaping">auto-escaping</link> is not |
| applied on it.</para> |
| </section> |
| |
| <section xml:id="dgui_template_exp_get_character"> |
| <title>Getting a character</title> |
| |
| <indexterm> |
| <primary>charAt</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>get character</primary> |
| </indexterm> |
| |
| <para>You can get a single character of a string at a given index |
| similarly as you can <link |
| linkend="dgui_template_exp_var_sequence">read the subvariable of a |
| sequence</link>, e.g. <literal>user[0]</literal>. 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.</para> |
| |
| <para>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 |
| <link linkend="ref_builtin_string_for_string">the |
| <literal>string</literal> built-in</link>, e.g. |
| <literal>user?string[0]</literal>. Don't worry if you don't |
| understand this yet; built-ins will be discussed later.)</para> |
| |
| <para>Example (assume that user is <quote>Big Joe</quote>):</para> |
| |
| <programlisting role="template">${user[0]} |
| ${user[4]}</programlisting> |
| |
| <para>will print (note that the index of the first character is |
| 0):</para> |
| |
| <programlisting role="output">B |
| J</programlisting> |
| </section> |
| |
| <section xml:id="dgui_template_exp_stringop_slice"> |
| <title>String slicing (substrings)</title> |
| |
| <indexterm> |
| <primary>string slicing</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>substring</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>string</primary> |
| |
| <secondary>slice</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>string</primary> |
| |
| <secondary>substring</secondary> |
| </indexterm> |
| |
| <para>You can slice a string in the same way as you <link |
| linkend="dgui_template_exp_seqenceop_slice">slice a |
| sequence</link> (see there), only here instead of sequence items |
| you work with characters. Some differences are:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>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.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>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 |
| <literal><replaceable>someXMLnode</replaceable>?string[<replaceable>range</replaceable>]</literal> |
| to fore string slicing.</para> |
| </listitem> |
| |
| <listitem> |
| <para>There's a legacy bug where a range with |
| <emphasis>inclusive</emphasis> end that's one less than the |
| starting index and is non-negative (like in |
| <literal>"abc"[1..0]</literal>) 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.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template"><#assign s = "ABCDEF"> |
| ${s[2..3]} |
| ${s[2..<4]} |
| ${s[2..*3]} |
| ${s[2..*100]} |
| ${s[2..]}</programlisting> |
| |
| <para>will print:</para> |
| |
| <programlisting role="output">CD |
| CD |
| CDE |
| CDEF |
| CDEF</programlisting> |
| |
| <note> |
| <para>Some of the typical use-cases of string slicing is covered |
| by convenient built-ins: <link |
| linkend="ref_builtin_remove_beginning"><literal>remove_beginning</literal></link>, |
| <link |
| linkend="ref_builtin_remove_ending"><literal>remove_ending</literal></link>, |
| <link |
| linkend="ref_builtin_keep_before"><literal>keep_before</literal></link>, |
| <link |
| linkend="ref_builtin_keep_after"><literal>keep_after</literal></link>, |
| <link |
| linkend="ref_builtin_keep_before_last"><literal>keep_before_last</literal></link>, |
| <link |
| linkend="ref_builtin_keep_after_last"><literal>keep_after_last</literal></link></para> |
| </note> |
| </section> |
| </section> |
| |
| <section xml:id="dgui_template_exp_sequenceop"> |
| <title>Sequence operations</title> |
| |
| <indexterm> |
| <primary>sequence</primary> |
| |
| <secondary>operations</secondary> |
| </indexterm> |
| |
| <section xml:id="dgui_template_exp_sequenceop_cat"> |
| <title>Concatenation</title> |
| |
| <indexterm> |
| <primary>concatenate sequences</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>joining sequences</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>sequence</primary> |
| |
| <secondary>concatenate</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>adding sequences</primary> |
| </indexterm> |
| |
| <para>You can concatenate sequences in the same way as strings, |
| with <literal>+</literal>. Example:</para> |
| |
| <programlisting role="template"><#list ["Joe", "Fred"] + ["Julia", "Kate"] as user> |
| - ${user} |
| </#list></programlisting> |
| |
| <para>will print:</para> |
| |
| <programlisting role="output">- Joe |
| - Fred |
| - Julia |
| - Kate |
| </programlisting> |
| |
| <para>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 <literal><#list users |
| + admins as person></literal>. Although concatenating sequences |
| is fast and is constant time (it's 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. Thus, after tens or hundreds of repeated |
| concatenations the result can be impractically slow to |
| reader.</para> |
| </section> |
| |
| <section xml:id="dgui_template_exp_seqenceop_slice"> |
| <title>Sequence slicing</title> |
| |
| <indexterm> |
| <primary>sequence slice</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>sequence</primary> |
| |
| <secondary>slice</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>subsequence</primary> |
| </indexterm> |
| |
| <para>With |
| <literal><replaceable>seq</replaceable>[<replaceable>range</replaceable>]</literal>, |
| were <literal><replaceable>range</replaceable></literal> is a |
| range value <link linkend="dgui_template_exp_direct_ranges">as |
| described here</link>, you can take a slice of the sequence. The |
| resulting sequence will contain the items from the original |
| sequence (<literal><replaceable>seq</replaceable></literal>) whose |
| indexes are in the range. For example:</para> |
| |
| <programlisting role="template"><#assign seq = ["A", "B", "C", "D", "E"]> |
| <#list seq[1..3] as i>${i}</#list></programlisting> |
| |
| <para>will print</para> |
| |
| <programlisting role="output">BCD </programlisting> |
| |
| <para>Furthermore, the items in the slice will be in the same |
| order as in the range. Thus for example the above example with the |
| <literal>3..1</literal> range would print |
| <literal>DCB</literal>.</para> |
| |
| <para>The numbers in the range must be valid indexes in the |
| sequence, or else the processing of the template will be aborted |
| with error. Like in the last example, |
| <literal>seq[-1..0]</literal> would be an error as |
| <literal>seq[-1]</literal> is invalid, also |
| <literal>seq[1..5]</literal> would be because |
| <literal>seq[5]</literal> is invalid. (Note that |
| <literal>seq[100..<100]</literal> or |
| <literal>seq[100..*0]</literal> would be valid despite that 100 is |
| out of bounds, because those ranges are empty.)</para> |
| |
| <para>Length limited ranges |
| (<literal><replaceable>start</replaceable>..*<replaceable>length</replaceable></literal>) |
| and right-unbounded ranges |
| (<literal><replaceable>start</replaceable>..</literal>) adapt to |
| the length of the sliced sequence. They will slice out at most as |
| many items as there is available:</para> |
| |
| <programlisting role="template"><#assign seq = ["A", "B", "C"]> |
| |
| Slicing with length limited ranges: |
| - <#list seq[0..*2] as i>${i}</#list> |
| - <#list seq[1..*2] as i>${i}</#list> |
| - <#list seq[2..*2] as i>${i}</#list> <#-- Not an error --> |
| - <#list seq[3..*2] as i>${i}</#list> <#-- Not an error --> |
| |
| Slicing with right-unlimited ranges: |
| - <#list seq[0..] as i>${i}</#list> |
| - <#list seq[1..] as i>${i}</#list> |
| - <#list seq[2..] as i>${i}</#list> |
| - <#list seq[3..] as i>${i}</#list></programlisting> |
| |
| <para>This will print:</para> |
| |
| <programlisting role="output">Slicing with length limited ranges: |
| - AB |
| - BC |
| - C |
| - |
| |
| Slicing with right-unlimited ranges: |
| - ABC |
| - BC |
| - C |
| -</programlisting> |
| |
| <para>Note above that slicing with length limited and right |
| unbounded ranges allow the starting index to be past the last item |
| <emphasis>by one</emphasis> (but no more).</para> |
| |
| <note> |
| <para>To split a sequence to slices of a given size, you should |
| use the <link |
| linkend="ref_builtin_chunk"><literal>chunk</literal></link> |
| built-in.</para> |
| </note> |
| </section> |
| </section> |
| |
| <section xml:id="dgui_template_exp_hashop"> |
| <title>Hash operations</title> |
| |
| <indexterm> |
| <primary>hash</primary> |
| |
| <secondary>operations</secondary> |
| </indexterm> |
| |
| <section xml:id="dgui_template_exp_hashop_cat"> |
| <title>Concatenation</title> |
| |
| <indexterm> |
| <primary>concatenate hashes</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>joining hashes</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>hash</primary> |
| |
| <secondary>concatenate</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>adding hashes</primary> |
| </indexterm> |
| |
| <para>You can concatenate hashes in the same way as strings, with |
| <literal>+</literal>. If both hashes contain the same key, the |
| hash on the right-hand side of the <literal>+</literal> takes |
| precedence. Example:</para> |
| |
| <programlisting role="template"><#assign ages = {"Joe":23, "Fred":25} + {"Joe":30, "Julia":18}> |
| - Joe is ${ages.Joe} |
| - Fred is ${ages.Fred} |
| - Julia is ${ages.Julia} |
| </programlisting> |
| |
| <para>will print:</para> |
| |
| <programlisting role="output">- Joe is 30 |
| - Fred is 25 |
| - Julia is 18</programlisting> |
| |
| <para>Note that hash concatenation is not to be used for many |
| repeated concatenations, like for adding items to a hash inside a |
| loop. While adding together hashes is fast and is constant time |
| (independent of the size of the hashes added), the resulting hash |
| is a bit slower to read than the hashes added together. Thus after |
| tens or hundreds of additions the result can be impractically slow |
| to read.</para> |
| </section> |
| </section> |
| |
| <section xml:id="dgui_template_exp_arit"> |
| <title>Arithmetical calculations</title> |
| |
| <indexterm> |
| <primary>arithmetic</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>math</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>addition</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>subtraction</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>division</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>modulus</primary> |
| </indexterm> |
| |
| <para>This is the basic 4-function calculator arithmetic plus the |
| modulus operator. So the operators are:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>Addition: <literal>+</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Subtraction: <literal>-</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Multiplication: <literal>*</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Division: <literal>/</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Modulus (remainder) of integer operands: |
| <literal>%</literal></para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template">${100 - x * x} |
| ${x / 2} |
| ${12 % 10}</programlisting> |
| |
| <para>Assuming that <literal>x</literal> is 5, it will print:</para> |
| |
| <programlisting role="output">75 |
| 2.5 |
| 2</programlisting> |
| |
| <para>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 <literal>"5"</literal> is a |
| string and not the number 5:</para> |
| |
| <programlisting role="template">${3 * "5"} <#-- WRONG! --></programlisting> |
| |
| <para>There is an exception to the above rule. The |
| <literal>+</literal> operator, is used to <link |
| linkend="dgui_template_exp_stringop_interpolation">concatenate |
| strings</link> as well. If on one side of <literal>+</literal> is a |
| string and on the other side of <literal>+</literal> 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 |
| <literal>+</literal> as string concatenation operator. |
| Example:</para> |
| |
| <programlisting role="template">${3 + "5"}</programlisting> |
| |
| <programlisting role="output">35</programlisting> |
| |
| <para>Generally, FreeMarker never converts a string to a number |
| automatically, but it may convert a number to a string |
| automatically.</para> |
| |
| <para><indexterm> |
| <primary>integer division</primary> |
| </indexterm><indexterm> |
| <primary>integer part</primary> |
| </indexterm> People often want only the integer part of the result |
| of a division (or of other calculations). This is possible with the |
| <literal>int</literal> built-in. (Built-ins are explained <link |
| linkend="dgui_template_exp_builtin">later</link>):</para> |
| |
| <programlisting role="template">${(x/2)?int} |
| ${1.1?int} |
| ${1.999?int} |
| ${-1.1?int} |
| ${-1.999?int}</programlisting> |
| |
| <para>Assuming that <literal>x</literal> is 5, it will print:</para> |
| |
| <programlisting role="output">2 |
| 1 |
| 1 |
| -1 |
| -1</programlisting> |
| |
| <para>Due to historical reasons, the <literal>%</literal> operator |
| works by first truncating the operands to an integer number, and |
| then returning the remainder of the division:</para> |
| |
| <programlisting role="template">${12 % 5} <#-- Prints 2 --> |
| ${12.9 % 5} <#-- Prints 2 --> |
| ${12.1 % 5} <#-- Prints 2 --> |
| |
| ${12 % 6} <#-- Prints 0 --> |
| ${12 % 6.9} <#-- Prints 0 --></programlisting> |
| |
| <para>The sign of the result of <literal>%</literal> is the same as |
| the sign of the left hand operand, and its absolute value is the |
| same as if both operands where positive:</para> |
| |
| <programlisting role="template">${-12 % -5} <#-- Prints -2 --> |
| ${-12 % 5} <#-- Prints -2 --> |
| ${12 % -5} <#-- Prints 2 --> |
| </programlisting> |
| |
| <para role="forProgrammers">About the precision of the operations: |
| By default FreeMarker uses <literal>BigDecimal</literal>-s for all |
| arithmetical calculations, to avoid rounding and overflow/underflow |
| artifacts, and also keeps the result as |
| <literal>BigDecimal</literal>-s. So <literal>+</literal> (addition), |
| <literal>-</literal> (subtraction) and <literal>*</literal> |
| (multiplication) are <quote>lossless</quote>. Again by default, |
| <literal>/</literal> (division) results are calculated to 12 |
| decimals with half-up rounding (unless some operands have even more |
| decimals, in which case it's calculated with that much decimals). |
| All this behavior depends on the |
| <literal>arithmetic_engine</literal> configuration setting |
| (<literal>Configurable.setArithmericEngine(ArithmericEngine)</literal>) |
| though, and some application might use a different value than the |
| default, although that's highly uncommon.</para> |
| </section> |
| |
| <section xml:id="dgui_template_exp_comparison"> |
| <title>Comparison</title> |
| |
| <indexterm> |
| <primary>comparison operators</primary> |
| </indexterm> |
| |
| <para>Sometimes you want to know if two values are equal or not, or |
| which value is the greater.</para> |
| |
| <para>To show concrete examples I will use the <literal>if</literal> |
| directive here. The usage of <literal>if</literal> directive is: |
| <literal><#if |
| <replaceable>expression</replaceable>>...</#if></literal>, |
| 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 <literal>true</literal> then the things between the |
| begin and end-tag will be processed, otherwise they will be |
| skipped.</para> |
| |
| <para>To test two values for equality you use <literal>==</literal> |
| (or <literal>=</literal> as a <emphasis>deprecated</emphasis> |
| alternative) To test two values for inequality you use |
| <literal>!=</literal>. For example, assume that |
| <literal>user</literal> is <quote>Big Joe</quote>:</para> |
| |
| <programlisting role="template"><#if <emphasis>user == "Big Joe"</emphasis>> |
| It is Big Joe |
| </#if> |
| <#if <emphasis>user != "Big Joe"</emphasis>> |
| It is not Big Joe |
| </#if></programlisting> |
| |
| <para>The <literal>user == "Big Joe"</literal> expression in the |
| <literal><#if ...></literal> will evaluate to the boolean |
| <literal>true</literal>, so the above will say <quote>It is Big |
| Joe</quote>.</para> |
| |
| <para>The expressions on both sides of the <literal>==</literal> or |
| <literal>!=</literal> must evaluate to a scalar (not a sequence or |
| hash). 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 <literal><#if 1 == "1"></literal> will |
| cause an error. Note that FreeMarker does exact comparison, so |
| string comparisons are case and white-space sensitive: |
| <literal>"x"</literal> and <literal>"x "</literal> and |
| <literal>"X"</literal> are not equal values.</para> |
| |
| <para>For numerical and date, time and date-time values you can also |
| use <literal><</literal>, <literal><=</literal>, |
| <literal>>=</literal> and <literal>></literal>. You can't use |
| them for strings! Example:</para> |
| |
| <programlisting role="template"><#if x <emphasis><=</emphasis> 12> |
| x is less or equivalent with 12 |
| </#if></programlisting> |
| |
| <para>There's a problem with <literal>>=</literal> and |
| <literal>></literal>. FreeMarker interprets the |
| <literal>></literal> character as the closing character of the |
| FTL tag. To prevent this, you can use <literal>lt</literal> instead |
| of <literal><</literal>, <literal>lte</literal> instead of |
| <literal><=</literal>, <literal>gt</literal> instead of |
| <literal>></literal> and <literal>gte</literal> instead of |
| <literal>>=</literal>, like in <literal><#if x gt |
| y></literal>. Another trick it to put the expression into <link |
| linkend="dgui_template_exp_parentheses">parentheses</link> like in |
| <literal><#if (x > y)></literal>, although it's considered |
| to be less elegant.</para> |
| |
| <para>FreeMarker supports some more syntactical alternatives:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>&gt;</literal> and |
| <literal>&lt;</literal> can also be used, like in: |
| <literal><#if x &gt; y></literal> or <literal><#if |
| x &gt;= y></literal>. This isn't meant to be entered |
| manually; it's to work around cases where the template gets |
| XML/HTML escaped and the user can't easily prevent that |
| happening. Note that in general FTL does not support entity |
| references (the |
| <literal>&<replaceable>...</replaceable>;</literal> things) |
| in FTL tags; it's just an exception with these operators.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Deprecated forms: <literal>\lt</literal>, |
| <literal>\lte</literal>, <literal>\gt</literal> and |
| <literal>\gte</literal>. These are the same as the ones without |
| the backslash.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section xml:id="dgui_template_exp_logicalop"> |
| <title>Logical operations</title> |
| |
| <indexterm> |
| <primary>boolean</primary> |
| |
| <secondary>operations</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>logical operations</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>or</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>and</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>not</primary> |
| </indexterm> |
| |
| <para>Just the usual logical operators:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>Logical or: <literal>||</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Logical and: <literal>&&</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Logical not: <literal>!</literal></para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>The operators will work with boolean values only. Otherwise an |
| error will abort the template processing.</para> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template"><#if x < 12 <emphasis>&&</emphasis> color == "green"> |
| We have less than 12 things, and they are green. |
| </#if> |
| <#if <emphasis>!</emphasis>hot> <#-- here hot must be a boolean --> |
| It's not hot. |
| </#if></programlisting> |
| |
| <para>FreeMarker supports some more syntactical alternatives:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>\and</literal> (since FreeMarker 2.3.27): In some |
| applications using <literal>&&</literal> causes problems |
| as it's not valid in XML or HTML. While FreeMarker templates was |
| never intended to be valid XML/HTML, only their output should be |
| that, in reality there are some applications that expect the |
| template itself to be valid XML/HTML regardless. This syntax is |
| a workaround for such cases. Also note that unlike with the |
| comparison operators, <literal>and</literal> without |
| <literal>\</literal> is not supported due to backward |
| compatibility restrictions.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>&amp;&amp;</literal> (since FreeMarker |
| 2.3.27): This isn't meant to be entered manually; it's to work |
| around cases where the template gets XML/HTML escaped and the |
| user can't easily prevent that happening. Note that in general |
| FTL does not support entity references (the |
| <literal>&<replaceable>...</replaceable>;</literal> things) |
| in FTL tags; it's just an exception with these operators.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Deprecated forms: <literal>&</literal> and |
| <literal>|</literal>. Don't use them anymore.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section xml:id="dgui_template_exp_builtin"> |
| <title>Built-ins</title> |
| |
| <indexterm> |
| <primary>built-in</primary> |
| </indexterm> |
| |
| <para>Built-ins are like methods that are added to the objects by |
| FreeMarker. To prevent name clashes with actual methods and other |
| sub-variables, instead of dot (<literal>.</literal>), you separate |
| them from the parent object with question mark |
| (<literal>?</literal>). For example, if you want to ensure that |
| <literal>path</literal> has an initial <literal>/</literal> then you |
| could write <literal>path?ensure_starts_with('/')</literal>. The |
| Java object behind <literal>path</literal> (a |
| <literal>String</literal> most certainly) doesn't have such method, |
| FreeMarker adds it. For brevity, if the method has no parameters, |
| you <emphasis>must</emphasis> omit the <literal>()</literal>, like, |
| to get the length of <literal>path</literal>, you have to write |
| <literal>path?length</literal>, <emphasis>not</emphasis> |
| <literal>path?length()</literal>.</para> |
| |
| <para>The other reason why built-ins are crucial is that normally |
| (though it depends on configuration settings), FreeMarker doesn't |
| expose the Java API of the objects. So despite that Java's |
| <literal>String</literal> has a <literal>length()</literal> method, |
| it's hidden from the template, you <emphasis>have to</emphasis> use |
| <literal>path?length</literal> instead. The advantage of that is |
| that thus the template doesn't depend on the exactly type of the |
| underlying Java objects. (Like <literal>path</literal> is maybe a |
| <literal>java.nio.Path</literal> behind the scenes, but if the |
| programmers has configure FreeMarker to expose |
| <literal>Path</literal> objects as FTL strings, the template won't |
| be aware of that, and <literal>?length</literal> will work, despite |
| that <literal>java.nio.Path</literal> has no similar method.)</para> |
| |
| <para>You can find some of the <link |
| linkend="topic.commonlyUsedBuiltIns">most commonly used built-ins |
| mentioned here</link>, and the <link linkend="ref_builtins">complete |
| list of built-ins in the Reference</link>. For now, just a few of |
| the more important ones:</para> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template">${testString?upper_case} |
| ${testString?html} |
| ${testString?upper_case?html} |
| |
| ${testSequence?size} |
| ${testSequence?join(", ")}</programlisting> |
| |
| <para>Assuming that <literal>testString</literal> stores the string |
| <quote>Tom & Jerry</quote>, and testSequnce stores the strings |
| <quote>foo</quote>, <quote>bar</quote> and <quote>baz</quote>, the |
| output will be:</para> |
| |
| <programlisting role="output">TOM & JERRY |
| Tom &amp; Jerry |
| TOM &amp; JERRY |
| |
| 3 |
| foo, bar, baz</programlisting> |
| |
| <para>Note the <literal>test?upper_case?html</literal> above. Since |
| the result of <literal>test?upper_case</literal> is a string, you |
| can apply the <literal>html</literal> built-in on it.</para> |
| |
| <para>Naturally, the left side of the built-in can be arbitrary |
| expression, not just a variable name:</para> |
| |
| <programlisting role="template">${testSeqence[1]?cap_first} |
| ${"horse"?cap_first} |
| ${(testString + " & Duck")?html}</programlisting> |
| |
| <programlisting role="output">Bar |
| Horse |
| Tom &amp; Jerry &amp; Duck</programlisting> |
| </section> |
| |
| <section xml:id="dgui_template_exp_methodcall"> |
| <title>Method call</title> |
| |
| <indexterm> |
| <primary>call a method</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>method</primary> |
| |
| <secondary>call</secondary> |
| </indexterm> |
| |
| <para>If you have a method then you can use the method call |
| operation on it. The method call operation is a comma-separated list |
| of expressions in parentheses. These values are called parameters. |
| The method call operation passes these values to the method which |
| will in turn return a result. This result will be the value of the |
| whole method call expression.</para> |
| |
| <para>For example, assume the programmers have made available a |
| method variable called <literal>repeat</literal>. You give a string |
| as the first parameter, and a number as the second parameter, and it |
| returns a string which repeats the first parameter the number of |
| times specified by the second parameter.</para> |
| |
| <programlisting role="template">${repeat("Foo", 3)}</programlisting> |
| |
| <para>will print:</para> |
| |
| <programlisting role="output">FooFooFoo</programlisting> |
| |
| <para>Here <literal>repeat</literal> was evaluated to the method |
| variable (according to how you <link |
| linkend="dgui_template_exp_var_toplevel">access top-level |
| variables</link>) and then <literal>("What", 3)</literal> invoked |
| that method.</para> |
| |
| <para>I would like to emphasize that method calls are just plain |
| expressions, like everything else. So this:</para> |
| |
| <programlisting role="template">${repeat(repeat("x", 2), 3) + repeat("Foo", 4)?upper_case}</programlisting> |
| |
| <para>will print this:</para> |
| |
| <programlisting role="output">xxxxxxFOOFOOFOOFOO</programlisting> |
| </section> |
| |
| <section xml:id="dgui_template_exp_missing"> |
| <title>Handling missing values</title> |
| |
| <note> |
| <para>These operators exist since FreeMarker 2.3.7 (replacing the |
| <literal>default</literal>, <literal>exists</literal> and |
| <literal>if_exists</literal> built-ins).</para> |
| </note> |
| |
| <indexterm> |
| <primary>undefined variable</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>missing variable</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>null</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>handling null-s</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>error handling</primary> |
| </indexterm> |
| |
| <para>As we explained earlier, an error will occur and abort the |
| template processing if you try to access a missing variable. However |
| two special operators can suppress this error, and handle the |
| problematic situation. The handled variable can be top-level |
| variable, hash subvariable, or sequence subvariable as well. |
| Furthermore these operators handle the situation when a method call |
| doesn't return a value <phrase role="forProgrammers">(from the |
| viewpoint of Java programmers: it returns <literal>null</literal> or |
| it's return type is <literal>void</literal>)</phrase>, so it's more |
| correct to say that these operators handle missing values in |
| general, rather than just missing variables.</para> |
| |
| <para><phrase role="forProgrammers">For those who know what's Java |
| <literal>null</literal>, FreeMarker 2.3.<replaceable>x</replaceable> |
| treats them as missing values. Simply, the template language doesn't |
| know the concept of <literal>null</literal>. For example, if you |
| have a bean that has a <literal>maidenName</literal> property, and |
| the value of that property is <literal>null</literal>, then that's |
| the same as if there were no such property at all, as far as the |
| template is concerned (assuming you didn't configured FreeMarker to |
| use some extreme object wrapper, that is). The result of a method |
| call that returns <literal>null</literal> is also treated as a |
| missing variable (again, assuming that you use some usual object |
| wrapper). See more <link linkend="faq_null">in the |
| FAQ</link>.</phrase></para> |
| |
| <note> |
| <para>If you wonder why is FreeMarker so picky about missing |
| variables, <link linkend="faq_picky_about_missing_vars">read this |
| FAQ entry</link>.</para> |
| </note> |
| |
| <section xml:id="dgui_template_exp_missing_default"> |
| <title>Default value operator</title> |
| |
| <indexterm> |
| <primary>default value operator</primary> |
| </indexterm> |
| |
| <para>Synopsis: |
| <literal><replaceable>unsafe_expr</replaceable>!<replaceable>default_expr</replaceable></literal> |
| or <literal><replaceable>unsafe_expr</replaceable>!</literal> or |
| <literal>(<replaceable>unsafe_expr</replaceable>)!<replaceable>default_expr</replaceable></literal> |
| or |
| <literal>(<replaceable>unsafe_expr</replaceable>)!</literal></para> |
| |
| <para>This operator allows you to specify a default value for the |
| case when the value is missing.</para> |
| |
| <para>Example. Assume no variable called <literal>mouse</literal> |
| is present:</para> |
| |
| <programlisting role="template">${mouse!"No mouse."} |
| <#assign mouse="Jerry"> |
| ${mouse!"No mouse."}</programlisting> |
| |
| <para>The output will be:</para> |
| |
| <programlisting role="output">No mouse. |
| Jerry</programlisting> |
| |
| <para>The default value can be any kind of expression, so it |
| doesn't have to be a string. For example you can write |
| <literal>hits!0</literal> or <literal>colors!["red", "green", |
| "blue"]</literal>. There is no restriction regarding the |
| complexity of the expression that specifies the default value, for |
| example you can write: <literal>cargo.weight!(item.weight * |
| itemCount + 10)</literal>.</para> |
| |
| <warning> |
| <para>If you have a composite expression after the |
| <literal>!</literal>, like <literal>1 + x</literal>, |
| <emphasis>always</emphasis> use parentheses, like |
| <literal>${x!(1 + y)}</literal> or <literal>${(x!1) + |
| y}</literal>, depending on which interpretation you meant. |
| That's needed because due to a programming mistake in FreeMarker |
| 2.3.x, the precedence of <literal>!</literal> (when it's used as |
| default value operator) is very low at its right side. This |
| means that, for example, <literal>${x!1 + y}</literal> is |
| misinterpreted by FreeMarker as <literal>${x!(1 + y)}</literal> |
| while it should mean <literal>${(x!1) + y}</literal>. This |
| programming error will be possibly fixed in some future version |
| (maybe 2.4), and you should not utilize this wrong behavior, so |
| that the fix can be enabled in your project!</para> |
| </warning> |
| |
| <para>If the default value is omitted, then it will be empty |
| string and empty sequence and empty hash at the same time. (This |
| is possible because FreeMarker allows multi-type values.) Note the |
| consequence that you can't omit the default value if you want it |
| to be <literal>0</literal> or <literal>false</literal>. |
| Example:</para> |
| |
| <programlisting role="template">(${mouse!}) |
| <#assign mouse = "Jerry"> |
| (${mouse!})</programlisting> |
| |
| <para>The output will be:</para> |
| |
| <programlisting role="output">() |
| (Jerry)</programlisting> |
| |
| <warning> |
| <para>Due to syntactical ambiguities <literal><@something |
| a=x! b=y /></literal> will be interpreted as |
| <literal><@something a=x!(b=y) /></literal>, that is, the |
| <literal>b=y</literal> will be interpreted as a comparison that |
| gives the default value for <literal>x</literal>, rather than |
| the specification of the <literal>b</literal> parameter. To |
| prevent this, write: <literal><@something a=(x!) b=y |
| /></literal></para> |
| </warning> |
| |
| <para>You can use this operator in two ways with non-top-level |
| variables:</para> |
| |
| <programlisting role="template">product.color!"red"</programlisting> |
| |
| <para>This will handle if <literal>color</literal> is missing |
| inside <literal>product</literal> (and returns |
| <literal>"red"</literal> if so), but will not handle if |
| <literal>product</literal> is missing. That is, the |
| <literal>product</literal> variable itself must exist, otherwise |
| the template processing will die with error.</para> |
| |
| <programlisting role="template">(product.color)!"red"</programlisting> |
| |
| <para>This will handle if <literal>product.color</literal> is |
| missing. That is, if <literal>product</literal> is missing, or |
| <literal>product</literal> exists but it does not contain |
| <literal>color</literal>, the result will be |
| <literal>"red"</literal>, and no error will occur. The important |
| difference between this and the previous example is that when |
| surrounded with parentheses, it is allowed for any component of |
| the expression to be undefined, while without parentheses only the |
| last component of the expression is allowed to be |
| undefined.</para> |
| |
| <para>Of course, the default value operator can be used with |
| sequence sub variables as well:</para> |
| |
| <programlisting role="template"><#assign seq = ['a', 'b']> |
| ${seq[0]!'-'} |
| ${seq[1]!'-'} |
| ${seq[2]!'-'} |
| ${seq[3]!'-'}</programlisting> |
| |
| <para>the outpur will be:</para> |
| |
| <programlisting role="output">a |
| b |
| - |
| -</programlisting> |
| |
| <para>A negative sequence index (as |
| <literal>seq[-1]!'-'</literal>) will always cause an error, you |
| can't suppress that with this or any other operator.</para> |
| </section> |
| |
| <section xml:id="dgui_template_exp_missing_test"> |
| <title>Missing value test operator</title> |
| |
| <indexterm> |
| <primary>existence test operator</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>missing value test operator</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>testing for null</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>testing for missing</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>testing for undefined</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>is null</primary> |
| </indexterm> |
| |
| <para>Synopsis: |
| <literal><replaceable>unsafe_expr</replaceable>??</literal> or |
| <literal>(<replaceable>unsafe_expr</replaceable>)??</literal></para> |
| |
| <para>This operator tells if a value is missing or not. Depending |
| on that, the result is either <literal>true</literal> or |
| <literal>false</literal>.</para> |
| |
| <para>Example. Assume no variable called <literal>mouse</literal> |
| is present:</para> |
| |
| <programlisting role="template"><#if mouse??> |
| Mouse found |
| <#else> |
| No mouse found |
| </#if> |
| Creating mouse... |
| <#assign mouse = "Jerry"> |
| <#if mouse??> |
| Mouse found |
| <#else> |
| No mouse found |
| </#if></programlisting> |
| |
| <para>The output will be:</para> |
| |
| <programlisting role="output"> No mouse found |
| Creating mouse... |
| Mouse found</programlisting> |
| |
| <para>With non-top-level variables the rules are the same as with |
| the default value operator, that is, you can write |
| <literal>product.color??</literal> and |
| <literal>(product.color)??</literal>.</para> |
| </section> |
| </section> |
| |
| <section xml:id="dgui_template_exp_assignment"> |
| <title>Assignment Operators</title> |
| |
| <para>These are actually not expressions, but parts of the syntax of |
| the assignment directives, such as <link |
| linkend="ref_directive_assign"><literal>assign</literal></link>, |
| <link linkend="ref_directive_local"><literal>local</literal></link> |
| and <link |
| linkend="ref_directive_global"><literal>global</literal></link>. As |
| such, they can't be used anywhere else.</para> |
| |
| <para><literal><#assign x += y></literal> is shorthand for |
| <literal><#assign x = x + y></literal>, <literal><#assign x |
| *= y></literal> is shorthand for <literal><#assign x = x * |
| y></literal>, and so on.</para> |
| |
| <para><literal><#assign x++></literal> differs from |
| <literal><#assign x += 1></literal> (or <literal><#assign x |
| = x + 1></literal>) in that it always does arithmetical addition |
| (and fails if the variable is not a number), while the others are |
| overloaded to do string and sequence concatenation and hash |
| addition. <literal><#assign x--></literal> is shorthand for |
| <literal><#assign x -= 1></literal>.</para> |
| |
| <note> |
| <para>The shorthand operators (like <literal>+=</literal>, |
| <literal>++</literal>, etc.) are only supported since FreeMarker |
| 2.3.23. Before that, you could only use <literal>=</literal> in |
| itself, as in <literal><#assign x = x + 1></literal>.</para> |
| </note> |
| </section> |
| |
| <section xml:id="dgui_template_exp_lambda"> |
| <title>Local lambdas</title> |
| |
| <indexterm> |
| <primary>lambda</primary> |
| </indexterm> |
| |
| <para>FreeMarker doesn't support general purpose lambdas (unlike |
| Java). The usage of lambdas is restricted to the parameters of |
| certain <link linkend="dgui_template_exp_builtin">built-ins</link>, |
| like: <link |
| linkend="ref_builtin_filter"><literal>filter</literal></link>, <link |
| linkend="ref_builtin_map"><literal>map</literal></link>, <link |
| linkend="ref_builtin_take_while"><literal>take_while</literal></link>, |
| <link |
| linkend="ref_builtin_drop_while"><literal>drop_while</literal></link>.</para> |
| |
| <para>The reason of this restriction is that FreeMarker doesn't |
| implement binding/capturing variables that are referred from the |
| lambda, instead it ensures that the evaluation of the lambda happens |
| before the enclosing variable scope is ended. Hence, and to |
| differentiate them from <quote>real</quote> lambdas, these are |
| called <emphasis>local</emphasis> lambdas.</para> |
| |
| <para>The syntax of lambdas is like |
| <literal>(<replaceable>name1</replaceable>, |
| <replaceable>name2</replaceable>, <replaceable>...</replaceable>, |
| <replaceable>nameN</replaceable>) -> |
| <replaceable>expression</replaceable></literal>. If there's only a |
| single argument, the parentheses can be omitted: |
| <literal><replaceable>name1</replaceable> -> |
| <replaceable>expression</replaceable></literal>.</para> |
| |
| <para>As the right side of the <literal>-></literal> is just a |
| single expression, if you need complex logic there, you probably |
| want to move that into a <link |
| linkend="ref.directive.function">function</link>, as the you can use |
| directives like <literal>if</literal>, <literal>list</literal>, etc. |
| In that case though, you don't need a lambda expression, as all |
| built-ins that support a lambda parameter, also support passing in a |
| function directly. For example, instead of <literal>seq?map(it -> |
| myMapper(it))</literal> you should just write |
| <literal>seq?map(myMapper)</literal>.</para> |
| |
| <para>The argument specified in a lambda expression can hold the |
| missing (Java <literal>null</literal>) value. Reading a lambda |
| argument never falls back to higher scope, so a variable with |
| identical name will not interfere when accessing the lambda |
| parameter. Therefore something like <literal>seq?filter(it -> |
| it??)</literal>, which filters out missing element from the |
| sequence, will work reliably.</para> |
| </section> |
| |
| <section xml:id="dgui_template_exp_parentheses"> |
| <title>Parentheses</title> |
| |
| <indexterm> |
| <primary>parentheses</primary> |
| </indexterm> |
| |
| <para>Parentheses can be used to group any expressions. Some |
| examples:</para> |
| |
| <programlisting role="template"> <#-- Output will be: --> |
| ${3 * 2 + 2} <#-- 8 --> |
| ${3 * (2 + 2)} <#-- 12 --> |
| ${3 * ((2 + 2) * (1 / 2))} <#-- 6 --> |
| ${"green " + "mouse"?upper_case} <#-- green MOUSE --> |
| ${("green " + "mouse")?upper_case} <#-- GREEN MOUSE --> |
| <#if !(color == "red" || color == "green")> |
| The color is nor red nor green |
| </#if></programlisting> |
| |
| <para>Note that the parentheses of a <link |
| linkend="dgui_template_exp_methodcall">method call |
| expressions</link> have nothing to do with the parentheses used for |
| grouping.</para> |
| </section> |
| |
| <section xml:id="dgui_template_exp_whitespace"> |
| <title>White-space in expressions</title> |
| |
| <para>FTL ignores superfluous <link |
| linkend="gloss.whiteSpace">white-space</link> in expressions. So |
| these are totally equivalent:</para> |
| |
| <programlisting role="template">${x + ":" + book.title?upper_case}</programlisting> |
| |
| <para>and</para> |
| |
| <programlisting role="template">${x+":"+book.title?upper_case}</programlisting> |
| |
| <para>and</para> |
| |
| <programlisting role="template">${ |
| x |
| + ":" + book . title |
| ? upper_case |
| }</programlisting> |
| </section> |
| |
| <section xml:id="dgui_template_exp_comment"> |
| <title>Comments in expressions</title> |
| |
| <indexterm> |
| <primary>comment</primary> |
| </indexterm> |
| |
| <para>Expression may contain comments anywhere where they can |
| contain ignored white-space (<link |
| linkend="dgui_template_exp_whitespace">see above</link>). Comments |
| look like <literal><#-- ... --></literal> or as <literal>[#-- |
| ... --]</literal>. Example:</para> |
| |
| <programlisting role="template"><#assign x <#-- A comment --> = 123 <#-- A comment -->> |
| <#function f(x <#-- A comment -->, y <#-- A comment -->)> |
| <#return <#-- A comment --> 1 <#-- A comment -->> |
| </#function> |
| <#assign someHash = { |
| "foo": 123, <#-- A comment --> |
| "bar": x <#-- A comment --> + 1, |
| <#-- A comment --> |
| "baaz": f(1 <#-- A comment -->, 2 <#-- A comment -->) |
| } <#-- A comment -->></programlisting> |
| </section> |
| |
| <section xml:id="dgui_template_exp_precedence"> |
| <title>Operator precedence</title> |
| |
| <indexterm> |
| <primary>precedence</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>operator precedence</primary> |
| </indexterm> |
| |
| <para>The following table shows the precedence assigned to the |
| operators. The operators in this table are listed in precedence |
| order: the higher in the table an operator appears, the higher its |
| precedence. Operators with higher precedence are evaluated before |
| operators with a relatively lower precedence. Operators on the same |
| line have equal precedence. When binary operators (operators with |
| two <quote>parameters</quote>, as <literal>+</literal> and |
| <literal>-</literal>) of equal precedence appear next to each other, |
| they are evaluated in left-to-right order.</para> |
| |
| <informaltable border="1"> |
| <thead> |
| <tr> |
| <th>Operator group</th> |
| |
| <th>Operators</th> |
| </tr> |
| </thead> |
| |
| <tbody> |
| <tr> |
| <td>highest precedence operators</td> |
| |
| <td><literal>[<replaceable>subvarName</replaceable>] |
| [<replaceable>subStringRange</replaceable>] . ? |
| (<replaceable>methodParams</replaceable>) |
| <replaceable>expr</replaceable>! |
| <replaceable>expr</replaceable>??</literal></td> |
| </tr> |
| |
| <tr> |
| <td>unary prefix operators</td> |
| |
| <td><literal>+<replaceable>expr</replaceable> |
| -<replaceable>expr</replaceable> !expr</literal></td> |
| </tr> |
| |
| <tr> |
| <td>multiplicative operators</td> |
| |
| <td><literal>* / %</literal></td> |
| </tr> |
| |
| <tr> |
| <td>additive operators</td> |
| |
| <td><literal>+ -</literal></td> |
| </tr> |
| |
| <tr> |
| <td>numerical ranges</td> |
| |
| <td><literal>..</literal> <literal>..<</literal> |
| <literal>..!</literal> <literal>..*</literal></td> |
| </tr> |
| |
| <tr> |
| <td>relational operators</td> |
| |
| <td><literal>< > <= >=</literal> (and equivalents: |
| <literal>gt</literal>, <literal>lt</literal>, etc.)</td> |
| </tr> |
| |
| <tr> |
| <td>equality operators</td> |
| |
| <td><literal>== !=</literal> (and equivalents: |
| <literal>=</literal>)</td> |
| </tr> |
| |
| <tr> |
| <td>logical <quote>and</quote> operator</td> |
| |
| <td><literal>&&</literal></td> |
| </tr> |
| |
| <tr> |
| <td>logical <quote>or</quote> operator</td> |
| |
| <td><literal>||</literal></td> |
| </tr> |
| |
| <tr> |
| <td>local lambda</td> |
| |
| <td><literal>-></literal></td> |
| </tr> |
| </tbody> |
| </informaltable> |
| |
| <para>For those of you who know C, Java language or JavaScript, note |
| that the precedence rules are the same as in those languages, except |
| that FTL has some operators that do not exist in those |
| languages.</para> |
| |
| <para>The default value operator |
| (<literal><replaceable>exp</replaceable>!<replaceable>exp</replaceable></literal>) |
| is not yet in the table because of a programming mistake, which will |
| be only fixed in FreeMarker 2.4 due to backward compatibility |
| constraints. It meant to be a "highest precedence operator", but in |
| FreeMarker 2.3.x the precedence on its right side is very low by |
| accident. So if you have a composite expression on the right side, |
| always use paranthesses, etiher like <literal>x!(y + 1)</literal> or |
| like <literal>(x!y) + 1</literal>. Never write just <literal>x!y + |
| 1</literal>.</para> |
| </section> |
| </section> |
| |
| <section xml:id="dgui_template_valueinsertion"> |
| <title>Interpolations</title> |
| |
| <indexterm> |
| <primary>interpolation</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>${...}</primary> |
| </indexterm> |
| |
| <section> |
| <title>Overview</title> |
| |
| <para>The format of interpolations is |
| <literal>${<replaceable>expression</replaceable>}</literal>, where |
| <literal><replaceable>expression</replaceable></literal> can be all |
| kind of expression (e.g. <literal>${100 + x}</literal>).</para> |
| |
| <note> |
| <para>FreeMarker can be configured to use |
| <literal>[=<replaceable>expression</replaceable>]</literal> syntax |
| instead. <link linkend="dgui_misc_alternativesyntax">See more |
| about alternative syntaxes...</link></para> |
| </note> |
| |
| <para>The interpolation is used to insert the value of the |
| <literal><replaceable>expression</replaceable></literal> converted |
| to text (to string). Interpolations can be used only on two places: |
| in <link linkend="dgui_template_overallstructure"><phrase |
| role="markedText">text</phrase> sections</link> (e.g., |
| <literal><h1>Hello ${name}!</h1></literal>) and <link |
| linkend="dgui_template_exp_stringop_interpolation">in string literal |
| expressions</link> (e.g., <literal><#include |
| "/footer/${company}.html"></literal>).</para> |
| |
| <para>The result of the expression must be a string, number or |
| date/time/date-time value, because (by default) only these types are |
| converted to string by interpolation automatically. Values of other |
| types (such as booleans, sequences) must be converted to string |
| <quote>manually</quote> (see some advices later), or an error will |
| stop the template processing.</para> |
| |
| <warning> |
| <para>It's a frequent mistake to use interpolations on places |
| where they needn't/shouldn't/can't be used. Interpolations work |
| <emphasis>only</emphasis> in <link |
| linkend="dgui_template_overallstructure"><phrase |
| role="markedText">text</phrase> sections</link> (e.g. |
| <literal><h1>Hello ${name}!</h1></literal>) and in |
| <link linkend="dgui_template_exp_direct_string">string |
| literals</link> (e.g. <literal><#include |
| "/footer/${company}.html"></literal>). A typical |
| <emphasis>WRONG</emphasis> usage is <literal><#if |
| ${big}>...</#if></literal>, which will give syntactical |
| error. You should simply write <literal><#if |
| big>...</#if></literal>. Also, <literal><#if |
| "${big}">...</#if></literal> is |
| <emphasis>WRONG</emphasis>, since it converts the parameter value |
| to string and the <literal>if</literal> directive wants a boolean |
| value, so it will cause a runtime error.</para> |
| </warning> |
| </section> |
| |
| <section> |
| <title>Automatic escaping</title> |
| |
| <para>If the interpolation is in a <link |
| linkend="dgui_template_overallstructure"><phrase |
| role="markedText">text</phrase> section</link> (not in a <link |
| linkend="dgui_template_exp_stringop_interpolation">string literal |
| expression</link>), the text that it inserts goes through |
| automatically escaping, <emphasis>if FreeMarker was properly |
| configured</emphasis>. <link |
| linkend="dgui_quickstart_template_autoescaping">See more about |
| escaping here...</link>.</para> |
| </section> |
| |
| <section> |
| <title>Guide to inserting numerical values</title> |
| |
| <para>If the expression evaluates to a number then the numerical |
| value will be converted to string according the default number |
| format. This may includes the maximum number of decimals, grouping, |
| and like. Usually the programmer should set the default number |
| format; the template author doesn't have to deal with it (but he can |
| with the <literal>number_format</literal> setting; see in the <link |
| linkend="ref_directive_setting">documentation of |
| <literal>setting</literal> directive</link>). Also, you can override |
| the default number format for a single interpolation with the <link |
| linkend="ref_builtin_string_for_number"><literal>string</literal> |
| built-in</link>.</para> |
| |
| <para>The decimal separator used (and other such symbols, like the |
| group separator) depends on the current locale (language, country), |
| that also should be set by the programmer. For example, this |
| template:</para> |
| |
| <programlisting role="template">${1.5}</programlisting> |
| |
| <para>will print something like this if the current locale is |
| English:</para> |
| |
| <programlisting role="output">1.5</programlisting> |
| |
| <para>but if the current locale is German then it will print |
| something like:</para> |
| |
| <programlisting role="output">1,5</programlisting> |
| |
| <para>since German people use comma as decimal separator.</para> |
| |
| <warning> |
| <para>When the number you print will be read by some computer |
| process, always use the <link linkend="ref_builtin_c"><link |
| linkend="ref_builtin_c"><literal>c</literal></link> |
| built-in</link>, to get rid of any localized, or otherwise fancy |
| formatting! Like when you print a database record ID as the part |
| of an URL or as an invisible field value in a HTML form, or when |
| you print CSS/JavaScript numerical literals. Example:</para> |
| |
| <programlisting role="template"><a href="/shop/productdetails?id=${product.id<emphasis>?c</emphasis>}">Details...</a></programlisting> |
| |
| <para>That <literal>?c</literal> there formats the number with a |
| simple US format, which most computer processes will |
| understand.</para> |
| </warning> |
| </section> |
| |
| <section xml:id="dgui_template_valueinserion_universal_date"> |
| <title>Guide to inserting date/time/date-time values</title> |
| |
| <para>If the expression evaluates to a date-like value then that |
| will be transformed to a text according to a default format. Usually |
| the programmer should set the default format; the template author |
| doesn't have to deal with it (but if you care, <link |
| linkend="topic.dateTimeFormatSettings">see the |
| <literal>date_format</literal>, <literal>time_format</literal> and |
| <literal>datetime_format</literal> settings</link> in the |
| documentation of the <link |
| linkend="ref.directive.setting"><literal>setting</literal> |
| directive</link>). Also, you can override the default formatting for |
| a single interpolation with the <link |
| linkend="ref_builtin_string_for_date"><literal>string</literal> |
| built-in</link>.</para> |
| |
| <warning> |
| <para>To display a date-like value as text, FreeMarker must know |
| which parts of it are in use, that is, if only the date part |
| (year, month, day), or only the time part (hour, minute, second, |
| millisecond), or both. Unfortunately, because of the technical |
| limitations of Java platform, for some variables it is not |
| possible to detect this automatically; ask the programmer if the |
| data-model contains such problematic variables. When it's not |
| possible to find out which parts of the date are in use, then you |
| must help FreeMarker with the <link |
| linkend="ref_builtin_date_datetype"><literal>date</literal>, |
| <literal>time</literal> and <literal>datetime</literal></link> |
| built-ins (like <literal>${lastUpdated?datetime}</literal>), or it |
| will stop with error.</para> |
| </warning> |
| </section> |
| |
| <section> |
| <title>Guide to inserting boolean values</title> |
| |
| <para>By default an attempt to print boolean values with |
| interpolation causes an error and aborts template processing. For |
| example this will cause an error: <literal>${a == 2}</literal> and |
| will not print ''true'' or something like that. That's because |
| there's no universally useful way of representing booleans |
| (sometimes you want to print yes/no, sometimes enabled/disabled, |
| on/off, etc.).</para> |
| |
| <para>However, you can convert booleans to strings with the <link |
| linkend="ref_builtin_string_for_boolean"><literal>?string</literal> |
| built-in</link>. For example, to print the value of the "married" |
| variable (assuming it's a boolean), you could write |
| <literal>${married?string("yes", "no")}</literal>.</para> |
| |
| <para>FreeMarker can be configured with a default boolean format |
| with the <literal>boolean_format</literal> setting, then |
| <literal>${married}</literal> and such will work. However, in most |
| applications it's not recommended, as boolean should be rendered |
| differently on different places, and leaving the formatting on the |
| default is possibly just an oversight and thus should generate |
| error.</para> |
| |
| <para>When you want to generate JavaScript or other computer |
| language parts, then |
| <literal>${<replaceable>someBoolean</replaceable>?c}</literal> |
| (<quote>c</quote> stands for computer audience) should be used to |
| print true/false. (Remember that <literal>?c</literal> was also used |
| to print numbers for computer audience.)</para> |
| </section> |
| |
| <section> |
| <title>Exact conversion rules</title> |
| |
| <para>For those who are interested, the exact rules of conversion |
| from the expression value to string (which is then still subject to |
| escaping) are these, in this order:</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>If the value is a number, then it is converted to string |
| in the format specified with the |
| <literal>number_format</literal> setting. So this usually |
| formats for human audience, as opposed to computer |
| audience.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Else if the value is date, time or date-time, then it is |
| converted to string in the format specified with the |
| <literal>date_format</literal>, <literal>time_format</literal> |
| or <literal>datetime_format</literal> setting, respectively. If |
| it can't be detected what kind of date-like value it is (date vs |
| time vs date-time), an error will occur.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Else if the value is a string, then there is no |
| conversion.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Else if the engine is in classic compatibility |
| mode:</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>If the value is a boolean, true values are converted |
| to "true", false values are converted to an empty |
| string.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If the expression is undefined |
| (<literal>null</literal> or a variable is undefined), it is |
| converted to an empty string.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Else an error will abort the template |
| processing.</para> |
| </listitem> |
| </orderedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Else an error will abort the template processing.</para> |
| </listitem> |
| </orderedlist> |
| </section> |
| </section> |
| </chapter> |
| |
| <chapter xml:id="dgui_misc"> |
| <title>Miscellaneous</title> |
| |
| <remark>Do we need a short chapter on i18n/charset issues in general, |
| with the introduction of FreeMarker facilities on this field at the |
| end?</remark> |
| |
| <section xml:id="dgui_misc_userdefdir"> |
| <title>Defining your own directives</title> |
| |
| <indexterm> |
| <primary>macro</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>transform</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>custom directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>user-defined directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>directive</primary> |
| |
| <secondary>user-defined</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>tag</primary> |
| |
| <secondary>user-defined</secondary> |
| </indexterm> |
| |
| <para>As far as template authors are concerned, user-defined |
| directives can be defined using the <literal>macro</literal> |
| directive. <phrase role="forProgrammers">Java programmers who want to |
| implement directives in Java Language, rather than in a template, |
| should use |
| <literal>freemarker.template.TemplateDirectiveModel</literal> (see |
| <link linkend="pgui_datamodel_directive">more |
| here...</link>).</phrase></para> |
| |
| <section> |
| <title>Basics</title> |
| |
| <indexterm> |
| <primary>defining macro</primary> |
| </indexterm> |
| |
| <para>A macro is a template fragment associated with a variable. You |
| can use that variable in your template as a user-defined directive, |
| so it helps in repetitive tasks. For example, this creates a macro |
| variable that prints a big <quote>Hello Joe!</quote>:</para> |
| |
| <programlisting role="template"><emphasis><#macro greet></emphasis> |
| <font size="+2">Hello Joe!</font> |
| <emphasis></#macro></emphasis></programlisting> |
| |
| <para>The <literal>macro</literal> directive itself does not print |
| anything; it just creates the macro variable, so there will be a |
| variable called <literal>greet</literal>. Things between the |
| <literal><#macro greet></literal> and |
| <literal></#macro></literal> (called <emphasis |
| role="term">macro definition body</emphasis>) will be executed only |
| when you use the variable as directive. You use user-defined |
| directives by writing <literal>@</literal> instead of |
| <literal>#</literal> in the FTL tag. Use the variable name as the |
| directive name. Also, the <link |
| linkend="gloss.endTag">end-tag</link> for user-defined directives is |
| mandatory. So you use <literal>greet</literal> like this:</para> |
| |
| <programlisting role="template"><@greet></@greet></programlisting> |
| |
| <para>But since |
| <literal><<replaceable>anything</replaceable>></<replaceable>anything</replaceable>></literal> |
| is equivalent with |
| <literal><<replaceable>anything</replaceable>/></literal> you |
| should use this shorter form (that is familiar for you if you know |
| <link linkend="gloss.XML">XML</link>):</para> |
| |
| <programlisting role="template"><@greet/></programlisting> |
| |
| <para>This will print:</para> |
| |
| <programlisting role="output"> <font size="+2">Hello Joe!</font> |
| </programlisting> |
| |
| <para>But macros can do much more, since the thing between |
| <literal><#macro <replaceable>...</replaceable>></literal> and |
| <literal></#macro></literal> is a template fragment, thus it |
| can contain interpolations |
| (<literal>${<replaceable>...</replaceable>}</literal>) and FTL tags |
| (e.g. <literal><#if |
| <replaceable>...</replaceable>><replaceable>...</replaceable></#if></literal>).</para> |
| |
| <note> |
| <para>Programmers will say on |
| <literal><@<replaceable>...</replaceable>></literal> that |
| you <emphasis role="term">call</emphasis> the macro.</para> |
| </note> |
| </section> |
| |
| <section> |
| <title>Parameters</title> |
| |
| <para>Let's improve the <literal>greet</literal> macro so it can use |
| arbitrary name, not only <quote>Joe</quote>. For this purpose you |
| can use <emphasis role="term">parameters</emphasis>. You define the |
| parameters after the name of the macro in the |
| <literal>macro</literal> directive. Here we define one parameter for |
| the <literal>greet</literal> macro, |
| <literal>person</literal>:</para> |
| |
| <programlisting role="template"><#macro greet <emphasis>person</emphasis>> |
| <font size="+2">Hello <emphasis>${person}</emphasis>!</font> |
| </#macro></programlisting> |
| |
| <para>and then you can use this macro as:</para> |
| |
| <programlisting role="template"><@greet <emphasis>person="Fred"</emphasis>/> and <@greet <emphasis>person="Batman"</emphasis>/> |
| </programlisting> |
| |
| <para>which is similar to HTML syntax. This will print:</para> |
| |
| <programlisting role="output"> <font size="+2">Hello <emphasis>Fred</emphasis>!</font> |
| and <font size="+2">Hello <emphasis>Batman</emphasis>!</font> |
| </programlisting> |
| |
| <para>As you can see, the actual value of the macro parameter is |
| accessible in the macro definition body as a variable |
| (<literal>person</literal>). As with <link |
| linkend="gloss.predefinedDirective">predefined directives</link>, |
| the value of a parameter (the right side of <literal>=</literal>) is |
| an <link linkend="dgui_template_exp">FTL expression</link>. Thus, |
| unlike with HTML, the quotation marks around |
| <literal>"Fred"</literal> and <literal>"Batman"</literal> are not |
| optional. <literal><@greet person=Fred/></literal> would mean |
| that you use the value of variable <literal>Fred</literal> for the |
| <literal>person</literal> parameter, rather than the string |
| <literal>"Fred"</literal>. Of course parameter value need not be a |
| string, it can be number, boolean, hash, sequence, etc., also you |
| can use complex expression on the right side of <literal>=</literal> |
| (e.g. <literal>someParam=(price + 50)*1.25</literal>).</para> |
| |
| <para>User-defined directives can have multiple parameters. For |
| example, add a new parameter <literal>color</literal>:</para> |
| |
| <programlisting role="template"><#macro greet person <emphasis>color</emphasis>> |
| <font size="+2" color="${color}">Hello ${person}!</font> |
| </#macro></programlisting> |
| |
| <para>and then you can use this macro like:</para> |
| |
| <programlisting role="template"><@greet person="Fred" color="black"/></programlisting> |
| |
| <para>The order of parameters is not important, so this is |
| equivalent with the previous:</para> |
| |
| <programlisting role="template"><@greet color="black" person="Fred"/></programlisting> |
| |
| <para>When you call the macro, you can use only parameters that you |
| have defined in the <literal>macro</literal> directive (in this |
| case: <literal>person</literal> and <literal>color</literal>). So if |
| you try <literal><@greet person="Fred" color="black" |
| background="green"/></literal> then you will get an error, since |
| you haven't mentioned parameter <literal>background</literal> in the |
| <literal><#macro |
| <replaceable>...</replaceable>></literal>.</para> |
| |
| <para>Also, you must give value for all parameters that you have |
| defined for the macro. So if you try <literal><@greet |
| person="Fred"/></literal> then you will get an error, since you |
| forgot to specify the value of <literal>color</literal>. However, it |
| often happens that you would specify the same value for a parameter |
| in most cases, so you want to specify the value only when you want a |
| different value for it than the usual. This can be achieved if you |
| specify the parameter in the <literal>macro</literal> directive as |
| <literal><replaceable>param_name</replaceable>=<replaceable>usual_value</replaceable></literal>. |
| For example, you want to use <literal>"black"</literal> for |
| <literal>color</literal> if you don't specify value for that |
| parameter when you use the <literal>greet</literal> |
| directive:</para> |
| |
| <programlisting role="template"><#macro greet person color<emphasis>="black"</emphasis>> |
| <font size="+2" color="${color}">Hello ${person}!</font> |
| </#macro></programlisting> |
| |
| <para>Now <literal><@greet person="Fred"/></literal> is OK, |
| since it is equivalent with <literal><@greet person="Fred" |
| color="black"/></literal>, thus the value of |
| <literal>color</literal> parameter is known. If you want |
| <literal>"red"</literal> for <literal>color</literal>, then you |
| write <literal><@greet person="Fred" color="red"/></literal>, |
| and this value will override the usual value specified with the |
| <literal>macro</literal> directive, so the value of |
| <literal>color</literal> parameter will be |
| <literal>"red"</literal>.</para> |
| |
| <para>Also, it is important to realize that -- according to the |
| already explained <link linkend="dgui_template_exp">FTL expression |
| rules</link> -- <literal>someParam=foo</literal> and |
| <literal>someParam="${foo}"</literal> are very different. In the |
| fist case, you use the value of variable <literal>foo</literal> as |
| the value of the parameter. In the second case, you use a <link |
| linkend="dgui_template_exp_stringop_interpolation">string literal |
| with interpolation</link>, so the value of the parameter will be a |
| string -- in this case, the value of <literal>foo</literal> rendered |
| to text -- regardless of the type (as number, date, etc.) of |
| <literal>foo</literal>. Or, another example: |
| <literal>someParam=3/4</literal> and |
| <literal>someParam="${3/4}"</literal> are different. If the |
| directive wants a numerical value for <literal>someParam</literal>, |
| it will not like the second variation. Do not exchange these.</para> |
| |
| <para>A very important aspect of macro parameters is that they are |
| local variables. For more information about local variables please |
| read: <xref linkend="dgui_misc_var"/></para> |
| </section> |
| |
| <section> |
| <title>Nested content</title> |
| |
| <para>Custom directive can have nested content, similarly as |
| predefined directives like <literal><#if |
| <replaceable>...</replaceable>><replaceable>nested |
| content</replaceable></#if></literal> can have. For example, |
| this creates a macro that draws borders around its nested |
| content:</para> |
| |
| <programlisting role="template"><#macro border> |
| <table border=4 cellspacing=0 cellpadding=4><tr><td> |
| <emphasis><#nested></emphasis> |
| </tr></td></table> |
| </#macro></programlisting> |
| |
| <para>The <literal><#nested></literal> directive executes the |
| template fragment between the start-tag and end-tags of the |
| directive. So if you do this:</para> |
| |
| <programlisting role="template"><@border>The bordered text</@border></programlisting> |
| |
| <para>the output will be:</para> |
| |
| <programlisting role="output"> <table border=4 cellspacing=0 cellpadding=4><tr><td> |
| The bordered text |
| </td></tr></table> |
| </programlisting> |
| |
| <para>The <literal>nested</literal> directive can be called for |
| multiple times, for example:</para> |
| |
| <programlisting role="template"><#macro do_thrice><emphasis> |
| <#nested> |
| <#nested> |
| <#nested></emphasis> |
| </#macro> |
| <@do_thrice> |
| Anything. |
| </@do_thrice></programlisting> |
| |
| <para>will print:</para> |
| |
| <programlisting role="output"> Anything. |
| Anything. |
| Anything.</programlisting> |
| |
| <para>If you don't use the <literal>nested</literal> directive, then |
| the nested content will not be executed. Thus, if you accidentally |
| use the <literal>greet</literal> directive like this:</para> |
| |
| <programlisting role="template"><@greet person="Joe"> |
| Anything. |
| </@greet></programlisting> |
| |
| <para>then FreeMarker will not see this as an error, and simply |
| prints:</para> |
| |
| <programlisting role="output"><font size="+2">Hello Joe!</font></programlisting> |
| |
| <para>and the nested content will be ignored, since the |
| <literal>greet</literal> macro never uses <literal>nested</literal> |
| directive.</para> |
| |
| <para>The nested content can be anything that is valid FTL, |
| including other user-defined directives. Thus this is OK:</para> |
| |
| <programlisting role="template"><@border> |
| <ul> |
| <@do_thrice> |
| <li><@greet person="Joe"/> |
| </@do_thrice> |
| </ul> |
| </@border></programlisting> |
| |
| <para>and will print:</para> |
| |
| <programlisting role="output"> <table border=4 cellspacing=0 cellpadding=4><tr><td> |
| <ul> |
| <li><font size="+2">Hello Joe!</font> |
| |
| <li><font size="+2">Hello Joe!</font> |
| |
| <li><font size="+2">Hello Joe!</font> |
| |
| </ul> |
| |
| </tr></td></table></programlisting> |
| |
| <para>The <link linkend="dgui_misc_var">local variables</link> of a |
| macro are not visible in the nested content. Say, this:</para> |
| |
| <programlisting role="template"><#macro repeat count> |
| <#local y = "test"> |
| <#list 1..count as x> |
| ${y} ${count}/${x}: <#nested> |
| </#list> |
| </#macro> |
| <@repeat count=3>${y!"?"} ${x!"?"} ${count!"?"}</@repeat></programlisting> |
| |
| <para>will print this:</para> |
| |
| <programlisting role="output"> test 3/1: ? ? ? |
| test 3/2: ? ? ? |
| test 3/3: ? ? ?</programlisting> |
| |
| <para>because the <literal>y</literal>, <literal>x</literal> and |
| <literal>count</literal> are the local (private) variables of the |
| macro, and are not visible from outside the macro definition. |
| Furthermore, a different set of local variables is used for each |
| macro call, so this will not cause confusion:</para> |
| |
| <programlisting role="template"><#macro test foo>${foo} (<#nested>) ${foo}</#macro> |
| <@test foo="A"><@test foo="B"><@test foo="C"/></@test></@test> |
| </programlisting> |
| |
| <para>and will print this:</para> |
| |
| <programlisting role="output">A (B (C () C) B) A</programlisting> |
| </section> |
| |
| <section xml:id="dgui_misc_userdefdir_loopvar"> |
| <title>Macros with loop variables</title> |
| |
| <indexterm> |
| <primary>loop variable</primary> |
| </indexterm> |
| |
| <para>Predefined directives like <literal>list</literal> can use |
| so-called loop variables; you should read <xref |
| linkend="dgui_misc_var"/> to understand loop variables.</para> |
| |
| <para>User-defined directives can also have loop variables. For |
| example, let's extend the <literal>do_thrice</literal> directive of |
| the earlier examples so it exposes the current repetition number as |
| a loop variable. As with the predefined directives (as |
| <literal>list</literal>) the <emphasis>name</emphasis> of loop |
| variables is given when you call the directive (as |
| <literal>foo</literal> in <literal><#list foos as |
| foo><replaceable>...</replaceable></#list></literal>), |
| while the <emphasis>value</emphasis> of the variables is set by the |
| directive itself.</para> |
| |
| <programlisting role="template"><#macro do_thrice> |
| <#nested <emphasis>1</emphasis>> |
| <#nested <emphasis>2</emphasis>> |
| <#nested <emphasis>3</emphasis>> |
| </#macro> |
| <@do_thrice <emphasis>; x</emphasis>> <#-- user-defined directive uses ";" instead of "as" --> |
| ${<emphasis>x</emphasis>} Anything. |
| </@do_thrice></programlisting> |
| |
| <para>This will print:</para> |
| |
| <programlisting role="output"> 1 Anything. |
| 2 Anything. |
| 3 Anything. |
| </programlisting> |
| |
| <para>The syntactical rule is that you pass the actual value of the |
| loop variable for a certain "loop" (i.e. repetition of the nested |
| content) as the parameter of <literal>nested</literal> directive (of |
| course the parameter can by arbitrary expression). The name of the |
| loop variable is specified in the user-defined directive open tag |
| (<literal><@...></literal>) after the parameters and a |
| semicolon.</para> |
| |
| <para>A macro can use more the one loop variable (the order of |
| variables is significant):</para> |
| |
| <programlisting role="template"><#macro repeat count> |
| <#list 1..count as x> |
| <#nested <emphasis>x, x/2, x==count</emphasis>> |
| </#list> |
| </#macro> |
| <@repeat count=4 ; <emphasis>c, halfc, last</emphasis>> |
| ${<emphasis>c</emphasis>}. ${<emphasis>halfc</emphasis>}<#if <emphasis>last</emphasis>> Last!</#if> |
| </@repeat></programlisting> |
| |
| <para>The output will be:</para> |
| |
| <programlisting role="output"> 1. 0.5 |
| 2. 1 |
| 3. 1.5 |
| 4. 2 Last! |
| </programlisting> |
| |
| <para>It is not a problem if you specify different number of loop |
| variables in the user-defined directive start-tag (that is, after |
| the semicolon) than with the <literal>nested</literal> directive. If |
| you specify less loop variables after the semicolon, then simply you |
| will not see the last few values that the <literal>nested</literal> |
| directive provides, since there is no loop variable to hold those |
| values. So these are all OK:</para> |
| |
| <programlisting role="template"><@repeat count=4 ; <emphasis>c, halfc, last</emphasis>> |
| ${c}. ${halfc}<#if last> Last!</#if> |
| </@repeat> |
| <@repeat count=4 ; <emphasis>c, halfc</emphasis>> |
| ${c}. ${halfc} |
| </@repeat> |
| <@repeat count=4> |
| Just repeat it... |
| </@repeat></programlisting> |
| |
| <para>If you specify more variables after the semicolon than with |
| the <literal>nested</literal> directive, then the last few loop |
| variables will not be created (i.e. will be undefined in the nested |
| content).</para> |
| </section> |
| |
| <section> |
| <title>More about user-defined directives and macros</title> |
| |
| <para>Now you may read the relevant parts of the FreeMarker |
| Reference:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><link linkend="ref.directive.userDefined">user-defined |
| directive call</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref.directive.macro"><literal>macro</literal> |
| directive</link></para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>You can define methods in FTL as well, see <link |
| linkend="ref.directive.function">the <literal>function</literal> |
| directive</link>.</para> |
| |
| <para>Also, you may interested in namespaces: <xref |
| linkend="dgui_misc_namespace"/>. Namespaces help you to organize and |
| reuse your commonly used macros.</para> |
| |
| <para>Java programmers might want to know that directives (macros |
| are directives) and methods (function-like things) can also be |
| written in Java language, by<link |
| linkend="pgui_datamodel_directive"> implementing the |
| <literal>TemplateDirectiveModel</literal></link> or |
| <literal>TemplateMethodModelEx</literal> interfaces, respectively. |
| Then you can pull in the Java implementations into the template like |
| <literal><#assign foo = |
| "com.example.FooDirective"?new()></literal> or |
| <literal><#assign foo = |
| "com.example.FooMethod"?new()></literal> on the same place where |
| you would have <literal><#macro foo |
| <replaceable>...</replaceable>></literal> or |
| <literal><#function foo |
| <replaceable>...</replaceable>></literal> otherwise.</para> |
| </section> |
| </section> |
| |
| <section xml:id="dgui_misc_var"> |
| <title>Defining variables in the template</title> |
| |
| <indexterm> |
| <primary>variable</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>loop variable</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>local variable</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>temporary variable</primary> |
| </indexterm> |
| |
| <para>Most of the variables that a typical template works with comes |
| from the data-model. But templates can also define variables |
| themselves, usually to hold loops variables, temporary results, |
| macros, etc. Such variables are outside the data-model; modifying the |
| data-model from templates is by design unsupported. Note that each |
| <link linkend="gloss.templateProcessingJob">template processing |
| job</link> has its own private set of these variables, which will be |
| thrown away when the template processing job is finished.</para> |
| |
| <para>You access variables defined in the template the same way as you |
| access variables defined in the data-model root. For example, if you |
| create a variable called <quote>foo</quote> in the template, you can |
| print its value with <literal>${foo}</literal>. If, coincidently, |
| there's a variable called <quote>foo</quote> in the data-model too, |
| the variable created in the template will hide (not overwrite!) |
| it.</para> |
| |
| <para>There are these kinds of variables that are defined in a |
| template:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><emphasis role="term"><quote>plain</quote> |
| variables</emphasis>: They are accessible from everywhere in the |
| template, or from another templates that was inserted with the |
| <link linkend="ref.directive.include"><literal>include</literal> |
| directive</link>. You can create and replace these variables with |
| the <link linkend="ref.directive.assign"><link |
| linkend="ref.directive.assign"><literal>assign</literal></link> |
| directive</link>, or, because macros and functions are just |
| variables, with the <link |
| linkend="ref.directive.macro"><literal>macro</literal> |
| directives</link> and <link |
| linkend="ref.directive.function"><literal>function</literal> |
| directives</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><emphasis role="term">Local variables</emphasis>: They can |
| only be set inside a <link |
| linkend="gloss.macroDefinitionBody">macro definition body</link> |
| or <link linkend="gloss.functionDefinitionBody">function |
| definition body</link>, and are only visible from there, not from |
| other macros or functions called from there. A local variable only |
| exists for the duration of a macro or function call. You can |
| create and replace local variables inside the definition body with |
| the <link linkend="ref.directive.local"><literal>local</literal> |
| directive</link>. <link linkend="ref.directive.macro">Macro</link> |
| and <link linkend="ref.directive.function">function</link> |
| parameters are also local variables.</para> |
| </listitem> |
| |
| <listitem> |
| <para><emphasis role="term">Loop variables</emphasis>: Loop |
| variables are created automatically by directives like <link |
| linkend="ref.directive.list"><literal>list</literal></link> (like |
| <literal>x</literal> in <literal><#list xs as |
| x><replaceable>...</replaceable></#list></literal>), and |
| they only exist between the start-tag and end-tag of the |
| directive. (User defined directives, like macros, can also create |
| loop variables.) They are only visible directly between these |
| tags, not from macros or functions called from there. As such, |
| they are quite similar to local variables, but they can't be |
| assigned to directly.</para> |
| </listitem> |
| |
| <listitem> |
| <para><emphasis role="term">Global variables</emphasis>: These |
| should be seldom used. Global variables are shared by all |
| templates, even if they belong to different name spaces because of |
| <link |
| linkend="ref.directive.import"><literal>import</literal>-ing</link>. |
| Thus, their visibility is similar to data-model variables. They |
| are set via the <link |
| linkend="ref.directive.global"><literal>global</literal> |
| directive</link>. Global variables hide (but don't overwrite) the |
| data-model variables of the same name.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Example: Create and replace variables with |
| <literal>assign</literal>:</para> |
| |
| <programlisting role="template"><#assign x = 1> <#-- create variable x --> |
| ${x} |
| <#assign x = 2> <#-- replace variable x --> |
| ${x} |
| <#assign x++> <#-- replace variable x --> |
| ${x}</programlisting> |
| |
| <programlisting role="output">1 |
| 2 |
| 3</programlisting> |
| |
| <para>In the next example we demonstrate that local variables hide |
| (not overwrite) <quote>plain</quote> variables of the same name, and |
| that loop variables hide (not overwrite) local and |
| <quote>plain</quote> variables of the same name:</para> |
| |
| <programlisting role="template"><#assign x = "plain"> |
| 1. ${x} <#-- we see the plain var. here --> |
| <@test/> |
| 6. ${x} <#-- the value of plain var. was not changed --> |
| <#list ["loop"] as x> |
| 7. ${x} <#-- now the loop var. hides the plain var. --> |
| <#assign x = "plain2"> <#-- replaces the plain var, not the loop var. --> |
| 8. ${x} <#-- it still hides the plain var. --> |
| </#list> |
| 9. ${x} <#-- now the new value of plain var. becomse visible --> |
| |
| <#macro test> |
| 2. ${x} <#-- we still see the plain var. here --> |
| <#local x = "local"> |
| 3. ${x} <#-- now the local var. hides it --> |
| <#list ["loop"] as x> |
| 4. ${x} <#-- now the loop var. hides the local var. --> |
| </#list> |
| 5. ${x} <#-- now we see the local var. again --> |
| </#macro></programlisting> |
| |
| <programlisting role="output">1. plain |
| 2. plain |
| 3. local |
| 4. loop |
| 5. local |
| 6. plain |
| 7. loop |
| 8. loop |
| 9. plain2 </programlisting> |
| |
| <para>In the next example we demonstrate that an inner loop variable |
| can hide (not overwrite) an outer loop variable of the same |
| name:</para> |
| |
| <programlisting role="template"><#list ["loop 1"] as x> |
| ${x} |
| <#list ["loop 2"] as x> |
| ${x} |
| <#list ["loop 3"] as x> |
| ${x} |
| </#list> |
| ${x} |
| </#list> |
| ${x} |
| </#list></programlisting> |
| |
| <programlisting role="output"> loop 1 |
| loop 2 |
| loop 3 |
| loop 2 |
| loop 1</programlisting> |
| |
| <para>When a variable hides the variable from the data-model, you can |
| still read that variable from the data-model using <link |
| linkend="dgui_template_exp_var_special">special variable</link> |
| <literal>globals</literal>. For example, assume we have a variable |
| called <literal>user</literal> in the data-model with value <quote>Big |
| Joe</quote>:</para> |
| |
| <programlisting role="template">${user} <#-- prints: Big Joe --> |
| <#assign user = "Joe Hider"> |
| ${user} <#-- prints: Joe Hider --> |
| ${.globals.user} <#-- prints: Big Joe --></programlisting> |
| |
| <para>You could also write <literal>.data_model.user</literal> |
| instead, and then not even a <literal><#global user = |
| "<replaceable>...</replaceable>"></literal> can hide the value in |
| the data-model. However, global variables are often purposely set to |
| override the value coming from the data-model, so using |
| <literal>globals</literal> is a better practice usually.</para> |
| |
| <para>For information about syntax of variables (allowed characters |
| and such) please read: <xref linkend="dgui_template_exp"/></para> |
| </section> |
| |
| <section xml:id="dgui_misc_namespace"> |
| <title>Namespaces</title> |
| |
| <indexterm> |
| <primary>namespaces</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>libraries</primary> |
| </indexterm> |
| |
| <para>When you run templates, you have a (possibly empty) set of |
| variables that you have created with <literal>assign</literal> and |
| <literal>macro</literal> and <literal>function</literal> directives |
| (see in the <link linkend="dgui_misc_var">previous chapter</link>). A |
| set of template-made variables like that is called a <emphasis |
| role="term">namespace</emphasis>. In simple cases you use only one |
| namespace, the <emphasis role="term">main namespace</emphasis>. |
| Whenever you define a variable in the main template (macros and |
| functions are also variables, mind you), or in templates <link |
| linkend="ref.directive.include"><literal>include</literal>-d</link> in |
| it, that's where the variable are created. The key property of a |
| namespace is that the variable name uniquely identifies a value in it |
| (i.e, you can't have multiple variables in it with the same name in |
| the same namespace).</para> |
| |
| <para>Sometimes you want to build reusable collection of macros, |
| functions, and other variables, which we call a <emphasis |
| role="term">library</emphasis>. It's important that a library can use |
| its own namespace, to avoid accidental name clashes. Consider, you may |
| have many names in that library, and you intend to use the library in |
| many templates, maybe even reuse it in several projects. It becomes |
| impractical to keep track of where the library used in another |
| template accidentally hides variables from the data-model, or what |
| names you shouldn't assign to in the template to avoid overwriting the |
| variables of the library. If you have multiple libraries used in the |
| same template, this becomes even harder to track. So you should use a |
| separate namespace for the variables of each library.</para> |
| |
| <section> |
| <title>Creating a library</title> |
| |
| <para>Here's a simple library, which contains a |
| <literal>copyright</literal> macro and a <literal>mail</literal> |
| string:</para> |
| |
| <programlisting role="template"><#macro copyright date> |
| <p>Copyright (C) ${date} Someone. All rights reserved.</p> |
| </#macro> |
| |
| <#assign mail = "user@example.com"></programlisting> |
| |
| <para>Save this into the <literal>lib/example.ftl</literal> file |
| (inside the directory where you store the templates). Then create a |
| template, let's say, <literal>some_web_page.ftl</literal>, and use |
| the library in it:</para> |
| |
| <programlisting role="template"><#<emphasis>import</emphasis> "/lib/example.ftl" as <emphasis>e</emphasis>> |
| |
| Some Web page... |
| <@<emphasis>e</emphasis>.copyright date="1999-2002"/> |
| ${<emphasis>e</emphasis>.mail}</programlisting> |
| |
| <programlisting role="output">Some Web page... |
| <p>Copyright (C) 1999-2002 Someone. All rights reserved.</p> |
| user@example.com</programlisting> |
| |
| <para>Note the <link |
| linkend="ref.directive.import"><literal>import</literal> |
| directive</link> above, and the subsequent usage of the |
| <quote><literal>e</literal></quote> variable. |
| <literal>import</literal> is similar to the perhaps already familiar |
| <link linkend="ref.directive.include"><literal>include</literal> |
| directive</link>, but it will create an empty namespace and will run |
| <literal>lib/example.ftl</literal> in that namespace. So |
| <literal>lib/example.ftl</literal> will find itself in a clean |
| world, where only the variables of the data-models are visible (and |
| the globals), and will create its two variables |
| (<literal>copyright</literal> and <literal>mail</literal>) in this |
| clean namespace. But you will need to access those two variables |
| from another namespace (the main namespace), thus, the |
| <literal>import</literal> directive creates a hash variable |
| (<literal>e</literal> in this case) to access the namespace it has |
| created . That variable is in the namespace that the |
| <literal>import</literal>-ing template uses, and acts as a window to |
| the namespace of the imported library.</para> |
| |
| <para>To demonstrate that the two namespaces are separate, consider |
| the example below. Replace <literal>lib/example.ftl</literal> with |
| this:</para> |
| |
| <programlisting role="template"><#macro copyright date> |
| <p>Copyright (C) ${date} Someone. All rights reserved. |
| <br>Email: <emphasis>${mail}</emphasis></p> |
| </#macro> |
| |
| <#assign mail = "user@example.com"></programlisting> |
| |
| <para>and <literal>some_web_page.ftl</literal> with this:</para> |
| |
| <programlisting role="template"><#import "/lib/example.ftl" as e> |
| <emphasis><#assign mail="other@example.com"></emphasis> |
| <@e.copyright date="1999-2002"/> |
| ${e.mail} |
| ${mail}</programlisting> |
| |
| <programlisting role="output"> <p>Copyright (C) 1999-2002 Someone. All rights reserved. |
| <br>Email: <emphasis>user@example.com</emphasis></p> |
| user@example.com |
| other@example.com</programlisting> |
| |
| <para>As you can see, the <literal>mail</literal> variable assigned |
| in <literal>some_web_page.ftl</literal> is separate from the |
| <literal>mail</literal> variable assigned in the imported |
| library.</para> |
| </section> |
| |
| <section> |
| <title>Writing the variables of imported namespaces</title> |
| |
| <para>Sometimes you want to create or replace a variable in an |
| imported namespace. You can do that with the |
| <literal>assign</literal> directive and its |
| <literal>namespace</literal> parameter:</para> |
| |
| <programlisting role="template"><#import "/lib/example.ftl" as e> |
| ${e.mail} |
| <#assign mail="other@example.com" <emphasis>in e</emphasis>> |
| ${e.mail}</programlisting> |
| |
| <programlisting role="output">user@example.com |
| other@example.com</programlisting> |
| </section> |
| |
| <section> |
| <title>Namespaces and data-model</title> |
| |
| <para>The variables of the data-model are visible from everywhere. |
| For example, if you have a variable called <literal>user</literal> |
| in the data-model, <literal>lib/example.ftl</literal> will access |
| that, exactly like <literal>some_web_page.ftl</literal> does:</para> |
| |
| <programlisting role="template"><#macro copyright date> |
| <p>Copyright (C) ${date} <emphasis>${user}</emphasis>. All rights reserved.</p> |
| </#macro></programlisting> |
| |
| <para>Assuming <literal>user</literal> is <quote>John |
| Doe</quote>:</para> |
| |
| <programlisting role="template"><#import "/lib/my_test.ftl" as my> |
| User is: ${user} |
| <@my.copyright date="1999-2002"/> |
| </programlisting> |
| |
| <programlisting role="output">User is: John Doe |
| <p>Copyright (C) 1999-2002 John Doe. All rights reserved.</p> |
| </programlisting> |
| |
| <para>Don't forget that the variables in the namespace (the |
| variables you create with <literal>assign</literal>, |
| <literal>macro</literal>, and <literal>function</literal> |
| directives) have precedence over the variables of the data-model |
| when you are in that namespace. So generally, if a library is |
| interested in a data-model variable, it doesn't assign to the same |
| name.</para> |
| |
| <note> |
| <para>In some unusual applications you want to create variables in |
| the template that are visible from all namespaces, exactly like |
| the variables of the data-model. While templates can't change the |
| data-model, it's possible to achieve similar effect with the |
| <literal>global</literal> directive; see the <link |
| linkend="ref.directive.global">reference</link>.</para> |
| </note> |
| </section> |
| |
| <section> |
| <title>The life-cycle of namespaces</title> |
| |
| <para>A namespace is identified by the path used in the |
| <literal>import</literal> directive (after it was normalized to an |
| absolute path). If you try to <literal>import</literal> with |
| equivalent paths for multiple times, it will create the namespace |
| and run the template for only the first invocation of |
| <literal>import</literal>. The later <literal>import</literal>-s |
| with equivalent paths will just assign the same namespace to the |
| variable specified after the <literal>as</literal> keyword. For |
| example:</para> |
| |
| <programlisting role="template"><#import "/lib/example.ftl" as e> |
| <#import "/lib/example.ftl" as e2> |
| <#import "/lib/example.ftl" as e3> |
| ${e.mail}, ${e2.mail}, ${e3.mail} |
| <#assign mail="other@example.com" in e> |
| ${e.mail}, ${e2.mail}, ${e3.mail}</programlisting> |
| |
| <programlisting role="output">user@example.com, user@example.com, user@example.com |
| other@example.com, other@example.com, other@example.com</programlisting> |
| |
| <para>As you access the same namespace through <literal>e</literal>, |
| <literal>e2</literal>, and <literal>e3</literal>, the |
| <literal>email</literal> has changed in all of them at once. The |
| practical importance of this is that when you import the same |
| library in multiple templates, only one namespace will be |
| initialized and created for the library, which will be shared by all |
| the importing templates.</para> |
| |
| <para>Note that namespaces are not hierarchical; it doesn't mater |
| what namespace are you in when <literal>import</literal> creates |
| another namespace. For example, when you <literal>import</literal> |
| namespace N2 while you are in name space N1, N2 will not be inside |
| N1. N1 just gets the same N2 that you get if you |
| <literal>import</literal> N2 when you are in the main |
| namespace.</para> |
| |
| <para>Each <link linkend="gloss.templateProcessingJob">template |
| processing job</link> has its own private set of namespaces. Each |
| template processing job is a separate universe that exists only for |
| the short period while the main template is rendered, and then it |
| vanishes with all its populated namespaces. Thus, whenever we say |
| that <quote><literal>import</literal> is called for the first |
| time</quote>, we always mean the first time within the lifespan of a |
| single template processing job.</para> |
| </section> |
| |
| <section> |
| <title>Auto-importing</title> |
| |
| <para>When you have to import the same libraries again and again in |
| many templates, know that the Java programmers (or whoever is |
| responsible for configuring FreeMarker) can specify auto-imports, |
| which are imports that are automatically done in all templates. Auto |
| imports can also be configured to be <quote>lazy</quote> (since |
| FreeMarker 2.3.25), which means that they are only done when the |
| imported library is actually used in the template. See the Java API |
| documentation for more details: <link |
| xlink:href="https://freemarker.apache.org/docs/api/freemarker/template/Configuration.html#setAutoImports-java.util.Map-">Configuration.setAutoImports</link>, |
| <link |
| xlink:href="https://freemarker.apache.org/docs/api/freemarker/template/Configuration.html#setLazyAutoImports-java.lang.Boolean-">Configuration.setLazyAutoImports</link>.</para> |
| </section> |
| </section> |
| |
| <section xml:id="dgui_misc_autoescaping"> |
| <title>Auto-escaping and output formats</title> |
| |
| <indexterm> |
| <primary>escaping</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>auto-escaping</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>MIME type</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>HTML escaping</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>HTML encoding</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>XML escaping</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>XML encoding</primary> |
| </indexterm> |
| |
| <para>This is a <emphasis>detailed</emphasis> tutorial to |
| auto-escaping and related concepts; for the bare minimum, <link |
| linkend="dgui_quickstart_template_autoescaping">read this |
| instead</link>.</para> |
| |
| <note> |
| <para>The kind of automatic escaping described here requires at |
| least FreeMarker 2.3.24. If you have to use an earlier version, use |
| the deprecated <link |
| linkend="ref_directive_escape"><literal>escape</literal> |
| directive</link> instead.</para> |
| </note> |
| |
| <section xml:id="dgui_misc_autoescaping_outputformat"> |
| <title>Output formats</title> |
| |
| <indexterm> |
| <primary>output format</primary> |
| </indexterm> |
| |
| <para>Each template has an associated output format <phrase |
| role="forProgrammers">(a |
| <literal>freemarker.core.OutputFormat</literal> instance)</phrase>. |
| The output format dictates the escaping rules, which is applied on |
| all <literal>${<replaceable>...</replaceable>}</literal>-s (and |
| <literal>#{<replaceable>...</replaceable>}</literal>-s) that aren't |
| <link linkend="dgui_misc_autoescaping_stringliteral">inside a string |
| literal</link>. It also specifies a MIME type (e.g. |
| <literal>"text/HTML"</literal>) and a canonical name (e.g. |
| <literal>"HTML"</literal>) that the embedding application/framework |
| can use for its own purposes.</para> |
| |
| <para>It's the programmer's responsibility to <link |
| linkend="pgui_config_outputformatsautoesc">associate output format |
| to templates</link>. Furthermore it's recommended that FreeMarker is |
| configured so that templates with <literal>ftlh</literal> and |
| <literal>ftlx</literal> file extensions are automatically associated |
| with the HTML and XML output formats, respectively.</para> |
| |
| <para xml:id="topic.predefinedOutputFormats">The predefined output |
| formats are:</para> |
| |
| <informaltable border="1"> |
| <thead> |
| <tr> |
| <th>Name</th> |
| |
| <th>Description</th> |
| |
| <th>MIME Type</th> |
| |
| <th>Default implementation |
| (<literal>freemarker.core.*</literal>)</th> |
| </tr> |
| </thead> |
| |
| <tbody> |
| <tr> |
| <td><literal>HTML</literal></td> |
| |
| <td>Escapes <literal><</literal>, <literal>></literal>, |
| <literal>&</literal>, <literal>"</literal>, |
| <literal>'</literal> as <literal>&lt;</literal>, |
| <literal>&gt;</literal>, <literal>&amp;</literal>, |
| <literal>&quot;</literal>, |
| <literal>&#39;</literal></td> |
| |
| <td><literal>text/html</literal></td> |
| |
| <td><literal>HTMLOutputFormat.INSTANCE</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>XHTML</literal></td> |
| |
| <td>Escapes <literal><</literal>, <literal>></literal>, |
| <literal>&</literal>, <literal>"</literal>, |
| <literal>'</literal> as <literal>&lt;</literal>, |
| <literal>&gt;</literal>, <literal>&amp;</literal>, |
| <literal>&quot;</literal>, |
| <literal>&#39;</literal></td> |
| |
| <td><literal>application/xhtml+xml</literal></td> |
| |
| <td><literal>XHTMLOutputFormat.INSTANCE</literal></td> |
| </tr> |
| </tbody> |
| |
| <tbody> |
| <tr> |
| <td><literal>XML</literal></td> |
| |
| <td>Escapes <literal><</literal>, <literal>></literal>, |
| <literal>&</literal>, <literal>"</literal>, |
| <literal>'</literal> as <literal>&lt;</literal>, |
| <literal>&gt;</literal>, <literal>&amp;</literal>, |
| <literal>&quot;</literal>, |
| <literal>&apos;</literal></td> |
| |
| <td><literal>application/xml</literal></td> |
| |
| <td><literal>XMLOutputFormat.INSTANCE</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>RTF</literal></td> |
| |
| <td>Escapes <literal>{</literal>, <literal>}</literal>, |
| <literal>\</literal> as <literal>\{</literal>, |
| <literal>\}</literal>, <literal>\\</literal></td> |
| |
| <td><literal>application/rtf</literal></td> |
| |
| <td><literal>RTFOutputFormat.INSTANCE</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>undefined</literal></td> |
| |
| <td>Doesn't escape. Prints markup output values (concept |
| explained <link |
| linkend="dgui_misc_autoescaping_movalues">later</link>) from |
| other output formats as is. The default output format used |
| when no output format was explicitly set in the |
| configuration.</td> |
| |
| <td>None (<literal>null</literal>)</td> |
| |
| <td><literal>UndefinedOutputFormat.INSTANCE</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>plainText</literal></td> |
| |
| <td>Doesn't escape.</td> |
| |
| <td><literal>text/plain</literal></td> |
| |
| <td><literal>PlainTextOutputFormat.INSTANCE</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>JavaScript</literal></td> |
| |
| <td>Doesn't escape.</td> |
| |
| <td><literal>application/javascript</literal></td> |
| |
| <td><literal>JavaScriptOutputFormat.INSTANCE</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>JSON</literal></td> |
| |
| <td>Doesn't escape.</td> |
| |
| <td><literal>application/json</literal></td> |
| |
| <td><literal>JSONOutputFormat.INSTANCE</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>CSS</literal></td> |
| |
| <td>Doesn't escape.</td> |
| |
| <td><literal>text/css</literal></td> |
| |
| <td><literal>CSSOutputFormat.INSTANCE</literal></td> |
| </tr> |
| </tbody> |
| </informaltable> |
| |
| <para>The programmers can add their your own output formats, so this |
| is maybe not all the output formats in your application!</para> |
| </section> |
| |
| <section xml:id="dgui_misc_autoescaping_overrideoformat"> |
| <title>Overriding the output format in templates</title> |
| |
| <para>Especially in legacy applications, you will often find that |
| the output format is <literal>undefined</literal> (you can check |
| that with <literal>${.output_format}</literal>), and so no automatic |
| escaping is happening. In other cases, a common output format (like |
| HTML) is set for all templates, but a few templates need a different |
| output format. In any case, the output format of a template can be |
| enforced in the <link linkend="ref_directive_ftl">the |
| <literal>ftl</literal> header</link>:</para> |
| |
| <programlisting role="template"><#ftl output_format="XML"> |
| ${"'"} <#-- Prints: &apos; --></programlisting> |
| |
| <para>Above, the output format was referred by its name shown in the |
| earlier table <emphasis role="forProgrammers">(looked up via |
| <literal>Configuration.getOutputFormat(String name)</literal>, |
| actually)</emphasis>.</para> |
| |
| <note> |
| <para>If escaping doesn't happen after adding the above |
| <literal>ftl</literal> header, then <literal><#ftl |
| output_format="XML" auto_esc=true></literal> might helps (and |
| that means that FreeMarker was configured to use |
| <quote>disable</quote> auto-escaping <emphasis>policy</emphasis>, |
| which is generally not recommended).</para> |
| </note> |
| |
| <para>The output format can also be applied to only a section of a |
| template, like:</para> |
| |
| <programlisting role="template"><#-- Let's assume we have "HTML" output format by default. --> |
| ${"'"} <#-- Prints: &#39; --> |
| <#outputformat "XML"> |
| ${"'"} <#-- Prints: &apos; --> |
| </#outputformat> |
| ${"'"} <#-- Prints: &#39; --> |
| </programlisting> |
| |
| <para>Basically, each position in a template has an associated |
| output format, and as you saw above, it might not be the same |
| everywhere in the template. This association sticks to the positions |
| and won't change as the template executes. So if, for example, you |
| call a macro from inside an <literal>outputformat</literal> block |
| and the called macro is defined outside that block, it won't get the |
| output format of it. Or, if you have a macro that's defined in a |
| template with HTML output format, no mater from where you call it, |
| that macro will always execute with HTML output format. This is like |
| if you were coloring each characters of the template files by output |
| format in the text editor, and then later when the templates are |
| executed, it only considers the color of the statement being |
| executed. This gives you firm control over the output format and |
| hence escaping; you don't have to consider the possible execution |
| paths that can lead to a point.</para> |
| </section> |
| |
| <section xml:id="dgui_misc_autoescaping_disableautoesc"> |
| <title>Disabling auto escaping</title> |
| |
| <para>For a single interpolation you can disable auto-escaping with |
| <link |
| linkend="ref_builtin_no_esc"><literal>?no_esc</literal></link>:</para> |
| |
| <programlisting role="template"><#-- Let's assume we have "HTML" output format by default. --> |
| ${'<b>test</b>'} <#-- prints: &lt;b&gt;test&lt;/b&gt; --> |
| ${'<b>test</b>'<emphasis>?no_esc</emphasis>} <#-- prints: <b>test</b> --></programlisting> |
| |
| <para>You can also disable auto escaping for a whole section with |
| the <link |
| linkend="ref_directive_noautoesc"><literal>noautoesc</literal> |
| directive</link>:</para> |
| |
| <programlisting role="template">${'&'} <#-- prints: &amp; --> |
| <emphasis><#noautoesc></emphasis> |
| ${'&'} <#-- prints: & --> |
| ... |
| ${'&'} <#-- prints: & --> |
| <emphasis></#noautoesc></emphasis> |
| ${'&'} <#-- prints: &amp; --></programlisting> |
| |
| <para>Just like <literal>outputformat</literal>, this only applies |
| to the part that's literally inside the block |
| (<quote>coloring</quote> logic).</para> |
| |
| <para>Auto-escaping can also be disabled for the whole template in |
| the <literal>ftl</literal> header. It can then be re-enabled for a |
| section with the <link |
| linkend="ref_directive_autoesc"><literal>autoesc</literal> |
| directive</link>:</para> |
| |
| <programlisting role="template"><#ftl <emphasis>autoesc=false</emphasis>> |
| ${'&'} <#-- prints: & --> |
| <emphasis><#autoesc></emphasis> |
| ${'&'} <#-- prints: &amp; --> |
| ... |
| ${'&'} <#-- prints: &amp; --> |
| <emphasis></#autoesc></emphasis> |
| ${'&'} <#-- prints: & --></programlisting> |
| |
| <para>You can also force escaping for an individual interpolation |
| when escaping is disabled, with <link |
| linkend="ref_builtin_esc"><literal>?esc</literal></link>:</para> |
| |
| <programlisting role="template"><#ftl <emphasis>autoesc=false</emphasis>> |
| ${'&'} <#-- prints: & --> |
| ${'&'<emphasis>?esc</emphasis>} <#-- prints: &amp; --></programlisting> |
| |
| <para>Naturally, both <literal>autoesc</literal> and |
| <literal>?esc</literal> works inside <literal>noautoesc</literal> |
| blocks too.</para> |
| </section> |
| |
| <section xml:id="dgui_misc_autoescaping_movalues"> |
| <title><quote>Markup output</quote> values</title> |
| |
| <para>In FTL, <link linkend="dgui_datamodel_basics">values have |
| type</link>, like string, number, boolean, etc. One such type is |
| called <quote>markup output</quote>. A value of that type is a piece |
| of text that's already in the output format (like HTML), and hence |
| needs no further escaping. We have already produced such values |
| earlier:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal><replaceable>s</replaceable>?esc</literal> |
| creates a markup output value out of a string value by escaping |
| all special characters in it.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>s</replaceable>?no_esc</literal> |
| creates a markup output value out of a string value by assuming |
| that the string already stores markup and so needs no further |
| escaping</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>These can be useful outside |
| <literal>${<replaceable>...</replaceable>}</literal> too. For |
| example, here the caller of the <literal>infoBox</literal> macro can |
| decide if the message is plain text (hence needs escaping) or HTML |
| (hence it mustn't be escaped):</para> |
| |
| <programlisting role="template"><#-- We assume that we have "HTML" output format by default. --> |
| |
| <@infoBox "Foo & bar" /> |
| <@infoBox "Foo <b>bar</b>"?no_esc /> |
| |
| <#macro infoBox message> |
| <div class="infoBox"> |
| ${message} |
| </div> |
| </#macro></programlisting> |
| |
| <programlisting role="output"> <div class="infoBox"> |
| Foo &amp; bar |
| </div> |
| <div class="infoBox"> |
| Foo <b>bar</b> |
| </div></programlisting> |
| |
| <para>Another case where you get a markup output value is output |
| capturing:</para> |
| |
| <programlisting role="template"><#-- We assume that we have "HTML" output format by default. --> |
| <#assign captured><b>Test</b></#assign> |
| Just a string: ${"<b>Test</b>"} |
| Captured output: ${captured}</programlisting> |
| |
| <programlisting role="output">Just a string: &lt;b&gt;Test&lt;/b&gt; |
| Captured output: <b>Test</b></programlisting> |
| |
| <para>Because the captured output is markup output, it wasn't |
| auto-escaped.</para> |
| |
| <para>It's important that markup output values aren't strings, and |
| aren't automatically coerced to strings. Thus |
| <literal>?upper_case</literal>, <literal>?starts_with</literal> |
| etc., will give an error with them. You won't be able to pass them |
| to Java methods for <literal>String</literal> parameters either. But |
| sometimes you need the markup that's behind the value as a string, |
| which you can get as |
| <literal><replaceable>markupOutput</replaceable>?markup_string</literal>. |
| Be sure you know what you are doing though. Applying string |
| operations on markup (as opposed to on plain text) can result in |
| invalid markup. Also there's the danger of unintended double |
| escaping.</para> |
| |
| <programlisting role="template"><#-- We assume that we have "HTML" output format by default. --> |
| |
| <#assign markupOutput1="<b>Test</b>"?no_esc> |
| <#assign markupOutput2="Foo & bar"?esc> |
| |
| As expected: |
| ${markupOutput1} |
| ${markupOutput2} |
| |
| Possibly unintended double escaping: |
| ${markupOutput1?markup_string} |
| ${markupOutput2?markup_string}</programlisting> |
| |
| <programlisting role="output">As expected: |
| <b>Test</b> |
| Foo &amp; bar |
| |
| Possibly unintended double escaping: |
| &lt;b&gt;Test&lt;/b&gt; |
| Foo &amp;amp; bar</programlisting> |
| </section> |
| |
| <section> |
| <title>Further details and tricky cases</title> |
| |
| <section xml:id="dgui_misc_autoescaping_nonmarkupof"> |
| <title>Non-markup output formats</title> |
| |
| <para>An output format is said to be a non-markup format if it |
| defines no escaping rules. Examples of such output formats are the |
| <literal>undefined</literal> format and the |
| <literal>plainText</literal> format.</para> |
| |
| <para>These formats produce no <link |
| linkend="dgui_misc_autoescaping_movalues">markup output |
| values</link>, hence you can't use <literal>?esc</literal> or |
| <literal>?no_esc</literal> when they are the current format. You |
| can use output capturing (like <literal><#assign |
| captured><replaceable>...</replaceable></#assign></literal>), |
| but the resulting value will be a string, not a markup output |
| value.</para> |
| |
| <para>Furthermore, you aren't allowed to use the |
| <literal>autoesc</literal> directive or <literal><#ftl |
| auto_esc=true></literal> when the current output format is |
| non-markup.</para> |
| |
| <para>Using constructs that aren't supported by the current output |
| format will give <link linkend="gloss.parseTimeError">parse-time |
| error</link>.</para> |
| </section> |
| |
| <section xml:id="dgui_misc_autoescaping_mixingoutputformats"> |
| <title>Inserting markup output values from other markups</title> |
| |
| <para>Each <link linkend="dgui_misc_autoescaping_movalues">markup |
| output value</link> has an associated <link |
| linkend="dgui_misc_autoescaping_outputformat">output |
| format</link>. When a markup output value is inserted with |
| <literal>${<replaceable>...</replaceable>}</literal> (or |
| <literal>#{<replaceable>...</replaceable>}</literal>), it has to |
| be converted to the current output format at the point of |
| insertion (if they differ). As of this writing (2.3.24), such |
| output format conversion will only be successful if the value to |
| convert was created by escaping plain text:</para> |
| |
| <programlisting role="template"><#-- We assume that we have "HTML" output format by default. --> |
| |
| <#assign mo1 = "Foo's bar {}"?esc> |
| HTML: ${mo1} |
| XML: <#outputformat 'XML'>${mo1}</#outputformat> |
| RTF: <#outputformat 'RTF'>${mo1}</#outputformat> |
| |
| <#assign mo2><p>Test</#assign> |
| HTML: ${mo2} |
| XML: <#attempt><#outputformat 'XML'>${mo2}</#outputformat><#recover>Failed</#attempt> |
| RTF: <#attempt><#outputformat 'RTF'>${mo2}</#outputformat><#recover>Failed</#attempt></programlisting> |
| |
| <programlisting role="output">HTML: Foo&#39;s bar {} |
| XML: Foo&apos;s bar {} |
| RTF: Foo's bar \{\} |
| |
| HTML: <p>Test |
| XML: Failed |
| RTF: Failed</programlisting> |
| |
| <para>But, an output format can also chose to insert pieces of |
| other output formats as is, without converting them. Among the |
| standard output formats, <literal>undefined</literal> is like |
| that, which is the output format used for templates for which no |
| output format was specified in the configuration:</para> |
| |
| <programlisting role="template"><#-- We assume that we have "undefined" output format here. --> |
| |
| <#outputformat "HTML"><#assign htmlMO><p>Test</#assign></#outputformat> |
| <#outputformat "XML"><#assign xmlMO><p>Test</p></#assign></#outputformat> |
| <#outputformat "RTF"><#assign rtfMO>\par Test</#assign></#outputformat> |
| HTML: ${htmlMO} |
| XML: ${xmlMO} |
| RTF: ${rtfMO}</programlisting> |
| |
| <programlisting role="output">HTML: <p>Test |
| XML: <p>Test</p> |
| RTF: \par Test</programlisting> |
| </section> |
| |
| <section xml:id="dgui_misc_autoescaping_concatenation"> |
| <title>Markup output values and the <quote>+</quote> |
| operator</title> |
| |
| <para>As you certainly know, if one of the sides of the |
| <literal>+</literal> operator is a string then <link |
| linkend="dgui_template_exp_stringop_concatenation">it does |
| concatenation</link>. If there's a <link |
| linkend="dgui_misc_autoescaping_movalues">markup output |
| value</link> in one side, the other side gets promoted to markup |
| output value of the same output format (if it's not already that), |
| by escaping its string value, and finally the two markups are |
| concatenated to form a new markup output value. Example:</para> |
| |
| <programlisting role="template"><#-- We assume that we have "HTML" output format by default. --> |
| ${"<h1>"?no_esc + "Foo & bar" + "</h1>"?no_esc}</programlisting> |
| |
| <programlisting role="output"><h1>Foo &amp; bar</h1></programlisting> |
| |
| <para>If the two sides of the <literal>+</literal> operator are |
| markup values of different output formats, the right side operand |
| is converted to the output format of the left side. If that's not |
| possible, then the left side operand is converted to the output |
| format of the right side. If that isn't possible either, that's an |
| error. (See the <link |
| linkend="dgui_misc_autoescaping_mixingoutputformats">limitations |
| of conversions here</link>.)</para> |
| </section> |
| |
| <section xml:id="dgui_misc_autoescaping_stringliteral"> |
| <title>${...} inside string literals</title> |
| |
| <para>When <literal>${<replaceable>...</replaceable>}</literal> is |
| used inside string <emphasis>expressions</emphasis> (e.g., in |
| <literal><#assign s = "Hello ${name}!"></literal>), it's |
| just a shorthand of using the <literal>+</literal> operator |
| (<literal><#assign s = "Hello" + name + "!"></literal>). |
| Thus, <literal>${<replaceable>...</replaceable>}</literal>-s |
| inside string expressions aren't auto-escaped, but of course when |
| the resulting concatenated string is printed later, it will be |
| possibly auto-escaped.</para> |
| |
| <programlisting role="template"><#-- We assume that we have "HTML" output format by default. --> |
| <#assign name = "Foo & Bar"> |
| |
| <#assign s = "<p>Hello ${name}!"> |
| ${s} |
| <p>Hello ${name}! |
| |
| To prove that s didn't contain the value in escaped form: |
| ${s?replace('&'), 'and'}</programlisting> |
| |
| <programlisting role="output">&lt;p&gt;Hello Foo &amp; Bar! |
| <p>Hello Foo &amp; Bar! |
| |
| To prove that "s" didn't contain the value in escaped form: |
| &lt;p&gt;Hello Foo and Bar!</programlisting> |
| </section> |
| |
| <section> |
| <title>Combined output formats</title> |
| |
| <para>Combined output formats are output formats that are created |
| ad-hoc from other output formats by nesting them into each other, |
| so that the escaping of both output formats are applied. <link |
| linkend="topic.combinedOutputFormats">They are discussed |
| here...</link></para> |
| </section> |
| </section> |
| </section> |
| |
| <section xml:id="dgui_misc_computer_vs_human_format"> |
| <title>Formatting for humans, or for computers</title> |
| |
| <para>By default |
| <literal>${<replaceable>someValue</replaceable>}</literal> outputs |
| numbers, date/time/date-time and boolean values in a format that |
| targets normal users (<quote>humans</quote>). You have various |
| settings to specify how that format looks, like |
| <literal>number_format</literal>, <literal>date_format</literal>, |
| <literal>time_format</literal>, <literal>datetime_format</literal>, |
| <literal>boolan_format</literal>. The output also often depends on the |
| <literal>locale</literal> setting (i.e., on the language, and country |
| of the user). So 3000000 is possibly printed as |
| <literal>3,000,000</literal> (i.e., with grouping separators), or |
| <literal>3.14</literal> is possibly printed as <literal>3,14</literal> |
| (i.e., with a different decimal separator).</para> |
| |
| <para>At some places you need to output values that will be read |
| (parsed) by some program, in which case always use the <link |
| linkend="ref_builtin_c"><literal>c</literal> built-in</link>, as in |
| <literal>${<replaceable>someValue</replaceable>?c}</literal> (the |
| <quote>c</quote> stands for Computer). <emphasis>Then the formatting |
| depends on the <literal>c_format</literal> <link |
| linkend="pgui_config_settings">setting</link></emphasis>, which |
| usually refers to a computer language, like <literal>"JSON"</literal>. |
| The output of <literal>?c</literal> is not influenced by |
| <literal>locale</literal>, <literal>number_format</literal>, |
| etc.</para> |
| |
| <para>The <literal>c</literal> built-in will format string values to |
| string literals. Like if the <literal>c_format</literal> setting is |
| <literal>"JSON"</literal>, then <literal>{"fullName": |
| ${fullName?c}}</literal> will output something like |
| <literal>{"fullName": "John Doe"}</literal>, where the quotation marks |
| (and <literal>\</literal> escaping if needed) were added by |
| <literal>?c</literal>.</para> |
| |
| <note> |
| <para>At least as of 2.3.32, the <literal>c</literal> built-in |
| doesn't support date/time/datetime values, only numbers, booleans, |
| and strings.</para> |
| </note> |
| |
| <para>When formatting for computers, at some places you want to output |
| a <literal>null</literal> (or its equivalent in the target language) |
| if the value you print is missing/<literal>null</literal>. The |
| convenient shortcut for that is using the <literal>cn</literal> |
| built-in (the <quote>n</quote> stands for Nullable), as in |
| <literal>${<replaceable>someValue</replaceable>?cn}</literal>. It |
| behaves like the <literal>c</literal> built-in, except that if |
| <literal><replaceable>someValue</replaceable></literal> evaluates to |
| <literal>null</literal>/missing, it outputs the |
| <literal>null</literal> literal in the syntax that the |
| <literal>c_format</literal> setting specifies, instead of stopping |
| with missing value error.</para> |
| |
| <para>For the templates where the output is obviously only for |
| computer consumption, some prefers setting the |
| <literal>number_format</literal>, and |
| <literal>boolean_format</literal> settings to <literal>"c"</literal>. |
| (Before 2.3.32, for <literal>number_format</literal> you have to use |
| <literal>"computer"</literal> instead.) Then |
| <literal>${<replaceable>someValue</replaceable>}</literal>, for |
| number, and boolean values will format like <literal>?c</literal> |
| does. To output string literals (i.e, to add quotation and escaping), |
| you will still need an explicit <literal>?c</literal>. Also if you |
| need to output <literal>null</literal> literals, you still have to use |
| <literal>?cn</literal>.</para> |
| |
| <para>These are the table of supported <literal>c_format</literal> |
| setting values (as of FreeMarker 2.3.32), and their intended |
| use:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>"JSON"</literal>: JSON generation. Generally, |
| <literal>"JavaScript or JSON"</literal> (see later) is recommended |
| over this.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>"JavaScript"</literal>: JavaScript generation. |
| Generally, <literal>"JavaScript or JSON"</literal> (see later) is |
| recommended over this.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>"Java"</literal>: Java source code |
| generation</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>"XS"</literal>: XML Schema compliant XML |
| generation</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>"JavaScript or JSON"</literal>: For generating |
| output that's compatible with both JSON and JavaScript. This setup |
| is therefore resilient against configuration mistakes, where we |
| generate output in one language, but use the |
| <literal>c_format</literal> for the other. The small price to pay |
| is that we can't utilize some language-specific opportunities to |
| make the output a bit shorter, but that hardly matters in |
| practice. This is the default if if the <link |
| linkend="pgui_config_incompatible_improvements"><literal>incompatible_improvements</literal> |
| setting</link> is at least 2.3.32.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>"legacy"</literal>: Default for backward |
| compatibility when the <link |
| linkend="pgui_config_incompatible_improvements"><literal>incompatible_improvements</literal> |
| setting</link> is less than 2.3.32. Avoid! Can have rounding |
| losses, and formatting glitches for infinity and NaN.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>The behaviour of these is documented at the <literal>c</literal> |
| built-in: <link linkend="ref_builtin_c">for numbers</link>, <link |
| linkend="ref_builtin_c_boolean">for boolean</link>, <link |
| linkend="ref_builtin_c_string">for strings</link>, <link |
| linkend="ref_builtin_cn">for null-s</link>.</para> |
| </section> |
| |
| <section xml:id="dgui_misc_whitespace"> |
| <title>White-space handling</title> |
| |
| <indexterm> |
| <primary>white-space removal</primary> |
| </indexterm> |
| |
| <para>The control of the <link |
| linkend="gloss.whiteSpace">white-space</link> in a template is a |
| problem that to some extent haunts every template engine in the |
| business.</para> |
| |
| <para>Let see this template. I have marked the components of template |
| with colors: <phrase role="markedText">text</phrase>, <phrase |
| role="markedInterpolation">interpolation</phrase>, <phrase |
| role="markedFTLTag">FTL tag</phrase>. With the <phrase |
| role="markedInvisibleText">[BR]</phrase>-s I visualize the <link |
| linkend="gloss.lineBreak">line breaks</link>.</para> |
| |
| <programlisting role="template"><phrase role="markedText"><p>List of users:<phrase |
| role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedFTLTag"><#assign users = [{"name":"Joe", "hidden":false},<phrase |
| role="markedInvisibleText">[BR]</phrase> |
| {"name":"James Bond", "hidden":true},<phrase |
| role="markedInvisibleText">[BR]</phrase> |
| {"name":"Julia", "hidden":false}]></phrase><phrase |
| role="markedInvisibleText">[BR]</phrase> |
| <ul><phrase role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedFTLTag"><#list users as user></phrase><phrase |
| role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedFTLTag"><#if !user.hidden></phrase><phrase |
| role="markedInvisibleText">[BR]</phrase> |
| <li><phrase role="markedInterpolation">${user.name}</phrase><phrase |
| role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedFTLTag"></#if></phrase><phrase |
| role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedFTLTag"></#list></phrase><phrase |
| role="markedInvisibleText">[BR]</phrase> |
| </ul><phrase role="markedInvisibleText">[BR]</phrase> |
| <p>That's all.</phrase></programlisting> |
| |
| <para>If FreeMarker were to output all <phrase |
| role="markedText">text</phrase> as is, the output would be:</para> |
| |
| <programlisting role="output"><phrase role="markedText"><p>List of users:<phrase |
| role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedInvisibleText">[BR]</phrase> |
| <ul><phrase role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedInvisibleText">[BR]</phrase> |
| <li></phrase>Joe<phrase role="markedText"><phrase |
| role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedInvisibleText">[BR]</phrase> |
| <li></phrase>Julia<phrase role="markedText"><phrase |
| role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedInvisibleText">[BR]</phrase> |
| </ul><phrase role="markedInvisibleText">[BR]</phrase> |
| <p>That's all.</phrase></programlisting> |
| |
| <para>You have a lot of unwanted spaces and line breaks here. |
| Fortunately neither HTML nor XML is typically white-space sensitive, |
| but this amount of superfluous white-space can be annoying, and |
| needlessly increases the size of produced HTML. Of course, it is even |
| bigger problem when outputting white-space-sensitive formats.</para> |
| |
| <para>FreeMarker provides the following tools to cope with this |
| problem:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Tools to ignore certain white-space of the template files |
| <phrase role="forProgrammers">(parse time white-space |
| removal)</phrase>:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>White-space stripping: This feature automatically |
| ignores typical superfluous white-space around FTL tags. It |
| can be enabled or disabled on per template manner.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Trimmer directives: <literal>t</literal>, |
| <literal>rt</literal>, <literal>lt</literal>. With these |
| directives you can explicitly tell FreeMarker to ignore |
| certain white-space. Read <link linkend="ref.directive.t">the |
| reference</link> for more information.</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref.directive.ftl"><literal>ftl</literal></link> |
| parameter <literal>strip_text</literal>: This removes all |
| top-level text from the template. It is useful for templates |
| that contain macro definitions only (and some other |
| non-outputting directives), because it removes the line-breaks |
| that you use between the macro definitions and between the |
| other top-level directives to improve the readability of the |
| template.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Tools that remove white-space from the output <phrase |
| role="forProgrammers">(on-the-fly white-space |
| removal)</phrase>:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>compress</literal> directive.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| </itemizedlist> |
| |
| <section xml:id="dgui_misc_whitespace_stripping"> |
| <title>White-space stripping</title> |
| |
| <indexterm> |
| <primary>white-space removal</primary> |
| |
| <secondary>stripping</secondary> |
| </indexterm> |
| |
| <para>If this feature is enabled for a template, then it |
| automatically ignores (i.e. does not print to the output) two kind |
| of typical superfluous white-space:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Indentation white-space, and trailing white-space at the |
| end of the line (includes the line break) will be ignored in |
| lines that contains only FTL tags (e.g. |
| <literal><@myMacro/></literal>, <literal><#if |
| <replaceable>...</replaceable>></literal>) and/or FTL |
| comments (e.g. <literal><#-- blah --></literal>), apart |
| from the the ignored white-space itself. For example, if a line |
| contains only an <literal><#if |
| <replaceable>...</replaceable>></literal>, then the |
| indentation before the tag and the line break after the tag will |
| be ignored. However, if the line contains <literal><#if |
| <replaceable>...</replaceable>>x</literal>, then the |
| white-space in that line will not be ignored, because of the |
| <literal>x</literal>, as that is not FTL tag. Note that |
| according these rules, a line that contains <literal><#if |
| <replaceable>...</replaceable>><#list |
| <replaceable>...</replaceable>></literal> is subject to |
| white-space ignoring, while a line that contains |
| <literal><#if <replaceable>...</replaceable>>Â <#list |
| <replaceable>...</replaceable>></literal> is not, because the |
| white-space between the two FTL tags is embedded white-space, |
| not indentation or trailing white-space.</para> |
| </listitem> |
| |
| <listitem> |
| <para>White-space sandwiched between the following directives is |
| ignored: <literal>macro</literal>, <literal>function</literal>, |
| <literal>assign</literal>, <literal>global</literal>, |
| <literal>local</literal>, <literal>ftl</literal>, |
| <literal>import</literal>, but only if there is |
| <emphasis>only</emphasis> white-space and/or FTL comments |
| between the directives. In practice it means that you can put |
| empty lines between macro definitions and assignments as spacing |
| for better readability, without printing needless empty lines |
| (line breaks) to the output.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>The output of the last example with white-space stripping |
| enabled will be:</para> |
| |
| <programlisting role="output"><phrase role="markedText"><p>List of users:<phrase |
| role="markedInvisibleText">[BR]</phrase> |
| <ul><phrase role="markedInvisibleText">[BR]</phrase> |
| <li></phrase>Joe<phrase role="markedText"><phrase |
| role="markedInvisibleText">[BR]</phrase> |
| <li></phrase>Julia<phrase role="markedText"><phrase |
| role="markedInvisibleText">[BR]</phrase> |
| </ul><phrase role="markedInvisibleText">[BR]</phrase> |
| <p>That's all.</phrase></programlisting> |
| |
| <para>This is because after stripping the template becomes the |
| following; the ignored text is not <phrase |
| role="markedText">colored</phrase>:</para> |
| |
| <programlisting role="template"><phrase role="markedText"><p>List of users:<phrase |
| role="markedInvisibleText">[BR]</phrase></phrase> |
| <phrase role="markedFTLTag"><#assign users = [{"name":"Joe", "hidden":false},<phrase |
| role="markedInvisibleText">[BR]</phrase> |
| {"name":"James Bond", "hidden":true},<phrase |
| role="markedInvisibleText">[BR]</phrase> |
| {"name":"Julia", "hidden":false}]></phrase><phrase |
| role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedText"><ul><phrase role="markedInvisibleText">[BR]</phrase></phrase> |
| <phrase role="markedFTLTag"><#list users as user></phrase><phrase |
| role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedFTLTag"><#if !user.hidden></phrase><phrase |
| role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedText"> <li><phrase role="markedInterpolation">${user.name}</phrase><phrase |
| role="markedInvisibleText">[BR]</phrase></phrase> |
| <phrase role="markedFTLTag"></#if></phrase><phrase |
| role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedFTLTag"></#list></phrase><phrase |
| role="markedInvisibleText">[BR]</phrase> |
| <phrase role="markedText"></ul><phrase role="markedInvisibleText">[BR]</phrase> |
| <p>That's all.</phrase></programlisting> |
| |
| <para>White-space stripping can be enabled/disabled in per template |
| manner with the <link |
| linkend="ref.directive.ftl"><literal>ftl</literal> directive</link>. |
| If you don't specify this with the <literal>ftl</literal> directive, |
| then white-space stripping will be enabled or disabled depending on |
| how the programmer has configured FreeMarker. The factory default is |
| white-space stripping enabled, and the programmers probably left it |
| so (<phrase role="forProgrammers">recommended</phrase>). <phrase |
| role="forProgrammers">Note that enabling white-space stripping does |
| <emphasis>not</emphasis> degrade the performance of template |
| execution; white-space stripping is done during template |
| loading.</phrase></para> |
| |
| <para>White-space stripping can be disabled for a single line with |
| the <link linkend="ref.directive.nt"><literal>nt</literal></link> |
| directive (for No Trim).</para> |
| </section> |
| |
| <section> |
| <title>Using compress directive</title> |
| |
| <indexterm> |
| <primary>white-space removal</primary> |
| |
| <secondary>compress</secondary> |
| </indexterm> |
| |
| <para>Another solution is to use the <link |
| linkend="ref.directive.compress"><literal>compress</literal> |
| directive</link>. As opposed to white-space stripping, this works |
| directly on the generated output, not on the template. That is, it |
| will investigate the printed output on the fly, and does not |
| investigate the FTL program that creates the output. It aggressively |
| removes indentations, empty lines and repeated spaces/tabs (for more |
| information read the <link |
| linkend="ref.directive.compress">reference</link>). So the output |
| of:</para> |
| |
| <programlisting role="template"><emphasis><#compress></emphasis> |
| <#assign users = [{"name":"Joe", "hidden":false}, |
| {"name":"James Bond", "hidden":true}, |
| {"name":"Julia", "hidden":false}]> |
| List of users: |
| <#list users as user> |
| <#if !user.hidden> |
| - ${user.name} |
| </#if> |
| </#list> |
| That's all. |
| <emphasis></#compress></emphasis></programlisting> |
| |
| <para>will be:</para> |
| |
| <programlisting role="output">List of users: |
| - Joe |
| - Julia |
| That's all.</programlisting> |
| |
| <para>Note that <literal>compress</literal> is totally independent |
| of white-space stripping. So it is possible that the white-space of |
| template is stripped, and later the produced output is |
| <literal>compress</literal>-ed.</para> |
| |
| <para>Also, by default a user-defined directve called |
| <literal>compress</literal> is available in the data-model (due to |
| backward compatibility). This is the same as the directive, except |
| that you may optionally set the <literal>single_line</literal> |
| parameter, which will remove all intervening line breaks. If you |
| replace |
| <literal><#compress><replaceable>...</replaceable></#compress></literal> |
| on the last example with <literal><@compress |
| single_line=true><replaceable>...</replaceable></@compress></literal>, |
| then you get this output:</para> |
| |
| <programlisting role="output">List of users: - Joe - Julia That's all.</programlisting> |
| </section> |
| </section> |
| |
| <section xml:id="dgui_misc_alternativesyntax"> |
| <title>Alternative (square bracket) syntax</title> |
| |
| <indexterm> |
| <primary>alternative syntax</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>square bracket syntax</primary> |
| </indexterm> |
| |
| <para>Sometimes the generated content uses symbols that clashes with |
| the default FreeMarker syntax (typically, |
| <literal>${<replaceable>...</replaceable>}</literal>-s that FreeMarker |
| should print as is, without interpretation), or you use some tool that |
| is confused by the default FreeMarker syntax (typically by |
| <literal><</literal> and <literal>></literal>). While usually |
| there are tricks to work those cases around (like you can use |
| <literal>${'$'}{x}</literal> to print <literal>${x}</literal> as is) , |
| they are often too inconvenient. Thus, the interpolation syntax can be |
| configured to be like <literal>[=x]</literal> instead of |
| <literal>${x}</literal>. Also, independently of that, the FreeMarker |
| tag syntax can be configured to use <literal>[]</literal>, like in |
| <literal>[#if x]<replaceable>...</replaceable>[/#if]</literal>.</para> |
| |
| <note> |
| <para>While both the <quote>tag syntax</quote> and |
| <quote>interpolation syntax</quote> can be configured to use square |
| brackets, they are totally independent configuration settings. Thus, |
| the overall syntax can be like <literal>[#if x]${y}[/#if]</literal>, |
| or like <literal><#if x>[=y]</#if></literal> as |
| well.</para> |
| </note> |
| |
| <section xml:id="dgui_misc_alternativesyntax_tag"> |
| <title>Square bracket tag syntax</title> |
| |
| <note> |
| <para>This section is about the <emphasis>tag</emphasis> syntax, |
| not the <link |
| linkend="dgui_misc_alternativesyntax_interpolation"><emphasis>interpolation</emphasis> |
| syntax</link>. Don't confuse the two, they are independent.</para> |
| </note> |
| |
| <note> |
| <para>This feature exists since FreeMarker 2.3.4.</para> |
| </note> |
| |
| <para>FreeMarker supports an alternative tag syntax, where |
| <literal>[</literal> and <literal>]</literal> is used instead of |
| <literal><</literal> and <literal>></literal> in FreeMarker |
| directives and comments, for example:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>Calling predefined directive: <literal>[#list animals as |
| animal]<replaceable>...</replaceable>[/#list]</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Calling user-defined directive: <literal>[@myMacro |
| /]</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Comment: <literal>[#-- the comment --]</literal></para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>To use square tag syntax instead of the default one, the |
| programmers should configure FreeMarker so <phrase |
| role="forProgrammers">(see |
| <literal>Configuraton.setTagSyntax</literal>, or the |
| <literal>tag_syntax</literal> setting)</phrase>. However, the tag |
| syntax can also be enforced in the template, with the <link |
| linkend="ref_directive_ftl"><literal>ftl</literal> directive</link> |
| (see later).</para> |
| |
| <para>For example, this is how the last example of the <link |
| linkend="dgui_quickstart_template">Getting Started</link> looks with |
| the alternative syntax:</para> |
| |
| <programlisting role="template"><p>We have these animals: |
| <table border=1> |
| <tr><th>Name<th>Price |
| <emphasis>[#list animals as animal]</emphasis> |
| <tr> |
| <td> |
| <emphasis>[#if animal.size == "large"]</emphasis><b><emphasis>[/#if]</emphasis> |
| ${animal.name} |
| <emphasis>[#if animal.size == "large"]</emphasis></b><emphasis>[/#if]</emphasis> |
| <td>${animal.price} Euros |
| <emphasis>[/#list]</emphasis> |
| </table></programlisting> |
| |
| <para>The square bracket and the default (angle bracket) syntax are |
| mutually exclusive within a template; they can't be mixed. If the |
| template uses square bracket tag syntax, then things like |
| <literal><#if <replaceable>...</replaceable>></literal> will |
| be just static text, not FTL tags. Similarly, if the template uses |
| the angle brackets tag syntax, things like <literal>[#if |
| <replaceable>...</replaceable>]</literal> are static text, not FTL |
| tags.</para> |
| |
| <para>If you start the file with <literal>[#ftl |
| <replaceable>...</replaceable>]</literal> (where the |
| <literal><replaceable>...</replaceable></literal> stands for the |
| optional parameters; of course <literal>[#ftl]</literal> works too) |
| the file will use square bracket <emphasis>tag</emphasis> syntax |
| regardless of the configuration settings (but that does |
| <emphasis>not</emphasis> change the interpolation syntax to |
| <literal>[=...]</literal>). Similarly, if you start the file with |
| <literal><#ftl <replaceable>...</replaceable>></literal> the |
| file will use the normal (angle bracket) tag syntax. If there is no |
| <literal>ftl</literal> directive in the file, then the programmer |
| decides what the tag <emphasis>syntax</emphasis> will be by |
| configuring FreeMarker <phrase role="forProgrammers">(programmers |
| see <literal>Configuration.setTagSyntax(int)</literal> in the API |
| javadocs)</phrase>. Most probably the programmers use the factory |
| default.</para> |
| </section> |
| |
| <section xml:id="dgui_misc_alternativesyntax_interpolation"> |
| <title>Square bracket interpolation syntax</title> |
| |
| <note> |
| <para>This section is about the <emphasis>interpolation</emphasis> |
| syntax, not the <link |
| linkend="dgui_misc_alternativesyntax_tag"><emphasis>tag</emphasis> |
| syntax</link>. Don't confuse the two, they are independent.</para> |
| </note> |
| |
| <note> |
| <para>This feature exists since FreeMarker 2.3.28</para> |
| </note> |
| |
| <para>In this case instead of |
| <literal>${<replaceable>expression</replaceable>}</literal> (and the |
| deprecated |
| <literal>#{<replaceable>expression</replaceable>}</literal>) you |
| write <literal>[=<replaceable>expression</replaceable>]</literal>. |
| This syntax is activated by the programmers from the configuration |
| <phrase role="forProgrammers">(see |
| <literal>Configuration.setInterpolationSyntax</literal> in the Java |
| API)</phrase>; unlike the tag syntax, it can't be specified inside |
| the template. It can be used both together with, and without the |
| <link linkend="dgui_misc_alternativesyntax_tag">square bracket |
| <emphasis>tag</emphasis> syntax</link>, as they are technically |
| unrelated, but it's probably more aesthetic to use square bracket |
| tag syntax when you use square bracket interpolation syntax:</para> |
| |
| <programlisting role="template">[#-- |
| Note: |
| This example uses both interpolation_syntax=squareBracket and tag_syntax=squareBracket, |
| but you can also use interpolation_syntax=squareBracket and tag_syntax=angleBracket. |
| --] |
| <p>We have these animals: |
| <table border=1> |
| <tr><th>Name<th>Price |
| [#list animals as animal] |
| <tr> |
| <td> |
| [#if animal.size == "large"]<b>[/#if] |
| <emphasis>[=animal.name]</emphasis> |
| [#if animal.size == "large"]</b>[/#if] |
| <td><emphasis>[=animal.price]</emphasis> Euros |
| [/#list] |
| </table></programlisting> |
| |
| <para>When square bracket interpolation syntax is used, |
| <literal>${<replaceable>expression</replaceable>}</literal> and |
| <literal>#{<replaceable>expression</replaceable>}</literal> in the |
| template will be just static text, which is printed as is. This is |
| mostly useful if you generate output that should contain those |
| (especially |
| <literal>${<replaceable>expression</replaceable>}</literal> is |
| frequent), such as when generating JSP files.</para> |
| |
| <para>There's also a third tag syntax, <quote>dollar</quote>, where |
| only the interpolation syntax is |
| <literal>${<replaceable>expression</replaceable>}</literal>, and the |
| deprecated |
| <literal>#{<replaceable>expression</replaceable>}</literal> is just |
| static text. (The one where |
| <literal>#{<replaceable>expression</replaceable>}</literal> is still |
| an interpolation is called the <quote>legacy</quote> interpolation |
| syntax, and is the default for backward compatibility.)</para> |
| </section> |
| </section> |
| </chapter> |
| </part> |
| |
| <part xml:id="pgui"> |
| <title>Programmer's Guide</title> |
| |
| <chapter xml:id="pgui_quickstart"> |
| <title>Getting Started</title> |
| |
| <para>If you are new to FreeMarker, you should read at least the <xref |
| linkend="dgui_quickstart_basics"/> before this chapter.</para> |
| |
| <section xml:id="pgui_quickstart_createconfiguration"> |
| <title>Create a configuration instance</title> |
| |
| <indexterm> |
| <primary>configuration</primary> |
| </indexterm> |
| |
| <para>First you have to create a |
| <literal>freemarker.template.Configuration</literal> instance and |
| adjust its settings. A <literal>Configuration</literal> instance is |
| the central place to store the application level settings of |
| FreeMarker. Also, it deals with the creation and |
| <emphasis>caching</emphasis> of pre-parsed templates (i.e., |
| <literal>Template</literal> objects).</para> |
| |
| <para>Normally you will <emphasis>do this only once</emphasis> at the |
| beginning of the application (possibly servlet) life-cycle:</para> |
| |
| <programlisting role="unspecified">// Create your Configuration instance, and specify if up to what FreeMarker |
| // version (here 2.3.32) do you want to apply the fixes that are not 100% |
| // backward-compatible. See the Configuration JavaDoc for details. |
| Configuration cfg = new Configuration(Configuration.VERSION_2_3_33); |
| |
| // Specify the source where the template files come from. Here I set a |
| // plain directory for it, but non-file-system sources are possible too: |
| cfg.setDirectoryForTemplateLoading(new File("<replaceable>/where/you/store/templates</replaceable>")); |
| |
| // From here we will set the settings recommended for new projects. These |
| // aren't the defaults for backward compatibilty. |
| |
| // Set the preferred charset template files are stored in. UTF-8 is |
| // a good choice in most applications: |
| cfg.setDefaultEncoding("UTF-8"); |
| |
| // Sets how errors will appear. |
| // During web page *development* TemplateExceptionHandler.HTML_DEBUG_HANDLER is better. |
| cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); |
| |
| // Don't log exceptions inside FreeMarker that it will thrown at you anyway: |
| cfg.setLogTemplateExceptions(false); |
| |
| // Wrap unchecked exceptions thrown during template processing into TemplateException-s: |
| cfg.setWrapUncheckedExceptions(true); |
| |
| // Do not fall back to higher scopes when reading a null loop variable: |
| cfg.setFallbackOnNullLoopVariable(false); |
| |
| // To accomodate to how JDBC returns values; see Javadoc! |
| cfg.setSQLDateAndTimeTimeZone(TimeZone.getDefault());</programlisting> |
| |
| <para>From now you should use this <emphasis>single</emphasis> |
| configuration instance (i.e., its a singleton). Note however that if a |
| system has multiple independent components that use FreeMarker, then |
| of course they will use their own private |
| <literal>Configuration</literal> instances.</para> |
| |
| <warning> |
| <para>Do not needlessly re-create <literal>Configuration</literal> |
| instances; it's expensive, among others because you lose the |
| template cache. <literal>Configuration</literal> instances meant to |
| be application-level singletons.</para> |
| </warning> |
| |
| <para>In multi-threaded applications (like Web sites) the settings in |
| the <literal>Configuration</literal> instance must not be modified |
| anymore after this point. Thus it can be treated as <quote>effectively |
| immutable</quote> object, so you can continue with <emphasis>safe |
| publishing</emphasis> techniques (see JSR 133 and related literature) |
| to make the instance available for other threads. Like, publish the |
| instance through a final or volatile filed, or through a thread-safe |
| IoC container (like the one provided by Spring). |
| <literal>Configuration</literal> methods that don't deal with |
| modifying settings are thread-safe.</para> |
| </section> |
| |
| <section xml:id="pgui_quickstart_createdatamodel"> |
| <title>Create a data-model</title> |
| |
| <indexterm> |
| <primary>data-model</primary> |
| |
| <secondary>assembling with Java</secondary> |
| </indexterm> |
| |
| <para>In simple cases you can build data-models using |
| <literal>java.lang</literal> and <literal>java.util</literal> classes |
| and custom JavaBeans:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Use <literal>java.lang.String</literal> for strings.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Use <literal>java.lang.Number</literal> subclasses for |
| numbers.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Use <literal>java.lang.Boolean</literal> for boolean |
| values.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Use <literal>java.util.Date</literal> and its subclasses for |
| date/time values</para> |
| </listitem> |
| |
| <listitem> |
| <para>Use <literal>java.util.List</literal> or Java arrays for |
| sequences.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Use <literal>java.util.Map</literal> with |
| <literal>String</literal> keys for hashes.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Use your custom bean class for hashes where the items |
| correspond to the bean properties. For example the |
| <literal>price</literal> property (<literal>getPrice()</literal>) |
| of <literal>product</literal> can be get as |
| <literal>product.price</literal>. (The actions of the beans can be |
| exposed as well; see much later <link |
| linkend="pgui_misc_beanwrapper">here</link>)</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>For example, let's build the data-model of the <link |
| linkend="example.first">first example of the Template Author's |
| Guide</link>. For convenience, here it is again:</para> |
| |
| <programlisting role="dataModel">(root) |
| | |
| +- user = "Big Joe" |
| | |
| +- latestProduct |
| | |
| +- url = "products/greenmouse.html" |
| | |
| +- name = "green mouse"</programlisting> |
| |
| <para>This Java code fragment that builds this data-model:</para> |
| |
| <programlisting role="unspecified">// Create the root hash. We use a Map here, but it could be a JavaBean too. |
| Map<String, Object> root = new HashMap<>(); |
| |
| // Put string "user" into the root |
| root.put("user", "Big Joe"); |
| |
| // Create the "latestProduct" hash. We use a JavaBean here, but it could be a Map too. |
| Product latest = new Product(); |
| latest.setUrl("products/greenmouse.html"); |
| latest.setName("green mouse"); |
| // and put it into the root |
| root.put("latestProduct", latest); |
| </programlisting> |
| |
| <para>As demonstrated above, for hashes (something that stores other |
| named items) you can use either a <literal>Map</literal> or any kind |
| of public class that has public |
| <literal>get<replaceable>Xxx</replaceable></literal>/<literal>is<replaceable>Xxx</replaceable></literal> |
| methods as prescribed by the JavaBeans specification. Like the above |
| <literal>Product</literal> class could be something like:</para> |
| |
| <programlisting role="unspecified">/** |
| * Product bean; note that it must be a public class! |
| */ |
| public class Product { |
| |
| private String url; |
| private String name; |
| |
| // As per the JavaBeans spec., this defines the "url" bean property |
| // It must be public! |
| public String getUrl() { |
| return url; |
| } |
| |
| public void setUrl(String url) { |
| this.url = url; |
| } |
| |
| // As per the JavaBean spec., this defines the "name" bean property |
| // It must be public! |
| public String getName() { |
| return name; |
| } |
| |
| public void setName(String name) { |
| this.name = name; |
| } |
| |
| }</programlisting> |
| |
| <para>Regardless if <literal>latestProduct</literal> is a |
| <literal>Map</literal> that contains the <literal>"name"</literal> and |
| <literal>"url"</literal> keys, or it's a JavaBean as shown above, in |
| the template you can use <literal>${latestProduct.name}</literal>. The |
| root itself need not be a <literal>Map</literal> either; it could be |
| an object with <literal>getUser()</literal> and |
| <literal>getLastestProduct()</literal> methods too.</para> |
| |
| <note> |
| <para>The behavior described here only stands if the value of the |
| <literal>object_wrapper</literal> configuration setting is something |
| that's used in almost all real world setups anyway. Anything that |
| the <literal>ObjectWrapper</literal> wraps to be a hash (something |
| that implements the <literal>TemplateHashModel</literal> interface) |
| can be used as the root, and can be traversed in templates with the |
| dot and <literal>[]</literal> operators. Something that it doesn't |
| wrap to be a hash can't be used as the root or be traversed like |
| that.</para> |
| </note> |
| </section> |
| |
| <section xml:id="pgui_quickstart_gettemplate"> |
| <title>Get the template</title> |
| |
| <indexterm> |
| <primary>template</primary> |
| |
| <secondary>Java side</secondary> |
| </indexterm> |
| |
| <para>Templates are represented by |
| <literal>freemarker.template.Template</literal> instances. Typically |
| you obtain a <literal>Template</literal> instance from the |
| <literal>Configuration</literal> instance, using its. |
| <literal>getTemplate</literal> method. If you store <link |
| linkend="example.first">the example template</link> in the |
| <literal>test.ftlh</literal> file of the <link |
| linkend="pgui_quickstart_createconfiguration">earlier</link> set |
| directory, then you can do this:</para> |
| |
| <programlisting role="unspecified">Template temp = cfg.getTemplate("test.ftlh");</programlisting> |
| |
| <para>This gives you a <literal>Template</literal> instance that was |
| created by reading |
| <literal><replaceable>/where/you/store/templates/</replaceable>test.ftlh</literal> |
| and parsing it. The <literal>Template</literal> instance stores the |
| template in parsed form, and not as text. If the template is missing |
| or syntactically incorrect, <literal>getTemplate</literal> will throw |
| exception instead.</para> |
| |
| <para><literal>Configuration</literal> caches |
| <literal>Template</literal> instances, so when you call |
| <literal>cfg.getTemplate("test.ftlh")</literal> next time, it probably |
| won't read and parse the template file again, just returns the same |
| <literal>Template</literal> instance as for the first time.</para> |
| </section> |
| |
| <section xml:id="pgui_quickstart_merge"> |
| <title>Merging the template with the data-model</title> |
| |
| <indexterm> |
| <primary>output</primary> |
| |
| <secondary>generate with Java</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>merging</primary> |
| </indexterm> |
| |
| <para>As you might already know, data-model + template = output. We |
| already have a data-model (<literal>root</literal>) and a template |
| (<literal>temp</literal>), so to get the output we have to merge them. |
| This is done by the <literal>process</literal> method of the template. |
| It takes the data-model root and a <literal>Writer</literal> as |
| parameters. It writes the produced output to the |
| <literal>Writer</literal>. For the sake of simplicity here I write to |
| the standard output:</para> |
| |
| <programlisting role="unspecified">Writer out = new OutputStreamWriter(System.out); |
| temp.process(root, out);</programlisting> |
| |
| <para>This will print to your terminal the output you have seen in the |
| <link linkend="example.first">first example</link> of the Template |
| Author's Guide.</para> |
| |
| <para>Java I/O related notes: Depending on what <literal>out</literal> |
| is, you may need to ensure that <literal>out.close()</literal> is |
| called. This is typically needed when <literal>out</literal> writes |
| into a file that was opened to store the output of the template. In |
| other times, like in typical Web applications, you must |
| <emphasis>not</emphasis> close <literal>out</literal>. FreeMarker |
| calls <literal>out.flush()</literal> after a successful template |
| execution (but tis can be disabled in |
| <literal>Configuration</literal>), so you don't need to worry about |
| that.</para> |
| |
| <para>Note that once you have obtained a <literal>Template</literal> |
| instance, you can merge it with different data-models for unlimited |
| times (<literal>Template</literal> instances are stateless). Also, the |
| <literal>test.ftlh</literal> file is accessed only while the |
| <literal>Template</literal> instance is created, not when you call the |
| process method.</para> |
| </section> |
| |
| <section xml:id="pgui_quickstart_all"> |
| <title>Putting all together</title> |
| |
| <para>This is a working source file assembled from the previous |
| fragments. Don't forget to put <literal>freemarker.jar</literal> into |
| the <literal>CLASSPATH</literal>.</para> |
| |
| <programlisting role="unspecified">import freemarker.template.*; |
| import java.util.*; |
| import java.io.*; |
| |
| public class Test { |
| |
| public static void main(String[] args) throws Exception { |
| |
| /* ------------------------------------------------------------------------ */ |
| /* You should do this ONLY ONCE in the whole application life-cycle: */ |
| |
| /* Create and adjust the configuration singleton */ |
| Configuration cfg = new Configuration(Configuration.VERSION_2_3_33); |
| cfg.setDirectoryForTemplateLoading(new File("<replaceable>/where/you/store/templates</replaceable>")); |
| // Recommended settings for new projects: |
| cfg.setDefaultEncoding("UTF-8"); |
| cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); |
| cfg.setLogTemplateExceptions(false); |
| cfg.setWrapUncheckedExceptions(true); |
| cfg.setFallbackOnNullLoopVariable(false); |
| cfg.setSQLDateAndTimeTimeZone(TimeZone.getDefault()); |
| |
| /* ------------------------------------------------------------------------ */ |
| /* You usually do these for MULTIPLE TIMES in the application life-cycle: */ |
| |
| /* Create a data-model */ |
| Map root = new HashMap(); |
| root.put("user", "Big Joe"); |
| Product latest = new Product(); |
| latest.setUrl("products/greenmouse.html"); |
| latest.setName("green mouse"); |
| root.put("latestProduct", latest); |
| |
| /* Get the template (uses cache internally) */ |
| Template temp = cfg.getTemplate("test.ftlh"); |
| |
| /* Merge data-model with template */ |
| Writer out = new OutputStreamWriter(System.out); |
| temp.process(root, out); |
| // Note: Depending on what `out` is, you may need to call `out.close()`. |
| // This is usually the case for file output, but not for servlet output. |
| } |
| }</programlisting> |
| |
| <note> |
| <para>I have suppressed the exceptions for the sake of simplicity. |
| Don't do it in real products.</para> |
| </note> |
| |
| <para>For the sake completeness, here's the the Product class used in |
| the data model:</para> |
| |
| <programlisting role="unspecified">/** |
| * Product bean; note that it must be a public class! |
| */ |
| public class Product { |
| |
| private String url; |
| private String name; |
| |
| // As per the JavaBeans spec., this defines the "url" bean property |
| // It must be public! |
| public String getUrl() { |
| return url; |
| } |
| |
| public void setUrl(String url) { |
| this.url = url; |
| } |
| |
| // As per the JavaBean spec., this defines the "name" bean property |
| // It must be public! |
| public String getName() { |
| return name; |
| } |
| |
| public void setName(String name) { |
| this.name = name; |
| } |
| |
| }</programlisting> |
| |
| <para>and the template:</para> |
| |
| <programlisting role="template"><html> |
| <head> |
| <title>Welcome!</title> |
| </head> |
| <body> |
| <h1>Welcome ${user}!</h1> |
| <p>Our latest product: |
| <a href="${latestProduct.url}">${latestProduct.name}</a>! |
| </body> |
| </html></programlisting> |
| </section> |
| </chapter> |
| |
| <chapter xml:id="pgui_datamodel"> |
| <title>The Data Model</title> |
| |
| <para>This is just an introductory explanation. See the <olink |
| targetdoc="api">FreeMarker Java API documentation</olink> for more |
| detailed information.</para> |
| |
| <section xml:id="pgui_datamodel_basics"> |
| <title>Basics</title> |
| |
| <indexterm> |
| <primary>object wrapper</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>wrapper</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>data-model</primary> |
| |
| <secondary>assembling with Java, without object wrapper</secondary> |
| </indexterm> |
| |
| <para>You have seen how to build a data-model in the <link |
| linkend="pgui_quickstart">Getting Started</link> using the standard |
| Java classes (<literal>Map</literal>, <literal>String</literal>, |
| etc.). Internally, the variables available in the template are Java |
| objects that implement the |
| <literal>freemarker.template.TemplateModel</literal> interface. But |
| you could use standard Java collections as variables in your |
| data-model, because these were replaced with the appropriate |
| <literal>TemplateModel</literal> instances behind the scenes. This |
| facility is called <emphasis role="term">object wrapping</emphasis>. |
| The object wrapping facility can convert <emphasis>any</emphasis> kind |
| of object transparently to the instances of classes that implement |
| <literal>TemplateModel</literal> interface. This makes it possible, |
| for example, to access <literal>java.sql.ResultSet</literal> as |
| sequence variable in templates, or to access |
| <literal>javax.servlet.ServletRequest</literal> objects as a hash |
| variable that contains the request attributes, or even to traverse XML |
| documents as FTL variables (<link linkend="xgui">see here</link>). To |
| wrap (convert) these objects, however, you need to plug the proper |
| <literal>ObjectWrapper</literal> implementation (possibly your custom |
| implementation); this will be discussed <link |
| linkend="pgui_datamodel_objectWrapper">later</link>. The point for now |
| is that any object that you want to access from the templates, sooner |
| or later must be converted to an object that implements |
| <literal>TemplateModel</literal> interface. So first you should |
| familiarize yourself with writing of <literal>TemplateModel</literal> |
| implementations.</para> |
| |
| <para>There is roughly one |
| <literal>freemarker.template.TemplateModel</literal> descendant |
| interface corresponding to each basic type of variable |
| (<literal>TemplateHashModel</literal> for hashes, |
| <literal>TemplateSequenceModel</literal> sequences, |
| <literal>TemplateNumberModel</literal> for numbers, etc.). For |
| example, if you want to expose a <literal>java.sql.ResultSet</literal> |
| as a sequence for the templates, then you have to write a |
| <literal>TemplateSequenceModel</literal> implementation that can read |
| <literal>java.sql.ResultSet</literal>-s. We used to say on this, that |
| you <emphasis>wrap</emphasis> the |
| <literal>java.sql.ResultSet</literal> with your |
| <literal>TemplateModel</literal> implementation, as basically you just |
| encapsulate the <literal>java.sql.ResultSet</literal> to provide |
| access to it with the common <literal>TemplateSequenceModel</literal> |
| interface. Note that a class can implement multiple |
| <literal>TemplateModel</literal> interfaces; this is why FTL variables |
| can have multiple types (see: <xref |
| linkend="dgui_datamodel_basics"/>)</para> |
| |
| <para>Note that a trivial implementation of these interfaces is |
| provided with the <literal>freemarker.template</literal> package. For |
| example, to convert a <literal>String</literal> to FTL string |
| variable, you can use <literal>SimpleScalar</literal>, to convert a |
| <literal>java.util.Map</literal> to FTL hash variable, you can use |
| <literal>SimpleHash</literal>, etc.</para> |
| |
| <para>An easy way to try your own <literal>TemplateModel</literal> |
| implementation, is to create an instance of that, and drop it directly |
| into the data-model (as <literal>put</literal> it into the root hash). |
| The object wrapper will expose it untouched for the template, as it |
| already implements <literal>TemplateModel</literal>, so no conversion |
| (wrapping) needed. (This trick is also useful in cases when you do not |
| want the object wrapper to try to wrap (convert) a certain |
| object.)</para> |
| </section> |
| |
| <section xml:id="pgui_datamodel_scalar"> |
| <title>Scalars</title> |
| |
| <indexterm> |
| <primary>scalar</primary> |
| |
| <secondary>Java side</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>string</primary> |
| |
| <secondary>Java side</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>number</primary> |
| |
| <secondary>Java side</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>boolean</primary> |
| |
| <secondary>Java side</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>date</primary> |
| |
| <secondary>Java side</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>time</primary> |
| |
| <secondary>Java side</secondary> |
| </indexterm> |
| |
| <para>There are 4 scalar types:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>Boolean</para> |
| </listitem> |
| |
| <listitem> |
| <para>Number</para> |
| </listitem> |
| |
| <listitem> |
| <para>String</para> |
| </listitem> |
| |
| <listitem> |
| <para>Date-like (subtypes: date (no time part), time or |
| date-time)</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>For each scalar type is a |
| <literal>Template<replaceable>Type</replaceable>Model</literal> |
| interface, where <literal><replaceable>Type</replaceable></literal> is |
| the name of the type. These interfaces define only one method: |
| <literal><replaceable>type</replaceable> |
| getAs<replaceable>Type</replaceable>();</literal>. This returns the |
| value of the variable with the Java type (<literal>boolean</literal>, |
| <literal>Number</literal>, <literal>String</literal> and |
| <literal>Date</literal> respectively).</para> |
| |
| <note> |
| <para>For historical reasons the interface for string scalars is |
| called <literal>TemplateScalarModel</literal>, not |
| <literal>TemplateStringModel</literal>. (It's because in early |
| FreeMarker strings were the only kind of scalars.)</para> |
| </note> |
| |
| <para>A trivial implementation of these interfaces are available in |
| <literal>freemarker.template</literal> package with |
| <literal>Simple<replaceable>Type</replaceable></literal> class name. |
| However, there is no <literal>SimpleBooleanModel</literal>; to |
| represent the boolean values you can use the |
| <literal>TemplateBooleanModel.TRUE</literal> and |
| <literal>TemplateBooleanModel.FALSE</literal> singletons.</para> |
| |
| <note> |
| <para>For historical reasons the class for string scalars is called |
| <literal>SimpleScalar</literal>, not |
| <literal>SimpleString</literal>.</para> |
| </note> |
| |
| <para>Scalars are immutable within FTL. When you set the value of a |
| variable in a template, then you replace the |
| <literal>Template<replaceable>Type</replaceable>Model</literal> |
| instance with another instance, and don't change the value stored in |
| the original instance.</para> |
| |
| <section> |
| <title>Difficulties with the <quote>date-like</quote> types</title> |
| |
| <indexterm> |
| <primary>date</primary> |
| |
| <secondary>Java API related difficulties</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>time</primary> |
| |
| <secondary>Java API related difficulties</secondary> |
| </indexterm> |
| |
| <para>There is a complication around date-like types, because Java |
| API usually does not differentiate |
| <literal>java.util.Date</literal>-s that store only the date part |
| (April 4, 2003), only the time part (10:19:18 PM), or both (April 4, |
| 2003 10:19:18 PM). To display the value as text correctly (or to do |
| certain other operations), FreeMarker must know what parts of the |
| <literal>java.util.Date</literal> stores meaningful information, and |
| what parts are unused (usually 0-ed out). Unfortunately, this |
| information is usually only available when the value comes from a |
| database, because most databases have separate date, time and |
| date-time (aka. timestap) types, and <literal>java.sql</literal> has |
| 3 corresponding <literal>java.util.Date</literal> subclasses for |
| them.</para> |
| |
| <para><literal>TemplateDateModel</literal> interface has two |
| methods: <literal>java.util.Date getAsDate()</literal> and |
| <literal>int getDateType()</literal>. A typical implementation of |
| this interface, stores a <literal>java.util.Date</literal> object, |
| plus an integer that tells the subtype. The value of this integer |
| must be a constant from the <literal>TemplateDateModel</literal> |
| interface: <literal>DATE</literal>, <literal>TIME</literal>, |
| <literal>DATETIME</literal> and <literal>UNKNOWN</literal>.</para> |
| |
| <para>About <literal>UNKNOWN</literal>: <literal>java.lang</literal> |
| and <literal>java.util</literal> classes are usually converted |
| automatically into <literal>TemplateModel</literal> implementations |
| be the <literal>ObjectWrapper</literal> (see object wrapping |
| earlier). If the object wrapper has to wrap a |
| <literal>java.util.Date</literal>, that is not an instance of a |
| <literal>java.sql</literal> date class, it can't decide what the |
| subtype is, so it uses <literal>UNKNOWN</literal>. Later, if the |
| template has to use this variable, and the subtype is needed for the |
| operation, it will stop with error. To prevent this, for the |
| problematic variables the template author must specify the subtype |
| explicitly using the <link |
| linkend="ref_builtin_date_datetype"><literal>date</literal>, |
| <literal>time</literal> or <literal>datetime</literal> |
| built-ins</link> (like <literal>lastUpdated?datetime</literal>). |
| Note that if you use <literal>string</literal> built-in with format |
| parameter, as <literal>foo?string["MM/dd/yyyy"]</literal>, then |
| FreeMarker doesn't need to know the subtype.</para> |
| </section> |
| </section> |
| |
| <section xml:id="pgui_datamodel_parent"> |
| <title>Containers</title> |
| |
| <indexterm> |
| <primary>containers</primary> |
| |
| <secondary>Java side</secondary> |
| </indexterm> |
| |
| <para>These are hashes, sequences, and collections.</para> |
| |
| <section> |
| <title>Hashes</title> |
| |
| <indexterm> |
| <primary>hash</primary> |
| |
| <secondary>Java side</secondary> |
| </indexterm> |
| |
| <para>Hashes are java objects that implement |
| <literal>TemplateHashModel</literal> interface. |
| <literal>TemplateHashModel</literal> contains two methods: |
| <literal>TemplateModel get(String key)</literal>, which returns the |
| subvariable of the given name, and <literal>boolean |
| isEmpty()</literal>, which indicates if the hash has zero |
| subvariable or not. The <literal>get</literal> method returns null |
| if no subvariable with the given name exists.</para> |
| |
| <para>The <literal>TemplateHashModelEx</literal> interface extends |
| <literal>TemplateHashModel</literal>. It adds methods by which <link |
| linkend="ref_builtin_values">values</link> and <link |
| linkend="ref_builtin_keys">keys</link> built-ins can enumerate the |
| sub variables of the hash.</para> |
| |
| <para>The commonly used implementation is |
| <literal>SimpleHash</literal>, which implements |
| <literal>TemplateHashModelEx</literal>. Internally it uses a |
| <literal>java.util.Hash</literal> to store the sub variables. |
| <literal>SimpleHash</literal> has methods by which you can add and |
| remove subvariable. These methods should be used to initialize the |
| variable directly after its creation.</para> |
| |
| <para>Containers are immutable within FTL. That is, you can't add, |
| replace or remove the sub variables they contain.</para> |
| </section> |
| |
| <section> |
| <title>Sequences</title> |
| |
| <indexterm> |
| <primary>sequence</primary> |
| |
| <secondary>Java side</secondary> |
| </indexterm> |
| |
| <para>Sequences are java objects that implement |
| <literal>TemplateSequenceModel</literal>. It contains two methods: |
| <literal>TemplateModel get(int index)</literal> and <literal>int |
| size()</literal>.</para> |
| |
| <para>The commonly used implementation is |
| <literal>SimpleSequence</literal>. It uses internally a |
| <literal>java.util.List</literal> to store its sub variables. |
| <literal>SimpleSequence</literal> has methods by which you can add |
| sub variables. These methods should be used to populate the sequence |
| directly after its creation.</para> |
| </section> |
| |
| <section> |
| <title>Collections</title> |
| |
| <indexterm> |
| <primary>collection</primary> |
| |
| <secondary>Java side</secondary> |
| </indexterm> |
| |
| <para>Collections are java objects that implement the |
| <literal>TemplateCollectionModel</literal> interface. That interface |
| has one method: <literal>TemplateModelIterator iterator()</literal>. |
| The <literal>TemplateModelIterator</literal> interface is similar to |
| <literal>java.util.Iterator</literal>, but it returns |
| <literal>TemplateModels</literal> instead of |
| <literal>Object</literal>-s, and it can throw |
| <literal>TemplateModelException</literal>s.</para> |
| |
| <para>The commonly used implementation is |
| <literal>SimpleCollection</literal>.</para> |
| </section> |
| </section> |
| |
| <section xml:id="pgui_datamodel_method"> |
| <title>Methods</title> |
| |
| <indexterm> |
| <primary>method</primary> |
| |
| <secondary>Java side</secondary> |
| </indexterm> |
| |
| <para>Method variables exposed to a template implement the |
| <literal>TemplateMethodModel</literal> interface. This contains one |
| method: <literal>TemplateModel exec(java.util.List |
| arguments)</literal>. When you call a method with a <link |
| linkend="dgui_template_exp_methodcall">method call expression</link>, |
| then the <literal>exec</literal> method will be called. The arguments |
| parameter will contain the values of the FTL method call arguments. |
| The return value of <literal>exec</literal> gives the value of the FTL |
| method call expression.</para> |
| |
| <para>The <literal>TemplateMethodModelEx</literal> interface extends |
| <literal>TemplateMethodModel</literal>. It does not add any new |
| methods. The fact that the object implements this |
| <emphasis>marker</emphasis> interface indicates to the FTL engine that |
| the arguments should be put to the <literal>java.util.List</literal> |
| directly as <literal>TemplateModel</literal>-s. Otherwise they will be |
| put to the list as <literal>String</literal>-s.</para> |
| |
| <para>For obvious reasons there is no default implementation for these |
| interfaces.</para> |
| |
| <para>Example: This is a method, which returns the index within the |
| second string of the first occurrence of the first string, or -1 if |
| the second string doesn't contains the first.</para> |
| |
| <programlisting role="unspecified">public class IndexOfMethod implements TemplateMethodModel { |
| |
| public TemplateModel exec(List args) throws TemplateModelException { |
| if (args.size() != 2) { |
| throw new TemplateModelException("Wrong arguments"); |
| } |
| return new SimpleNumber( |
| ((String) args.get(1)).indexOf((String) args.get(0))); |
| } |
| }</programlisting> |
| |
| <para>If you put an instance of this, say, into the root:</para> |
| |
| <programlisting role="unspecified">root.put("indexOf", new IndexOfMethod());</programlisting> |
| |
| <para>then you can call it in the template:</para> |
| |
| <programlisting role="template"><#assign x = "something"> |
| ${indexOf("met", x)} |
| ${indexOf("foo", x)}</programlisting> |
| |
| <para>and then the output will be:</para> |
| |
| <programlisting role="output">2 |
| -1</programlisting> |
| |
| <para>If you need to access the runtime FTL environment (read/write |
| variables, get the current locale, etc.), you can get it with |
| <literal>Environment.getCurrentEnvironment()</literal>.</para> |
| </section> |
| |
| <section xml:id="pgui_datamodel_directive"> |
| <title>Directives</title> |
| |
| <indexterm> |
| <primary>directives</primary> |
| |
| <secondary>Java side</secondary> |
| </indexterm> |
| |
| <para>Java programmers can implement user-defined directives in Java |
| using the <literal>TemplateDirectiveModel</literal> interface. See in |
| the API documentation.</para> |
| |
| <note> |
| <para><literal>TemplateDirectiveModel</literal> was introduced in |
| FreeMarker 2.3.11, replacing the soon to be depreciated |
| <literal>TemplateTransformModel</literal>.</para> |
| </note> |
| |
| <section> |
| <title>Example 1</title> |
| |
| <para>We will implement a directive which converts all output |
| between its start-tag and end-tag to upper case. Like, this |
| template:</para> |
| |
| <programlisting role="template">foo |
| <emphasis><@upper></emphasis> |
| bar |
| <#-- All kind of FTL is allowed here --> |
| <#list ["red", "green", "blue"] as color> |
| ${color} |
| </#list> |
| baaz |
| <emphasis></@upper></emphasis> |
| wombat</programlisting> |
| |
| <para>will output this:</para> |
| |
| <programlisting role="output">foo |
| BAR |
| RED |
| GREEN |
| BLUE |
| BAAZ |
| wombat</programlisting> |
| |
| <para>This is the source code of the directive class:</para> |
| |
| <programlisting role="unspecified">package com.example; |
| import java.io.IOException; |
| import java.io.Writer; |
| import java.util.Map; |
| |
| import freemarker.core.Environment; |
| import freemarker.template.TemplateDirectiveBody; |
| import freemarker.template.TemplateDirectiveModel; |
| import freemarker.template.TemplateException; |
| import freemarker.template.TemplateModel; |
| import freemarker.template.TemplateModelException; |
| |
| /** |
| * FreeMarker user-defined directive that progressively transforms |
| * the output of its nested content to upper-case. |
| * |
| * |
| * <p><b>Directive info</b></p> |
| * |
| * <p>Directive parameters: None |
| * <p>Loop variables: None |
| * <p>Directive nested content: Yes |
| */ |
| public class UpperDirective implements TemplateDirectiveModel { |
| |
| public void execute(Environment env, |
| Map params, TemplateModel[] loopVars, |
| TemplateDirectiveBody body) |
| throws TemplateException, IOException { |
| // Check if no parameters were given: |
| if (!params.isEmpty()) { |
| throw new TemplateModelException( |
| "This directive doesn't allow parameters."); |
| } |
| if (loopVars.length != 0) { |
| throw new TemplateModelException( |
| "This directive doesn't allow loop variables."); |
| } |
| |
| // If there is non-empty nested content: |
| if (body != null) { |
| // Executes the nested body. Same as <#nested> in FTL, except |
| // that we use our own writer instead of the current output writer. |
| body.render(new UpperCaseFilterWriter(env.getOut())); |
| } else { |
| throw new RuntimeException("missing body"); |
| } |
| } |
| |
| /** |
| * A {@link Writer} that transforms the character stream to upper case |
| * and forwards it to another {@link Writer}. |
| */ |
| private static class UpperCaseFilterWriter extends Writer { |
| |
| private final Writer out; |
| |
| UpperCaseFilterWriter (Writer out) { |
| this.out = out; |
| } |
| |
| public void write(char[] cbuf, int off, int len) |
| throws IOException { |
| char[] transformedCbuf = new char[len]; |
| for (int i = 0; i < len; i++) { |
| transformedCbuf[i] = Character.toUpperCase(cbuf[i + off]); |
| } |
| out.write(transformedCbuf); |
| } |
| |
| public void flush() throws IOException { |
| out.flush(); |
| } |
| |
| public void close() throws IOException { |
| out.close(); |
| } |
| } |
| |
| }</programlisting> |
| |
| <para>Now we still need to create an instance of this class, and |
| make this directive available to the template with the name "upper" |
| (or with whatever name we want) somehow. A possible solution is to |
| put the directive in the data-model:</para> |
| |
| <programlisting role="unspecified">root.put("upper", new com.example.UpperDirective());</programlisting> |
| |
| <para>But typically it is better practice to put commonly used |
| directives into the <literal>Configuration</literal> as <link |
| linkend="pgui_config_sharedvariables">shared |
| variables</link>.</para> |
| |
| <para>It is also possible to put the directive into an FTL library |
| (collection of macros and like in a template, that you |
| <literal>include</literal> or <literal>import</literal> in other |
| templates) using the <link |
| linkend="ref_builtin_new"><literal>new</literal> |
| built-in</link>:</para> |
| |
| <programlisting role="template"><#-- Maybe you have directives that you have implemented in FTL --> |
| <#macro something> |
| ... |
| </#macro> |
| |
| <#-- Now you can't use <#macro upper>, but instead you can: --> |
| <#assign upper = "com.example.UpperDirective"?new()> |
| </programlisting> |
| </section> |
| |
| <section> |
| <title>Example 2</title> |
| |
| <para>We will create a directive that executes its nested content |
| again and again for the specified number of times (similarly to |
| <literal>list</literal> directive), optionally separating the the |
| output of the repetations with a <literal><hr></literal>-s. |
| Let's call this directive "repeat". Example template:</para> |
| |
| <programlisting role="template"><#assign x = 1> |
| |
| <emphasis><@repeat count=4></emphasis> |
| Test ${x} |
| <#assign x++> |
| <emphasis></@repeat></emphasis> |
| |
| <emphasis><@repeat count=3 hr=true></emphasis> |
| Test |
| <emphasis></@repeat></emphasis> |
| |
| <emphasis><@repeat count=3; cnt></emphasis> |
| ${cnt}. Test |
| <emphasis></@repeat></emphasis></programlisting> |
| |
| <para>Output:</para> |
| |
| <programlisting role="output"> Test 1 |
| Test 2 |
| Test 3 |
| Test 4 |
| |
| Test |
| <hr> Test |
| <hr> Test |
| |
| 1. Test |
| 2. Test |
| 3. Test |
| </programlisting> |
| |
| <para>The class:</para> |
| |
| <programlisting role="unspecified">package com.example; |
| import java.io.IOException; |
| import java.io.Writer; |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import freemarker.core.Environment; |
| import freemarker.template.SimpleNumber; |
| import freemarker.template.TemplateBooleanModel; |
| import freemarker.template.TemplateDirectiveBody; |
| import freemarker.template.TemplateDirectiveModel; |
| import freemarker.template.TemplateException; |
| import freemarker.template.TemplateModel; |
| import freemarker.template.TemplateModelException; |
| import freemarker.template.TemplateNumberModel; |
| |
| /** |
| * FreeMarker user-defined directive for repeating a section of a template, |
| * optionally with separating the output of the repetations with |
| * <tt>&lt;hr></tt>-s. |
| * |
| * |
| * <p><b>Directive info</b></p> |
| * |
| * <p>Parameters: |
| * <ul> |
| * <li><code>count</code>: The number of repetations. Required! |
| * Must be a non-negative number. If it is not a whole number then it will |
| * be rounded <em>down</em>. |
| * <li><code>hr</code>: Tells if a HTML "hr" element could be printed between |
| * repetations. Boolean. Optional, defaults to <code>false</code>. |
| * </ul> |
| * |
| * <p>Loop variables: One, optional. It gives the number of the current |
| * repetation, starting from 1. |
| * |
| * <p>Nested content: Yes |
| */ |
| public class RepeatDirective implements TemplateDirectiveModel { |
| |
| private static final String PARAM_NAME_COUNT = "count"; |
| private static final String PARAM_NAME_HR = "hr"; |
| |
| public void execute(Environment env, |
| Map params, TemplateModel[] loopVars, |
| TemplateDirectiveBody body) |
| throws TemplateException, IOException { |
| |
| // --------------------------------------------------------------------- |
| // Processing the parameters: |
| |
| int countParam = 0; |
| boolean countParamSet = false; |
| boolean hrParam = false; |
| |
| Iterator paramIter = params.entrySet().iterator(); |
| while (paramIter.hasNext()) { |
| Map.Entry ent = (Map.Entry) paramIter.next(); |
| |
| String paramName = (String) ent.getKey(); |
| TemplateModel paramValue = (TemplateModel) ent.getValue(); |
| |
| if (paramName.equals(PARAM_NAME_COUNT)) { |
| if (!(paramValue instanceof TemplateNumberModel)) { |
| throw new TemplateModelException( |
| "The \"" + PARAM_NAME_HR + "\" parameter " |
| + "must be a number."); |
| } |
| countParam = ((TemplateNumberModel) paramValue) |
| .getAsNumber().intValue(); |
| countParamSet = true; |
| if (countParam < 0) { |
| throw new TemplateModelException( |
| "The \"" + PARAM_NAME_HR + "\" parameter " |
| + "can't be negative."); |
| } |
| } else if (paramName.equals(PARAM_NAME_HR)) { |
| if (!(paramValue instanceof TemplateBooleanModel)) { |
| throw new TemplateModelException( |
| "The \"" + PARAM_NAME_HR + "\" parameter " |
| + "must be a boolean."); |
| } |
| hrParam = ((TemplateBooleanModel) paramValue) |
| .getAsBoolean(); |
| } else { |
| throw new TemplateModelException( |
| "Unsupported parameter: " + paramName); |
| } |
| } |
| if (!countParamSet) { |
| throw new TemplateModelException( |
| "The required \"" + PARAM_NAME_COUNT + "\" paramter" |
| + "is missing."); |
| } |
| |
| if (loopVars.length > 1) { |
| throw new TemplateModelException( |
| "At most one loop variable is allowed."); |
| } |
| |
| // Yeah, it was long and boring... |
| |
| // --------------------------------------------------------------------- |
| // Do the actual directive execution: |
| |
| Writer out = env.getOut(); |
| if (body != null) { |
| for (int i = 0; i < countParam; i++) { |
| // Prints a <hr> between all repetations if the "hr" parameter |
| // was true: |
| if (hrParam && i != 0) { |
| out.write("<hr>"); |
| } |
| |
| // Set the loop variable, if there is one: |
| if (loopVars.length > 0) { |
| loopVars[0] = new SimpleNumber(i + 1); |
| } |
| |
| // Executes the nested body (same as <#nested> in FTL). In this |
| // case we don't provide a special writer as the parameter: |
| body.render(env.getOut()); |
| } |
| } |
| } |
| |
| }</programlisting> |
| </section> |
| |
| <section> |
| <title>Notices</title> |
| |
| <para>It's important that a |
| <literal>TemplateDirectiveModel</literal> object usually should not |
| be stateful. The typical mistake is the storing of the state of the |
| directive call execution in the fields of the object. Think of |
| nested calls of the same directive, or directive objects used as |
| shared variables accessed by multiple threads concurrently.</para> |
| |
| <para>Unfortunately, <literal>TemplateDirectiveModel</literal>-s |
| don't support passing parameters by position (rather than by name). |
| This is fixed starting from FreeMarker 2.4.</para> |
| </section> |
| </section> |
| |
| <section xml:id="pgui_datamodel_node"> |
| <title>Node variables</title> |
| |
| <indexterm> |
| <primary>node</primary> |
| |
| <secondary>Java side</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>tree nodes</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>trees</primary> |
| </indexterm> |
| |
| <para>A node variable embodies a node in a tree structure. Node |
| variables were introduced to help <link linkend="xgui">the handling of |
| XML documents in the data-model</link>, but they can be used for the |
| modeling of other tree structures as well. For more information about |
| nodes from the point of view of the template language <link |
| linkend="dgui_datamodel_node">read this earlier section</link>.</para> |
| |
| <para>A node variable has the following properties, provided by the |
| methods of <literal>TemplateNodeModel</literal> interface:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Basic properties:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>TemplateSequenceModel |
| getChildNodes()</literal>: A node has sequence of children |
| (except if the node is a leaf node, in which case the method |
| return an empty sequence or null). The child nodes should be |
| node variables as well.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>TemplateNodeModel getParentNode()</literal>: A |
| node has exactly 1 parent node, except if the node is root |
| node of the tree, in which case the method returns |
| <literal>null</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Optional properties. If a property does not make sense in |
| the concrete use case, the corresponding method should return |
| <literal>null</literal>:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>String getNodeName()</literal>: The node name |
| is the name of the macro, that handles the node when you use |
| <link |
| linkend="ref.directive.recurse"><literal>recurse</literal></link> |
| and <link |
| linkend="ref.directive.visit"><literal>visit</literal></link> |
| directives. Thus, if you want to use these directives with the |
| node, the node name is <emphasis>required</emphasis>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>String getNodeType()</literal>: In the case of |
| XML: <literal>"element"</literal>, <literal>"text"</literal>, |
| <literal>"comment"</literal>, ...etc. This information, if |
| available, is used by the <literal>recurse</literal> and |
| <literal>visit</literal> directives to find the default |
| handler macro for a node. Also it can be useful for other |
| application specific purposes.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>String getNamespaceURI()</literal>: The node |
| namespace (has nothing to do with FTL namespaces used for |
| libraries) this node belongs to. For example, in the case of |
| XML, this is the URI of the XML namespace the element or |
| attribute belongs to. This information, if available, is used |
| by the <literal>recurse</literal> and <literal>visit</literal> |
| directives to find the FTL namespaces that store the handler |
| macros.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| </itemizedlist> |
| |
| <para>On the FTL side, the direct utilization of node properties is |
| done with <link linkend="ref_builtins_node">node built-ins</link>, and |
| with the <literal>visit</literal> and <literal>recurse</literal> |
| macros.</para> |
| |
| <para>In most use cases, variables that implement |
| <literal>TemplateNodeModel</literal>, implement other interfaces as |
| well, since node variable properties just provide the basic |
| infrastructure for navigating between nodes. For a concrete example, |
| see <link linkend="xgui">how FreeMarker deals with XML</link>.</para> |
| </section> |
| |
| <section xml:id="pgui_datamodel_objectWrapper"> |
| <title>Object wrappers</title> |
| |
| <indexterm> |
| <primary>object wrapper</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>wrapper</primary> |
| </indexterm> |
| |
| <para>The object wrapper is an object that implements the |
| <literal>freemarker.template.ObjectWrapper</literal> interface. It's |
| purpose is to implement a mapping between Java objects (like |
| <literal>String</literal>-s, <literal>Map</literal>-s, |
| <literal>List</literal>-s, instances of your application specific |
| classes, etc.) and FTL's type system. With other words, it specifies |
| how the templates will see the Java objects of the data-model |
| (including the return value of Java methods called from the template). |
| The object wrapper is plugged into the |
| <literal>Configuration</literal> as its |
| <literal>object_wrapper</literal> setting (or with |
| <literal>Configuration.setObjectWrapper</literal>).</para> |
| |
| <para>FTL's type system is technically represented by the |
| <literal>TemplateModel</literal> sub-interfaces that were introduced |
| earlier (<literal>TemplateScalarModel</literal>, |
| <literal>TemplateHashModel</literal>, |
| <literal>TemplateSequenceModel</literal>, etc). To map a Java object |
| to FTL's type system, object wrapper's <literal>TemplateModel |
| wrap(java.lang.Object obj)</literal> method will be called.</para> |
| |
| <para>Sometimes FreeMarker needs to reverse this mapping, in which |
| case the <literal>ObjectWrapper</literal>'s <literal>Object |
| unwrap(TemplateModel)</literal> method is called (or some other |
| variation of that, but see the API documentation for such details). |
| This last operation is in |
| <literal>ObjectWrapperAndUnwrapper</literal>, the subinterface of |
| <literal>ObjectWrapper</literal>. Most real world object wrappers will |
| implement <literal>ObjectWrapperAndUnwrapper</literal>.</para> |
| |
| <para>Here's how wrapping Java objects that contain other objects |
| (like a <literal>Map</literal>, a <literal>List</literal>, an array, |
| or an object with some JavaBean properties) usually work. Let's say, |
| an object wrapper wraps an <literal>Object[]</literal> array into some |
| implementation of the <literal>TemplateSquenceModel</literal> |
| interface. When FreeMarker needs an item from that FTL sequence, it |
| will call <literal>TemplateSquenceModel.get(int index)</literal>. The |
| return type of this method is <literal>TemplateModel</literal>, that |
| is, the <literal>TemplateSquenceModel</literal> implementation not |
| only have to get the <literal>Object</literal> from the given index of |
| the array, it's also responsible for wrapping that value before |
| returning it. To solve that, a typical |
| <literal>TemplateSquenceModel</literal> implementation will store the |
| <literal>ObjectWrapper</literal> that has cerated it, and then invoke |
| that <literal>ObjectWrapper</literal> to wrap the contained value. The |
| same logic stands for <literal>TemplateHashModel</literal> or for any |
| other <literal>TemplateModel</literal> that's a container for further |
| <literal>TemplateModel</literal>-s. Hence, usually, no mater how deep |
| the value hierarchy is, all values will be wrapped by the same single |
| <literal>ObjectWrapper</literal>. (To create |
| <literal>TemplateModel</literal> implementations that follow this |
| idiom, you can use the |
| <literal>freemarker.template.WrappingTemplateModel</literal> as base |
| class.)</para> |
| |
| <para>The data-model itself (the root variable) is a |
| <literal>TemplateHashModel</literal>. The root object that you specify |
| to <literal>Template.process</literal> will be wrapped with the object |
| wrapper specified in the <literal>object_wrapper</literal> |
| configuration setting, which must yield a |
| <literal>TemplateHashModel</literal>. From then on, the wrapping of |
| the contained values follow the logic described earlier (i.e., the |
| container is responsible for wrapping its children).</para> |
| |
| <para>Well behaving object wrappers bypass objects that already |
| implement <literal>TemplateModel</literal> as is. So if you put an |
| object into the data-model that already implements |
| <literal>TemplateModel</literal> (or you return as such object from a |
| Java method that's called from the template, etc.), then you can avoid |
| actual object wrapping. You do this usually when you are creating a |
| value specifically to be accessed from a template. Thus, you avoid |
| much of the object wrapping performance overhead, also you can control |
| exactly what will the template see (not depending on the mapping |
| strategy of the current object wrapper). A frequent application of |
| this trick is using a |
| <literal>freemarker.template.SimpleHash</literal> as the data-model |
| root (rather than a <literal>Map</literal>), by filling it with |
| <literal>SimpleHash</literal>'s <literal>put</literal> method (that's |
| important, so it won't have to copy an existing <literal>Map</literal> |
| that you have already filled). This speeds up top-level data-model |
| variable access.</para> |
| |
| <section xml:id="pgui_datamodel_defaultObjectWrapper"> |
| <title>The default object wrapper</title> |
| |
| <indexterm> |
| <primary>object wrapper</primary> |
| |
| <secondary>default</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>DefaultObjectWrapper</primary> |
| </indexterm> |
| |
| <para>The default of the <literal>object_wrapper</literal> |
| <literal>Configuration</literal> setting is a |
| <literal>freemarker.template.DefaultObjectWrapper</literal> |
| singleton. Unless you have very special requirements, it's |
| recommended to use this object wrapper, or an instance of a |
| <literal>DefaultObjectWrapper</literal> subclass of yours.</para> |
| |
| <para>It recognizes most basic Java types, like |
| <literal>String</literal>, <literal>Number</literal>, |
| <literal>Boolean</literal>, <literal>Date</literal>, |
| <literal>List</literal> (and in general all kind of |
| <literal>java.util.Collection</literal>-s), arrays, |
| <literal>Map</literal>, etc., and wraps them into the naturally |
| matching <literal>TemplateModel</literal> interfaces. It will also |
| wrap W3C DOM nodes with |
| <literal>freemarker.ext.dom.NodeModel</literal>, so you can |
| conveniently traverse XML as <link linkend="xgui">described in its |
| own chapter</link>). For Jython objects, it will delegate to |
| <literal>freemarker.ext.jython.JythonWrapper</literal>. For all |
| other objects, it will invoke <literal>BeansWrapper.wrap</literal> |
| (the super class's method), which will expose the JavaBean |
| properties of the objects as hash items (like |
| <literal>myObj.foo</literal> in FTL will call |
| <literal>getFoo()</literal> behind the scenes), and will also expose |
| the public methods (JavaBean actions) of the object (like |
| <literal>myObj.bar(1, 2)</literal> in FTL will call a method). (For |
| more information about BeansWrapper, <link |
| linkend="pgui_misc_beanwrapper">see its own section</link>.)</para> |
| |
| <para>Some further details that's worth mentioning about |
| <literal>DefaultObjectWrapper</literal>:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>You shouldn't use its constructor usually, instead create |
| it using a <literal>DefaultObjectWrapperBuilder</literal>. This |
| allows FreeMarker to use singletons.</para> |
| </listitem> |
| |
| <listitem xml:id="topic.defaultObjectWrapperIcI"> |
| <para><literal>DefaultObjectWrapper</literal> has an |
| <literal>incompatibleImprovements</literal> property, that's |
| highly recommended to set it to a high value (see the <link |
| xlink:href="https://freemarker.apache.org/docs/api/freemarker/template/DefaultObjectWrapper.html#DefaultObjectWrapper-freemarker.template.Version-">API |
| documentation</link> for the effects). How to set it:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>If you have set the |
| <literal>incompatible_improvements</literal> setting |
| <emphasis>of the <literal>Configuration</literal></emphasis> |
| to 2.3.22 or higher, and you didn't set the |
| <literal>object_wrapper</literal> setting (so it had |
| remained on its default value), then you have to do nothing, |
| as it already uses a <literal>DefaultObjectWrapper</literal> |
| singleton with the equivalent |
| <literal>incompatibleImprovements</literal> property |
| value.</para> |
| </listitem> |
| |
| <listitem xml:id="topic.setDefaultObjectWrapperIcIIndividually"> |
| <para>Otherwise you have to set the |
| <literal>incompatibleImprovements</literal> independently of |
| the <literal>Configuration</literal>. Depending on how you |
| create/set the <literal>ObjectWrapper</literal>, it can be |
| done like this:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>If you are using the builder API:</para> |
| |
| <programlisting role="unspecified">... = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_27).build()</programlisting> |
| </listitem> |
| |
| <listitem> |
| <para>Or, if you are using the constructor:</para> |
| |
| <programlisting role="unspecified">... = new DefaultObjectWrapper(Configuration.VERSION_2_3_27)</programlisting> |
| </listitem> |
| |
| <listitem> |
| <para>Or, if you are using the |
| <literal>object_wrapper</literal> property |
| (<literal>*.properties</literal> file or |
| <literal>java.util.Properties</literal> object):</para> |
| |
| <programlisting role="unspecified">object_wrapper=DefaultObjectWrapper(2.3.27)</programlisting> |
| </listitem> |
| |
| <listitem> |
| <para>Or, if you are configuring the |
| <literal>object_wrapper</literal> through a |
| <literal>FreemarkerServlet</literal> with an |
| <literal>init-param</literal> in |
| <literal>web.xml</literal>:</para> |
| |
| <programlisting role="unspecified"><init-param> |
| <param-name>object_wrapper</param-name> |
| <param-value>DefaultObjectWrapper(2.3.27)</param-value> |
| </init-param></programlisting> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>In new or properly test-covered projects it's also |
| recommended to set the |
| <literal>forceLegacyNonListCollections</literal> property to |
| <literal>false</literal>. If you are using |
| <literal>.properties</literal> or |
| <literal>FreemarkerServlet</literal> init-params or such, that |
| will look like <literal>DefaultObjectWrapper(2.3.22, |
| forceLegacyNonListCollections=false)</literal>, while with the |
| Java API you call |
| <literal>setForceLegacyNonListCollections(false)</literal> on |
| the <literal>DefaultObjectWrapperBuilder</literal> object before |
| calling <literal>build()</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The most common way of customizing |
| <literal>DefaultObjectWrapper</literal> is overriding its |
| <literal>handleUnknownType</literal> method.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section xml:id="pgui_datamodel_customObjectWrappingExample"> |
| <title>Custom object wrapping example</title> |
| |
| <indexterm> |
| <primary>object wrapper</primary> |
| |
| <secondary>custom</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>custom object wrapper</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>DefaultObjectWrapper</primary> |
| |
| <secondary>extending</secondary> |
| </indexterm> |
| |
| <para>Let's say you have an application-specific class like |
| this:</para> |
| |
| <programlisting role="unspecified">package com.example.myapp; |
| |
| public class Tupple<E1, E2> { |
| public Tupple(E1 e1, E2 e2) { ... } |
| public E1 getE1() { ... } |
| public E2 getE2() { ... } |
| }</programlisting> |
| |
| <para>You want templates to see this as a sequence of length 2, so |
| that you can do things like <literal>someTupple[1]</literal>, |
| <literal><#list someTupple |
| <replaceable>...</replaceable>></literal>, or |
| <literal>someTupple?size</literal>. For that you need to create a |
| <literal>TemplateSequenceModel</literal> implementation that adapts |
| a <literal>Tupple</literal> to the |
| <literal>TempateSequenceMoldel</literal> interface:</para> |
| |
| <programlisting role="unspecified">package com.example.myapp.freemarker; |
| |
| ... |
| |
| public class TuppleAdapter extends WrappingTemplateModel implements TemplateSequenceModel, |
| AdapterTemplateModel { |
| |
| private final Tupple<?, ?> tupple; |
| |
| public TuppleAdapter(Tupple<?, ?> tupple, ObjectWrapper ow) { |
| super(ow); // coming from WrappingTemplateModel |
| this.tupple = tupple; |
| } |
| |
| @Override // coming from TemplateSequenceModel |
| public int size() throws TemplateModelException { |
| return 2; |
| } |
| |
| @Override // coming from TemplateSequenceModel |
| public TemplateModel get(int index) throws TemplateModelException { |
| switch (index) { |
| case 0: return wrap(tupple.getE1()); |
| case 1: return wrap(tupple.getE2()); |
| default: return null; |
| } |
| } |
| |
| @Override // coming from AdapterTemplateModel |
| public Object getAdaptedObject(Class hint) { |
| return tupple; |
| } |
| |
| }</programlisting> |
| |
| <para>Regarding the classes and interfaces:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>TemplateSequenceModel</literal>: This is why the |
| template will see this as a sequence</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>WrappingTemplateModel</literal>: Just a |
| convenience class, used for <literal>TemplateModel</literal>-s |
| that do object wrapping themselves. That's normally only needed |
| for objects that contain other objects. See the |
| <literal>wrap(<replaceable>...</replaceable>)</literal> calls |
| above.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>AdapterTemplateModel</literal>: Indicates that |
| this template model adapts an already existing object to a |
| <literal>TemplateModel</literal> interface, thus unwrapping |
| should give back that original object.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Lastly, we tell FreeMarker to wrap <literal>Tupple</literal>-s |
| with the <literal>TuppleAdapter</literal> (alternatively, you could |
| wrap them manually before passing them to FreeMarker). For that, |
| first we create a custom object wrapper:</para> |
| |
| <programlisting role="unspecified">package com.example.myapp.freemarker; |
| |
| ... |
| |
| public class MyAppObjectWrapper extends DefaultObjectWrapper { |
| |
| public MyAppObjectWrapper(Version incompatibleImprovements) { |
| super(incompatibleImprovements); |
| } |
| |
| @Override |
| protected TemplateModel handleUnknownType(final Object obj) throws TemplateModelException { |
| if (obj instanceof Tupple) { |
| return new TuppleAdapter((Tupple<?, ?>) obj, this); |
| } |
| |
| return super.handleUnknownType(obj); |
| } |
| |
| }</programlisting> |
| |
| <para>and then where you configure FreeMarker (<link |
| linkend="pgui_config">about configuring, see here...</link>) we plug |
| our object wrapper in:</para> |
| |
| <programlisting role="unspecified">// Where you initialize the cfg *singleton* (happens just once in the application life-cycle): |
| cfg = new Configuration(Configuration.VERSION_2_3_27); |
| ... |
| cfg.setObjectWrapper(new MyAppObjectWrapper(cfg.getIncompatibleImprovements()));</programlisting> |
| |
| <para>or if you are configuring FreeMarker with |
| <literal>java.util.Properties</literal> instead (and let's say it's |
| also a <literal>.properties</literal> file):</para> |
| |
| <programlisting role="unspecified">object_wrapper=com.example.myapp.freemarker.MyAppObjectWrapper(2.3.27)</programlisting> |
| </section> |
| </section> |
| </chapter> |
| |
| <chapter xml:id="pgui_config"> |
| <title>The Configuration</title> |
| |
| <indexterm> |
| <primary>Configuration</primary> |
| </indexterm> |
| |
| <para>This is just an overview. See the <olink |
| targetdoc="api">FreeMarker Java API documentation</olink> for the |
| details.</para> |
| |
| <section xml:id="pgui_config_basics"> |
| <title>Basics</title> |
| |
| <para>First of all, be sure you have read the <link |
| linkend="pgui_quickstart_createconfiguration">Getting Started</link> |
| chapter.</para> |
| |
| <para>A configuration is a |
| <literal>freemarker.template.Configuration</literal> object that |
| stores your common (global, application level) settings and defines |
| variables that you want to be available in all templates (so called |
| shared variables). Also, it deals with the creation and caching of |
| <literal>Template</literal> instances.</para> |
| |
| <para>An application typically uses only a single shared |
| <literal>Configuration</literal> instance. More precisely, typically |
| you have one <literal>Configuration</literal> instance per |
| independently developed component that internally uses FreeMarker, so |
| they can be configured independently of each other. For example, your |
| e-mail sender component and your report generator component (service) |
| probably want to use their own <literal>Configuration</literal>-s, as |
| their needs differ.</para> |
| |
| <para>As the behavior of templates depends on the configuration |
| settings, each <literal>Template</literal> instance has an associated |
| <literal>Configuration</literal> instance. If you obtain the |
| <literal>Template</literal> instances with |
| <literal>Configuration.getTemplate</literal>, the associated |
| <literal>Configuration</literal> instance will be the one whose |
| <literal>getTemplate</literal> method was called. If you create the |
| <literal>Template</literal> instances directly with the |
| <literal>Template</literal> constructor, the |
| <literal>Configuration</literal> should be specified as constructor |
| parameter.</para> |
| </section> |
| |
| <section xml:id="pgui_config_sharedvariables"> |
| <title>Shared variables</title> |
| |
| <indexterm> |
| <primary>shared variable</primary> |
| </indexterm> |
| |
| <para><emphasis role="term">Shared variables</emphasis> are variables |
| that are defined for all templates. You can add shared variables to |
| the configuration with the <literal>setSharedVariable</literal> |
| methods:</para> |
| |
| <programlisting role="unspecified">Configuration cfg = new Configuration(Configuration.VERSION_2_3_27); |
| <replaceable>..</replaceable>. |
| cfg.setSharedVariable("warp", new WarpDirective()); |
| cfg.setSharedVariable("company", "Foo Inc.");</programlisting> |
| |
| <para>In all templates that use this configuration, an user-defined |
| directive with name <literal>wrap</literal> and a string with name |
| <literal>company</literal> will be visible in the data-model root, so |
| you don't have to add them to the root hash again and again. A |
| variable in the root object that you pass to the |
| <literal>Template.process</literal> will hide the shared variable with |
| the same name.</para> |
| |
| <warning> |
| <para>Never use <literal>TemplateModel</literal> implementation that |
| is not <link linkend="gloss.threadSafe">thread-safe</link> for |
| shared variables, if the configuration is used by multiple threads! |
| This is the typical situation for Servlet based applications.</para> |
| </warning> |
| |
| <para>Due to backward compatibility heritage, the set of shared |
| variables is initially (i.e., for a new |
| <literal>Configuration</literal> instance) not empty. It contains the |
| following user-defined directives (they are "user-defined" in the |
| sense that you use <literal>@</literal> to call them instead of |
| <literal>#</literal>):</para> |
| |
| <informaltable border="1"> |
| <thead> |
| <tr> |
| <th>name</th> |
| |
| <th>class</th> |
| </tr> |
| </thead> |
| |
| <tbody> |
| <tr> |
| <td><literal>capture_output</literal></td> |
| |
| <td><literal>freemarker.template.utility.CaptureOutput</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>compress</literal></td> |
| |
| <td><literal>freemarker.template.utility.StandardCompress</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>html_escape</literal></td> |
| |
| <td><literal>freemarker.template.utility.HtmlEscape</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>normalize_newlines</literal></td> |
| |
| <td><literal>freemarker.template.utility.NormalizeNewlines</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>xml_escape</literal></td> |
| |
| <td><literal>freemarker.template.utility.XmlEscape</literal></td> |
| </tr> |
| </tbody> |
| </informaltable> |
| </section> |
| |
| <section xml:id="pgui_config_settings"> |
| <title>Settings</title> |
| |
| <indexterm> |
| <primary>setting</primary> |
| </indexterm> |
| |
| <para><emphasis role="term">Settings</emphasis> are named values that |
| influence the behavior of FreeMarker. Examples of settings are: |
| <literal>locale</literal>, <literal>number_format</literal>, |
| <literal>default_encoding</literal>, |
| <literal>template_exception_handler</literal>. The full list of |
| settings can be found in the <olink |
| targetdoc="apiConfigurationSettings">Java API documentation of |
| <literal>Configuration.setSetting(...)</literal></olink>.</para> |
| |
| <para>The settings coming from the <literal>Configuration</literal> |
| can be overridden in a <literal>Template</literal> instance. For |
| example, if you set the <literal>locale</literal> setting to |
| <literal>"en_US"</literal> in the configuration, then the |
| <literal>locale</literal> in all templates that use this configuration |
| will be <literal>"en_US"</literal>, except in templates where the |
| <literal>locale</literal> was explicitly specified differently (see |
| <link linkend="ref_directive_include_localized">localization</link>). |
| Thus, the setting values in the <literal>Configuration</literal> serve |
| as defaults that can be overridden in a per template manner. The value |
| coming from the <literal>Configuration</literal> instance or |
| <literal>Template</literal> instance can be further overridden for a |
| single <literal>Template.process</literal> call. For each such call a |
| <literal>freemarker.core.Environment</literal> object is created |
| internally that holds the runtime environment of the template |
| processing, including the setting values that were overridden on that |
| level. The values stored there can even be changed during the template |
| processing, so a template can set settings itself, like switching |
| <literal>locale</literal> at the middle of the ongoing |
| processing.</para> |
| |
| <para>This can be imagined as 3 layers |
| (<literal>Configuration</literal>, <literal>Template</literal>, |
| <literal>Environment</literal>) of settings, where the topmost layer |
| that contains the value for a certain setting provides the effective |
| value of that setting. For example (settings A to F are just imaginary |
| settings for this example):</para> |
| |
| <informaltable border="1"> |
| <col align="left"/> |
| |
| <col align="center" span="6"/> |
| |
| <thead> |
| <tr> |
| <th/> |
| |
| <th>Setting A</th> |
| |
| <th>Setting B</th> |
| |
| <th>Setting C</th> |
| |
| <th>Setting D</th> |
| |
| <th>Setting E</th> |
| |
| <th>Setting F</th> |
| </tr> |
| </thead> |
| |
| <tbody> |
| <tr> |
| <td>Layer 3: <literal>Environment</literal></td> |
| |
| <td>1</td> |
| |
| <td>-</td> |
| |
| <td>-</td> |
| |
| <td>1</td> |
| |
| <td>-</td> |
| |
| <td>-</td> |
| </tr> |
| |
| <tr> |
| <td>Layer 2: <literal>Template</literal></td> |
| |
| <td>2</td> |
| |
| <td>2</td> |
| |
| <td>-</td> |
| |
| <td>-</td> |
| |
| <td>2</td> |
| |
| <td>-</td> |
| </tr> |
| |
| <tr> |
| <td>Layer 1: <literal>Configuration</literal></td> |
| |
| <td>3</td> |
| |
| <td>3</td> |
| |
| <td>3</td> |
| |
| <td>3</td> |
| |
| <td>-</td> |
| |
| <td>-</td> |
| </tr> |
| </tbody> |
| </informaltable> |
| |
| <para>The effective value of settings will be: A = 1, B = 2, C = 3, D |
| = 1, E = 2. The F setting is probably <literal>null</literal>, or it |
| throws exception when you try to get it.</para> |
| |
| <para>Let's see exactly how to set settings:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>Configuration</literal> layer: In principle you set |
| the settings with the setter methods of the |
| <literal>Configuration</literal> object, fore example:</para> |
| |
| <programlisting role="unspecified">Configuration myCfg = new Configuration(Configuration.VERSION_2_3_27); |
| myCfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); |
| myCfg.setDefaultEncoding("UTF-8"); |
| DefaultObjectWrapperBuilder owb = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_27); |
| owb.setForceLegacyNonListCollections(false); |
| owb.setDefaultDateType(TemplateDateModel.DATETIME); |
| myCfg.setObjectWrapper(owb.build());</programlisting> |
| |
| <para>You do this before you start to actually use the |
| <literal>Configuration</literal> object (typically, when you |
| initialize the application); you should treat the object as |
| read-only after that.</para> |
| |
| <para>In practice, in most frameworks you have to specify the |
| settings in some kind of framework-specific configuration file |
| that require specifying settings as <literal>String</literal> |
| name-value pairs (like in a <literal>.properties</literal> file). |
| In that case the authors of the frameworks most probably use the |
| <literal>Confguration.setSetting(String name, String |
| value)</literal> method; see available setting names and the |
| format of the values in the <link |
| xlink:href="https://freemarker.apache.org/docs/api/freemarker/template/Configuration.html#setSetting-java.lang.String-java.lang.String-">API |
| documentation of <literal>setSetting</literal></link>. Example for |
| Spring Framework:</para> |
| |
| <programlisting role="unspecified"><bean id="freemarkerConfig" |
| class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> |
| <property name="freemarkerSettings"> |
| <props> |
| <prop key="incompatible_improvements">2.3.27</prop> |
| <prop key="template_exception_handler">rethrow</prop> |
| <prop key="default_encoding">UTF-8</prop> |
| <prop key="object_wrapper"> |
| DefaultObjectWrapper( |
| 2.3.27, |
| forceLegacyNonListCollections = false, |
| defaultDateType = freemarker.template.TemplateDateModel.DATETIME) |
| </prop> |
| </props> |
| </property> |
| </bean></programlisting> |
| |
| <para>Here's the same when configuring FreeMarker for Struts, |
| which looks for a <literal>freemarker.properties</literal> in the |
| classpath:</para> |
| |
| <programlisting role="unspecified">incompatible_improvements=2.3.27 |
| template_exception_handler=rethrow |
| default_encoding=UTF-8 |
| object_wrapper=DefaultObjectWrapper( \ |
| 2.3.27, \ |
| forceLegacyNonListCollections = false, \ |
| defaultDateType = freemarker.template.TemplateDateModel.DATETIME)</programlisting> |
| |
| <para>As demonstrated above with |
| <literal>object_wrapper</literal>, some settings can accept quite |
| complex values, which can be used to instantiate objects of |
| arbitrary classes and set their properties. Still, configuring |
| with <literal>String</literal> key-value pairs is limited compared |
| to directly using the Java API, so in some cases you have to find |
| a way to do this in Java.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>Template</literal> layer: Settings on individual |
| templates are normally set by <link |
| linkend="pgui_config_templateconfigurations">template |
| configurations (see them in their own chapter)</link>, which |
| basically associate setting assignments to template name (template |
| path) patterns. There's a deviation from this approach with the |
| <literal>locale</literal> setting, because that you can also |
| specify to <literal>Configuration.getTemplate(...)</literal> as |
| parameter, to get the template for the requested locale (so called |
| localized lookup).</para> |
| |
| <warning> |
| <para>You should never set settings directly on the |
| <literal>Template</literal> object that you get from |
| <literal>Configuration.getTemplate(...)</literal>! Those objects |
| should be treated as already initialized and read-only.</para> |
| </warning> |
| |
| <para>When a template includes or imports another template, most |
| of the settings (like <literal>locale</literal>, |
| <literal>number_format</literal>, etc.) will remain those |
| specified by the top-level template. The exceptions are the |
| settings that affect the parsing of the template (like |
| <literal>tag_syntax</literal>, |
| <literal>whitespace_stripping</literal>, etc.), as these are not |
| inherited from the top-level template, instead each template |
| always uses its own values, no mater how it was invoked.</para> |
| |
| <note> |
| <para>If you are going to use template layer settings, you |
| should set <link |
| linkend="pgui_config_incompatible_improvements">the |
| <literal>incompatible_improvements</literal> setting</link> to |
| 2.3.22 or higher, to avoid some confusing legacy bugs.</para> |
| </note> |
| </listitem> |
| |
| <listitem> |
| <para><literal>Environment </literal>layer: There are two ways of |
| doing it:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>With Java API: Use the setter methods of the |
| <literal>Environment</literal> object. You may run into the |
| API problem that <literal>myTemplate.process(...)</literal> |
| both creates the <literal>Environment</literal> object |
| internally and processes the template, so you have no |
| opportunity to adjust the <literal>Environment</literal> in |
| between. The solution is that those two steps can be separated |
| like this:</para> |
| |
| <programlisting role="unspecified">Environment env = myTemplate.createProcessingEnvironment(root, out); |
| env.setLocale(java.util.Locale.ITALY); |
| env.setNumberFormat("0.####"); |
| env.process(); // process the template</programlisting> |
| </listitem> |
| |
| <listitem> |
| <para>Directly in the Template (considered as bad style, |
| usually): Use the <link |
| linkend="ref.directive.setting"><literal>setting</literal> |
| directive</link>, for example:</para> |
| |
| <programlisting role="template"><#setting locale="it_IT"> |
| <#setting number_format="0.####"></programlisting> |
| </listitem> |
| </itemizedlist> |
| |
| <para>There are no restriction regarding when can you change the |
| settings in this layer.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>To see the list of supported settings and their meaning, please |
| read the following parts of the FreeMarker Java API |
| documentation:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Setter methods of |
| <literal>freemarker.core.Configurable</literal> for the settings |
| that are in all three layers</para> |
| </listitem> |
| |
| <listitem> |
| <para>Setter methods of |
| <literal>freemarker.template.Configuration</literal> for the |
| settings that are available only in the |
| <literal>Configuration</literal> layer</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>freemarker.core.Configurable.setSetting(String, |
| String)</literal> for settings that are available in all three |
| layers and are writable with <literal>String</literal> key-value |
| pairs.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>freemarker.template.Configuration.setSetting(String, |
| String)</literal> for settings that are available only in the |
| <literal>Configuration</literal> layer and are writable with |
| <literal>String</literal> key-value pairs.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section xml:id="pgui_config_templateloading"> |
| <title>Template loading</title> |
| |
| <indexterm> |
| <primary>loading templates</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>template loading</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>storing templates</primary> |
| </indexterm> |
| |
| <section> |
| <title>Template loaders</title> |
| |
| <indexterm> |
| <primary>template loaders</primary> |
| </indexterm> |
| |
| <para>Template loaders are objects that load raw textual data based |
| on abstract template paths like <literal>"index.ftl"</literal> or |
| <literal>"products/catalog.ftl"</literal>. It's up to the concrete |
| template loader if from where and how the template |
| <quote>files</quote> are loaded. They could be real files inside a |
| specified directory, or values in a data base table, or |
| <literal>String</literal>-s in a Java Map, etc. When you call |
| <literal>cfg.getTemplate</literal> (where <literal>cfg</literal> is |
| a <literal>Configuration</literal> instance), FreeMarker asks the |
| template loader (<literal>cfg.getTemplateLoader</literal>) to return |
| the text for the given template path, and then FreeMarker parses |
| that text as template. It doesn't care or even know if the template |
| is a real file or not, and where it is physically; those details are |
| only known by the template loader.</para> |
| |
| <section> |
| <title>Built-in template loaders</title> |
| |
| <para>You can set up the three most common template loading |
| mechanism in the <literal>Configuration</literal> using the |
| following <emphasis>convenience</emphasis> methods:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>void setDirectoryForTemplateLoading(File |
| dir)</literal>: Sets a directory on the file system from which |
| to load templates. Template names (template paths) will be |
| interpreted relatively to this physical directory. It won't |
| let you load files outside this directory.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>void setClassForTemplateLoading(Class cl, |
| String basePackagePath)</literal> and <literal>void |
| setClassLoaderForTemplateLoading(ClassLoader classLoader, |
| String basePackagePath)</literal>: These are for when you want |
| to load templates via the same mechanism with which Java loads |
| classes (from the class-path, as they used to say vaguely). |
| This is very likely be the preferred means of loading |
| templates for production code, as it allows you to keep |
| everything inside the deployment <literal>jar</literal> files. |
| The first parameter decides which Java |
| <literal>ClassLoader</literal> will be used. The second |
| parameter specifies the package that contains the templates, |
| in <literal>/</literal>-separated format. Note that if you |
| don't start it with <literal>/</literal>, it will be |
| interpreted relatively to the package of the |
| <literal>Class</literal> parameter.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>void setServletContextForTemplateLoading(Object |
| servletContext, String path)</literal>: Takes the context of |
| your Servlet-based web application, and a base path, which is |
| interpreted relative to the web application root directory |
| (that's the parent of the <literal>WEB-INF</literal> |
| directory). Note that we refer to "directory" here although |
| this loading method works even for unpacked |
| <literal>.war</literal> files, since it uses |
| <literal>ServletContext.getResource()</literal> to access the |
| templates. If you omit the second parameter (or use |
| <literal>""</literal>), you can simply store the static files |
| (<literal>.html</literal>, <literal>.jpg</literal>, etc.) |
| mixed with the <literal>.ftl</literal> files. Of course, you |
| must set up a Servlet for the <literal>*.ftl</literal>, |
| <literal>*.ftlh</literal>, <literal>*.ftlx</literal> |
| uri-patterns in <literal>WEB-INF/web.xml</literal> for this, |
| otherwise the client will get the raw templates as is! To |
| avoid a such accident, many prefers storing the templates |
| somewhere inside the <literal>WEB-INF</literal> directory, |
| which is never visitable directly. This mechanism will very |
| likely be the preferred means of loading templates for servlet |
| applications, since the templates can be updated without |
| restarting the web application, while this often doesn't work |
| with the class-loader mechanism.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>If you want to use a custom |
| <literal>TemplateLoader</literal> implementation, or need to set |
| up some extra settings of a built-in template loader, you need to |
| instantiate the <literal>TemplateLoader</literal> object yourself, |
| and then call |
| <literal>Configuration.setTemplateLoader(TemplateLoader)</literal>:</para> |
| |
| <programlisting role="unspecified">WebappTemplateLoader templateLoader = new WebappTemplateLoader(servletContext, "WEB-INF/templates"); |
| templateLoader.setURLConnectionUsesCaches(false); |
| templateLoader.setAttemptFileAccess(false); |
| cfg.setTemplateLoader(templateLoader);</programlisting> |
| </section> |
| |
| <section> |
| <title>Loading templates from multiple locations</title> |
| |
| <para>If you need to load templates from multiple locations, you |
| have to instantiate the template loader objects for every |
| location, wrap them into a <literal>MultiTemplateLoader</literal>, |
| and finally pass that loader to the |
| <literal>setTemplateLoader(TemplateLoader loader)</literal> method |
| of <literal>Configuration</literal>. Here's an example for loading |
| templates from two distinct directories and with the |
| class-loader:</para> |
| |
| <programlisting role="unspecified">import freemarker.cache.*; // template loaders live in this package |
| |
| <replaceable>...</replaceable> |
| |
| FileTemplateLoader ftl1 = new FileTemplateLoader(new File("/tmp/templates")); |
| FileTemplateLoader ftl2 = new FileTemplateLoader(new File("/usr/data/templates")); |
| ClassTemplateLoader ctl = new ClassTemplateLoader(getClass(), "/com/example/templates"); |
| |
| MultiTemplateLoader mtl = new MultiTemplateLoader(new TemplateLoader[] { ftl1, ftl2, ctl }); |
| |
| cfg.setTemplateLoader(mtl);</programlisting> |
| |
| <para>Now FreeMarker will try to load templates from |
| <literal>/tmp/templates</literal> directory, and if it does not |
| find the requested template there, it will try to load that from |
| <literal>/usr/data/templates</literal>, and if it still does not |
| find the requested template, then it tries to load it from the |
| <literal>com.example.templates</literal> Java package.</para> |
| </section> |
| |
| <section> |
| <title>Loading templates from other sources</title> |
| |
| <para>If none of the built-in class loaders fit your needs, you |
| can write your own class that implements the |
| <literal>freemarker.cache.TemplateLoader</literal> interface and |
| pass it to the <literal>setTemplateLoader(TemplateLoader |
| loader)</literal> method of <literal>Configuration</literal>. |
| Please read the API JavaDoc for more information.</para> |
| |
| <para>If your template source accesses the templates through an |
| URL, you needn't implement a <literal>TemplateLoader</literal> |
| from scratch; you can choose to subclass |
| <literal>freemarker.cache.URLTemplateLoader</literal> instead and |
| just implement the <literal>URL getURL(String |
| templateName)</literal> method.</para> |
| </section> |
| |
| <section> |
| <title>The template name (template path)</title> |
| |
| <indexterm> |
| <primary>path</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>template path</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>template name</primary> |
| </indexterm> |
| |
| <para>It is up to the template loader how it interprets template |
| names (also known as template paths). But to work together with |
| other components there are restrictions regarding the format of |
| the path. In general, it is strongly recommended that template |
| loaders use URL-style paths. The path must not use |
| <literal>/</literal> (path step separator) character, nor the |
| <literal>.</literal> (same-directory) and <literal>..</literal> |
| (parent directory) path steps with other meaning than they have in |
| URL paths (or in UN*X paths). The <literal>*</literal> (asterisk) |
| step is also reserved, and used for <quote>template |
| acquisition</quote> feature of FreeMarker.</para> |
| |
| <para><literal>://</literal> (or with |
| <literal>template_name_format</literal> setting set to |
| <literal>DEFAULT_2_4_0</literal>, the <literal>:</literal> (colon) |
| character) is reserved for specifying a scheme part, similarly as |
| it works with URI-s. For example |
| <literal>someModule://foo/bar.ftl</literal> uses the |
| <literal>someModule</literal>, or assuming the |
| <literal>DEFAULT_2_4_0</literal> format, |
| <literal>classpath:foo/bar.ftl</literal> uses the |
| <literal>classpath</literal> scheme. Interpreting the scheme part |
| is completely up to the <literal>TemplateLoader</literal>. (The |
| FreeMarker core is only aware of the idea of schemes because |
| otherwise it couldn't resolve relative template names |
| properly.)</para> |
| |
| <para>FreeMarker always normalizes the paths before passing them |
| to the <literal>TemplateLoader</literal>, so the paths don't |
| contain <literal>/../</literal> or such, and are relative to the |
| imaginary template root directory (that is, they don't start with |
| <literal>/</literal>). They don't contain the <literal>*</literal> |
| step either, as template acquisition happens in an earlier stage. |
| Furthermore, with <literal>template_name_format</literal> setting |
| set to <literal>DEFAULT_2_4_0</literal>, multiple consecutive |
| <literal>/</literal>-s will be normalized to a single |
| <literal>/</literal> (unless they are part of the |
| <literal>://</literal> scheme separator).</para> |
| |
| <para>Note that FreeMarker template path should always uses slash |
| (not backslash) regardless of the host OS.</para> |
| </section> |
| </section> |
| |
| <section xml:id="pgui_config_templateloading_caching"> |
| <title>Template caching</title> |
| |
| <indexterm> |
| <primary>caching</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>template caching</primary> |
| </indexterm> |
| |
| <para>FreeMarker caches templates (assuming you use the |
| <literal>Configuration</literal> methods to create |
| <literal>Template</literal> objects). This means that when you call |
| <literal>getTemplate</literal>, FreeMarker not only returns the |
| resulting <literal>Template</literal> object, but stores it in a |
| cache, so when next time you call <literal>getTemplate</literal> |
| with the same (or equivalent) path, it just returns the cached |
| <literal>Template</literal> instance, and will not load and parse |
| the template file again.</para> |
| |
| <para>If you change the template file, then FreeMarker will re-load |
| and re-parse the template automatically when you get the template |
| next time. However, since always checking for changes can be burden |
| for a system that processes lot of templates, there is a |
| <literal>Configuration</literal> level setting called <quote>update |
| delay</quote> (defaults is 5 seconds). Until this much time has |
| elapsed since the last checking for a newer version, FreeMarker will |
| not check again if the template was changed. If you want to see the |
| changes without delay, set this setting to 0. Note that some |
| template loaders won't see that a template was changed because of |
| the underlying storage mechanism doesn't support that; for example, |
| class-loader based template loaders may have this problem.</para> |
| |
| <para>A template will be removed from the cache if you call |
| <literal>getTemplate</literal> and FreeMarker realizes that the |
| template file has been removed meanwhile. Also, if the JVM thinks |
| that it begins to run out of memory, by default it can arbitrarily |
| drop templates from the cache. Furthermore, you can empty the cache |
| manually with the <literal>clearTemplateCache</literal> method of |
| <literal>Configuration</literal>. You can also drop selected |
| template from the cache with |
| <literal>removeTemplateFromCache</literal>; this can be also |
| utilized to force re-loading a template regardless of the |
| <quote>update delay</quote> setting.</para> |
| |
| <para>The actual strategy of when a cached template should be thrown |
| away is pluggable with the <literal>cache_storage</literal> setting, |
| by which you can plug any <literal>CacheStorage</literal> |
| implementation. For most users |
| <literal>freemarker.cache.MruCacheStorage</literal> will be |
| sufficient. This cache storage implements a two-level Most Recently |
| Used cache. In the first level, items are strongly referenced up to |
| the specified maximum (strongly referenced items can't be dropped by |
| the JVM, as opposed to softly referenced items). When the maximum is |
| exceeded, the least recently used item is moved into the second |
| level cache, where they are softly referenced, up to another |
| specified maximum. The size of the strong and soft parts can be |
| specified with the constructor. For example, set the size of the |
| strong part to 20, and the size of soft part to 250:</para> |
| |
| <programlisting role="unspecified">cfg.setCacheStorage(new freemarker.cache.MruCacheStorage(20, 250))</programlisting> |
| |
| <para>Or, since <literal>MruCacheStorage</literal> is the default |
| cache storage implementation:</para> |
| |
| <programlisting role="unspecified">cfg.setSetting(Configuration.CACHE_STORAGE_KEY, "strong:20, soft:250");</programlisting> |
| |
| <para>When you create a new <literal>Configuration</literal> object, |
| initially it uses an <literal>MruCacheStorage</literal> where |
| <literal>strongSizeLimit</literal> is 0, and |
| <literal>softSizeLimit</literal> is |
| <literal>Integer.MAX_VALUE</literal> (that is, in practice, |
| infinite). Depending on how smart the JVM is, using non-0 |
| <literal>strongSizeLimit</literal> is maybe a safer option, as with |
| only softly referenced items the JVM could even throw the most |
| frequently used templates when there's a resource shortage, which |
| then have to be re-loaded and re-parsed, burdening the system even |
| more.</para> |
| </section> |
| </section> |
| |
| <section xml:id="pgui_config_errorhandling"> |
| <title>Error handling</title> |
| |
| <indexterm> |
| <primary>error handling</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>exception handling</primary> |
| </indexterm> |
| |
| <section> |
| <title>The possible exceptions</title> |
| |
| <para>The exceptions that can occur regarding FreeMarker could be |
| classified like this:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Exceptions occurring when you configure FreeMarker: |
| Typically you configure FreeMarker only once in your |
| application, when your application initializes itself. Of |
| course, during this, exceptions can occur.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Exceptions occurring when loading and parsing templates: |
| When you call |
| <literal>Configuration.getTemplate(<replaceable>...</replaceable>)</literal>, |
| FreeMarker has to load the template into the memory and parse it |
| (unless the template is already <link |
| linkend="pgui_config_templateloading_caching">cached</link> in |
| that <literal>Configuration</literal> object). During this, |
| these kind of exceptions can occur:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>TemplateNotFoundException</literal> because |
| the requested template doesn't exist. Note this extends |
| <literal>IOException</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>freemarker.core.ParseException</literal> |
| because the template is syntactically incorrect according |
| the rules of the FTL language. Note that this error occurs |
| when you obtain the <literal>Template</literal> object |
| (<literal>Configuration.getTemplate(<replaceable>...</replaceable>)</literal>), |
| not later when you execute |
| (<literal>Template.process(<replaceable>...</replaceable>)</literal>) |
| the template. . Note this extends |
| <literal>IOException</literal> (legacy).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Any other kind of <literal>IOException</literal> |
| because an error has occurred while reading an existing |
| template. For example you have no right to read the file, or |
| the connection through which you read the template is |
| broken. The emitter of these is the <link |
| linkend="pgui_config_templateloading"><literal>TemplateLoader</literal> |
| object</link>, which is plugged into the |
| <literal>Configuration</literal> object.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Exceptions occurring when executing (processing) |
| templates, that is, when you call |
| <literal>Template.process(<replaceable>...</replaceable>)</literal>. |
| Two kind of exceptions can occur:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>IOException</literal> because there was an |
| error when trying to write into the output writer.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>freemarker.template.TemplateException</literal> |
| because other problem occurred while executing the template. |
| For example, a frequent error is referring to a variable |
| that doesn't exist in the data-model. By default, when a |
| <literal>TemplateException</literal> occurs, FreeMarker |
| prints the FTL error message and the stack trace to the |
| output writer with plain text format, and then aborts the |
| template execution by re-throwing the |
| <literal>TemplateException</literal>, which then you can |
| catch as |
| <literal>Template.process(<replaceable>...</replaceable>)</literal> |
| throws it. This behavior can be customized, and in fact, it |
| should be; see the recommended configuration <link |
| linkend="pgui_quickstart_createconfiguration">here</link>. |
| By default FreeMarker also <link |
| linkend="pgui_misc_logging">logs</link> |
| <literal>TemplateException</literal>-s.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Customizing the behavior regarding |
| TemplateException-s</title> |
| |
| <para><literal>TemplateException</literal>-s thrown during the |
| template processing are handled by the |
| <literal>freemarker.template.TemplateExceptionHandler</literal> |
| object, which is plugged into the <literal>Configuration</literal> |
| object with its |
| <literal>setTemplateExceptionHandler(<replaceable>...</replaceable>)</literal> |
| method. These are the <literal>TemplateExceptionHandler</literal> |
| implementations with FreeMarker comes with:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>TemplateExceptionHandler.DEBUG_HANDLER</literal>: |
| Prints stack trace (includes FTL error message and FTL stack |
| trace) and re-throws the exception. This is the default handler, |
| however, you should be careful not using it in production |
| environment, as it shows technical information about your |
| system.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>TemplateExceptionHandler.HTML_DEBUG_HANDLER</literal>: |
| Same as <literal>DEBUG_HANDLER</literal>, but it formats the |
| stack trace so that it will be readable with Web browsers. |
| Recommended over <literal>DEBUG_HANDLER</literal> when you |
| generate HTML pages, but it should only be used for development |
| as it shows technical information about your system.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>TemplateExceptionHandler.IGNORE_HANDLER</literal>: |
| Simply suppresses all exceptions (though FreeMarker will still |
| log them if |
| <literal>Configuration.getLogTemplateExceptions</literal> is |
| <literal>true</literal>). It does nothing to handle the event. |
| It does not re-throw the exception.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>TemplateExceptionHandler.RETHROW_HANDLER</literal>: |
| Simply re-throws all exceptions; it doesn't do anything else. |
| This should be used in most applications today. It doesn't print |
| anything to the output about the error, which makes it safe, and |
| the developers can still get the error details from the logs. |
| It's not as convenient during template development as |
| <literal>HTML_DEBUG_HANDLER</literal> or |
| <literal>DEBUG_HANDLER</literal> though. For more information |
| about handling errors in Web applications <link |
| linkend="misc.faq.niceErrorPage">see the FAQ</link>.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>You can also write a custom |
| <literal>TemplateExceptionHandler</literal> by implementing that |
| interface, which contains this method:</para> |
| |
| <programlisting role="unspecified">void handleTemplateException(TemplateException te, Environment env, Writer out) |
| throws TemplateException;</programlisting> |
| |
| <para>Whenever a <literal>TemplateException</literal> occurs, this |
| method will be called. The exception to handle is in the |
| <literal>te</literal> argument, the runtime environment of the |
| template processing is in the <literal>env</literal> argument, and |
| the handler can print to the output using the <literal>out</literal> |
| argument. If this method throws exception (usually it re-throws |
| <literal>te</literal>), then the template processing will be |
| aborted, and |
| <literal>Template.process(<replaceable>...</replaceable>)</literal> |
| will throw the same exception. If |
| <literal>handleTemplateException</literal> doesn't throw exception, |
| then template processing continues as if nothing had happen, but the |
| statement that caused the exception will be skipped (see more |
| later). Of course, the handler can still print an error indicator to |
| the output.</para> |
| |
| <para>Let's see how FreeMarker skips statements when the error |
| handler doesn't throw exception, through examples. Assume we are |
| using this template exception handler:</para> |
| |
| <programlisting role="unspecified">class MyTemplateExceptionHandler implements TemplateExceptionHandler { |
| public void handleTemplateException(TemplateException te, Environment env, java.io.Writer out) |
| throws TemplateException { |
| try { |
| out.write("[ERROR: " + te.getMessage() + "]"); |
| } catch (IOException e) { |
| throw new TemplateException("Failed to print error message. Cause: " + e, env); |
| } |
| } |
| } |
| |
| <replaceable>...</replaceable> |
| |
| cfg.setTemplateExceptionHandler(new MyTemplateExceptionHandler());</programlisting> |
| |
| <para>If an error occurs in an interpolation which is not inside an |
| FTL tag (that is, not enclosed into |
| <literal><#<replaceable>...</replaceable>></literal> or |
| <literal><@<replaceable>...</replaceable>></literal>), then |
| the whole interpolation will be skipped. So this template (assuming |
| that <literal>badVar</literal> is missing from the |
| data-model):</para> |
| |
| <programlisting role="template">a${badVar}b</programlisting> |
| |
| <para>will print this if we use the |
| <literal>MyTemplateExceptionHandler</literal>:</para> |
| |
| <programlisting role="output">a[ERROR: Expression badVar is undefined on line 1, column 4 in test.ftl.]b</programlisting> |
| |
| <para>This template will print the same (except that the column |
| number will differ...):</para> |
| |
| <programlisting role="template">a${"moo" + badVar}b</programlisting> |
| |
| <para>because the whole interpolation is skipped if any error occurs |
| inside it.</para> |
| |
| <para>If an error occurs when evaluating the value of a parameter |
| for a directive call, or if there are other problems with the |
| parameter list, or if an error occurs when evaluating |
| <literal><replaceable>exp</replaceable></literal> in |
| <literal><@<replaceable>exp</replaceable> |
| <replaceable>...</replaceable>></literal>, or if the value of |
| <literal><replaceable>exp</replaceable></literal> is not an |
| user-defined directive, then the whole directive call is skipped. |
| For example this:</para> |
| |
| <programlisting role="template">a<#if badVar>Foo</#if>b</programlisting> |
| |
| <para>will print this:</para> |
| |
| <programlisting role="output">a[ERROR: Expression badVar is undefined on line 1, column 7 in test.ftlh.]b</programlisting> |
| |
| <para>Note that the error occurred in the <literal>if</literal> |
| start-tag (<literal><#if badVar></literal>), but the whole |
| directive call was skipped. Logically, the nested content |
| (<literal>Foo</literal>) was skipped with this, since the nested |
| content is handled (printed) by the enclosing directive |
| (<literal>if</literal>).</para> |
| |
| <para>The output will be the same with this (except that the column |
| number will differ...):</para> |
| |
| <programlisting role="template">a<#if "foo${badVar}" == "foobar">Foo</#if>b</programlisting> |
| |
| <para>because whole directive calling will be skipped if any error |
| occurs during the parameter evaluation.</para> |
| |
| <para>The directive call will not be skipped if the error occurs |
| after the execution of the directive was already started. That is, |
| if an error occurs in the nested content:</para> |
| |
| <programlisting role="template">a |
| <#if true> |
| Foo |
| ${badVar} |
| Bar |
| </#if> |
| c</programlisting> |
| |
| <para>or in the macro definition body:</para> |
| |
| <programlisting role="template">a |
| <@test /> |
| b |
| <#macro test> |
| Foo |
| ${badVar} |
| Bar |
| </#macro></programlisting> |
| |
| <para>the output will be something like:</para> |
| |
| <programlisting role="output">a |
| Foo |
| [ERROR: Expression badVar is undefined on line 4, column 5 in test.ftlh.] |
| Bar |
| c</programlisting> |
| </section> |
| |
| <section> |
| <title>TemplateException logging</title> |
| |
| <para>By default FreeMarker <link |
| linkend="pgui_misc_logging">logs</link> all |
| <literal>TemplateException</literal>-s under the |
| <literal>freemarker.runtime</literal> log category, even when it |
| will throw it at you from its public API. As logging has become |
| common practice in Java applications, this usually leads to double |
| logging of exceptions now, so it's recommended to disable this |
| legacy behavior by |
| <literal>cfg.setLogTemplateExceptions(false)</literal> (or |
| <literal>log_template_exceptions=false</literal>) where you |
| configure FreeMarker.</para> |
| </section> |
| |
| <section> |
| <title>Explicit error handling in templates</title> |
| |
| <para>Although it has nothing to do with the FreeMarker |
| configuration (the topic of this chapter), for the sake of |
| completeness it's mentioned here that you can handle errors directly |
| inside the templates as well:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Handling missing/null variables: <xref |
| linkend="dgui_template_exp_missing"/></para> |
| </listitem> |
| |
| <listitem> |
| <para>Substituting failing but expendable page sections: <xref |
| linkend="ref_directive_attempt"/></para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="pgui_config_templateconfigurations"> |
| <title>Template configurations</title> |
| |
| <para><quote>Template configurations</quote> refers to the |
| <literal>template_configurations</literal> setting of |
| <literal>Configuration</literal> |
| (<literal>Configuration.setTemplateConfigurations(<replaceable>...</replaceable>)</literal>). |
| This setting lets you override individual settings coming from the |
| common <literal>Configuration</literal> object, depending on the name |
| (path) of the template.</para> |
| |
| <para>It's important to understand, however, that this setting only |
| has effect if you get templates with |
| <literal>Configuration.getTemplate(<replaceable>...</replaceable>)</literal>, |
| not when you create templates directly with the |
| <literal>Template</literal> constructors. In that case it's up to you |
| to invoke this mechanism (see <literal>TemplateCache</literal> source |
| code as an example).</para> |
| |
| <para>You will use these kind of objects to declare your template |
| configuration rules:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>TemplateConfiguration</literal>-s: These store the |
| actual setting assignments that you want to apply. For example, |
| this <literal>TemplateConfiguration</literal> will set the |
| encoding and the output format of the matched template (and leave |
| all other settings of it alone):</para> |
| |
| <programlisting role="unspecified">TemplateConfiguration tcUTF8XML = new TemplateConfiguration(); |
| tc.setEncoding("utf-8"); |
| tc.setOutputFormat(XMLOutputFormat.INSTANCE);</programlisting> |
| </listitem> |
| |
| <listitem> |
| <para><literal>TemplateSourceMatcher</literal> (abstract) |
| subclasses: These define a rule that matches templates based on |
| their source name (their source path; as in |
| <literal>Template.getSourceName()</literal>), and possibly on |
| other <literal>TemplateLoader</literal>-dependent properties. For |
| example, <literal>new FileExtensionMatcher("xml")</literal> |
| matches templates that has <literal>xml</literal> file extension. |
| See all the subclasses in the Java API documentation.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>TemplateConfigurationFactory</literal>-es: This is |
| what connects <literal>TemplateConfiguration</literal>-s and |
| <literal>TemplateSourceMatcher</literal>-s together. This is the |
| Java type of the <literal>template_configurations</literal> |
| setting. See the examples below for more.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <simplesect> |
| <title>Example 1</title> |
| |
| <para>This setup combines our earlier two example objects with a |
| <literal>ConditionalTemplateConfigurationFactory</literal>, causing |
| all templates with <literal>xml</literal> extension to get UTF-8 |
| encoding and XML output format:</para> |
| |
| <programlisting role="unspecified">cfg.setTemplateConfigurations( |
| new ConditionalTemplateConfigurationFactory( |
| new FileExtensionMatcher("xml"), |
| tcUTF8XML));</programlisting> |
| |
| <para>The same configuring is also doable if you don't have access |
| to the configuring Java code, but only to a Java |
| <literal>*.properties</literal> file, or other kind of string-string |
| key value pairs (the <literal>\</literal>-s are prescribed by the |
| Java Properties file format for multi-line values, so omit them |
| elsewhere):</para> |
| |
| <programlisting role="unspecified">templateConfigurations = \ |
| ConditionalTemplateConfigurationFactory( \ |
| FileExtensionMatcher("xml"), \ |
| TemplateConfiguration( \ |
| encoding = "utf-8", \ |
| outputFormat = XMLOutputFormat() \ |
| ) \ |
| )</programlisting> |
| </simplesect> |
| |
| <simplesect> |
| <title>Example 2</title> |
| |
| <para>Let's say you only need to handle templates in the |
| <literal>mail</literal> directory specially, other templates can use |
| the setting coming from the shared <literal>Configuration</literal> |
| singleton. The names of templates there must contain |
| <literal>".subject."</literal> or <literal>".body."</literal>. |
| Subject templates must get <literal>plainText</literal> output |
| format, while body templates must get <literal>HTML</literal> output |
| format. So we have to make a choice here, and that's when you need a |
| <literal>FirstMatchTemplateConfigurationFactory</literal>.</para> |
| |
| <para>Assuming <literal>cfg</literal> stores the shared |
| <literal>Configuration</literal> singleton, you set this up like |
| this:</para> |
| |
| <programlisting role="unspecified">TemplateConfiguration tcSubject = new TemplateConfiguration(); |
| tcSubject.setOutputFormat(PlainTextOutputFormat.INSTANCE); |
| |
| TemplateConfiguration tcBody = new TemplateConfiguration(); |
| tcBody.setOutputFormat(HTMLOutputFormat.INSTANCE); |
| |
| cfg.setTemplateConfigurations( |
| new ConditionalTemplateConfigurationFactory( |
| new PathGlobMatcher("mail/**"), |
| new FirstMatchTemplateConfigurationFactory( |
| new ConditionalTemplateConfigurationFactory( |
| new FileNameGlobMatcher("*.subject.*"), |
| tcSubject), |
| new ConditionalTemplateConfigurationFactory( |
| new FileNameGlobMatcher("*.body.*"), |
| tcBody) |
| ) |
| .noMatchErrorDetails( |
| "Mail template names must contain \".subject.\" or \".body.\"!") |
| ));</programlisting> |
| |
| <para>The equivalent configuration using a Java |
| <literal>*.properties</literal> file or other kind of string-string |
| key value pairs (the <literal>\</literal>-s are prescribed by the |
| Java Properties file format only, so omit them elsewhere):</para> |
| |
| <programlisting role="unspecified">templateConfigurations = \ |
| ConditionalTemplateConfigurationFactory( \ |
| PathGlobMatcher("mail/**"), \ |
| FirstMatchTemplateConfigurationFactory( \ |
| ConditionalTemplateConfigurationFactory( \ |
| FileNameGlobMatcher("*.subject.*"), \ |
| TemplateConfiguration(outputFormat = PlainTextOutputFormat()) \ |
| ), \ |
| ConditionalTemplateConfigurationFactory( \ |
| FileNameGlobMatcher("*.body.*"), \ |
| TemplateConfiguration(outputFormat = HTMLOutputFormat()) \ |
| ), \ |
| noMatchErrorDetails = 'Mail template names must contain ".subject." or ".body."!' \ |
| ) \ |
| )</programlisting> |
| </simplesect> |
| |
| <simplesect> |
| <title>Example 3</title> |
| |
| <para>Let's say you want the following deviations from the shared |
| <literal>Configuration</literal> settings in your |
| application:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>All templates whose name contains |
| <literal>".stats."</literal> should use ISO date/time format and |
| UTC time zone</para> |
| </listitem> |
| |
| <listitem> |
| <para>All templates inside the <literal>mail</literal> directory |
| should use UTF-8 encoding</para> |
| </listitem> |
| |
| <listitem> |
| <para>Templates with <literal>xml</literal> file extension |
| should use XML <literal>output_format</literal>, templates with |
| <literal>html</literal> or <literal>htm</literal> extension |
| should use HTML output format. For other templates, the shared |
| <literal>Configuration</literal> can dictate the |
| <literal>output_format</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Here we have 3 independent concerns, and possibly multiple (or |
| none) of those apply to a template; that's when you need a |
| <literal>MergingTemplateConfigurationFactory</literal>. In file |
| extension related rule above you have mutually exclusive choices, so |
| you need a |
| <literal>FirstMatchTemplateConfigurationFactory</literal>, but this |
| time no choice is also allowed. Here's the source code, assuming |
| <literal>cfg</literal> stores the shared |
| <literal>Configuration</literal> instance:</para> |
| |
| <programlisting role="unspecified">TemplateConfiguration tcStats = new TemplateConfiguration(); |
| tcStats.setDateTimeFormat("iso"); |
| tcStats.setDateFormat("iso"); |
| tcStats.setTimeFormat("iso"); |
| tcStats.setTimeZone(DateUtil.UTC); |
| |
| TemplateConfiguration tcMail = new TemplateConfiguration(); |
| tcMail.setEncoding("utf-8"); |
| |
| TemplateConfiguration tcHTML = new TemplateConfiguration(); |
| tcHTML.setOutputFormat(HTMLOutputFormat.INSTANCE); |
| |
| TemplateConfiguration tcXML = new TemplateConfiguration(); |
| tcXML.setOutputFormat(XMLOutputFormat.INSTANCE); |
| |
| cfg.setTemplateConfigurations( |
| new MergingTemplateConfigurationFactory( |
| new ConditionalTemplateConfigurationFactory( |
| new FileNameGlobMatcher("*.stats.*"), |
| tcStats), |
| new ConditionalTemplateConfigurationFactory( |
| new PathGlobMatcher("mail/**"), |
| tcMail), |
| new FirstMatchTemplateConfigurationFactory( |
| new ConditionalTemplateConfigurationFactory( |
| new FileExtensionMatcher("xml"), |
| tcXML), |
| new ConditionalTemplateConfigurationFactory( |
| new OrMatcher( |
| new FileExtensionMatcher("html"), |
| new FileExtensionMatcher("htm")), |
| tcHTML) |
| ).allowNoMatch(true) |
| ) |
| );</programlisting> |
| |
| <para>The equivalent configuration using a Java |
| <literal>*.properties</literal> file or other kind of string-string |
| key value pairs (the <literal>\</literal>-s are prescribed by the |
| Java Properties file format only):</para> |
| |
| <programlisting role="unspecified">templateConfigurations = \ |
| MergingTemplateConfigurationFactory( \ |
| ConditionalTemplateConfigurationFactory( \ |
| FileNameGlobMatcher("*.stats.*"), \ |
| TemplateConfiguration( \ |
| dateTimeFormat = "iso", \ |
| dateFormat = "iso", \ |
| timeFormat = "iso", \ |
| timeZone = TimeZone("UTC") \ |
| ) \ |
| ), \ |
| ConditionalTemplateConfigurationFactory( \ |
| PathGlobMatcher("mail/**"), \ |
| TemplateConfiguration(encoding = "utf-8") \ |
| ), \ |
| FirstMatchTemplateConfigurationFactory( \ |
| ConditionalTemplateConfigurationFactory( \ |
| FileExtensionMatcher("xml"), \ |
| TemplateConfiguration(outputFormat = XMLOutputFormat()) \ |
| ), \ |
| ConditionalTemplateConfigurationFactory( \ |
| OrMatcher( \ |
| FileExtensionMatcher("html"), \ |
| FileExtensionMatcher("htm") \ |
| ), \ |
| TemplateConfiguration(outputFormat = HTMLOutputFormat()) \ |
| ), \ |
| allowNoMatch = true \ |
| ) \ |
| )</programlisting> |
| </simplesect> |
| </section> |
| |
| <section xml:id="pgui_config_outputformatsautoesc"> |
| <title>Associating output formats with templates</title> |
| |
| <indexterm> |
| <primary>auto-escaping</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>output format</primary> |
| </indexterm> |
| |
| <para>The output format associated to a template decides if and what |
| kind of auto-escaping is used in that template (unless the template |
| <link linkend="dgui_misc_autoescaping_overrideoformat">overrides that |
| with directives</link>). By default, templates have |
| <quote>undefined</quote> output format associated, which does no |
| escaping, and in general gives the behavior that you would expect from |
| a template engine that doesn't care about output formats and escaping. |
| However, if the <literal>recognize_standard_file_extensions</literal> |
| <link linkend="pgui_config_settings">setting</link> is |
| <literal>true</literal> (which is the default with <link |
| linkend="pgui_config_incompatible_improvements">the |
| <literal>incompatible_improvements</literal> setting</link> set to |
| 2.3.24 or higher), templates whose source name ends with |
| <literal>".ftlh"</literal> gets <quote>HTML</quote> output format, and |
| those with <literal>".ftlx"</literal> get <quote>XML</quote> output |
| format. Using the <literal>ftlh</literal> and <literal>ftlx</literal> |
| file extensions is the recommended way of activating HTML and XML |
| auto-escaping. You can also associate output formats to templates |
| based on arbitrary name patterns with the <link |
| linkend="pgui_config_templateconfigurations"><literal>template_configurations</literal> |
| setting</link>; see some examples of that below.</para> |
| |
| <para>There's another a related setting, called |
| <literal>auto_escaping_policy</literal>, which can be used to disable |
| auto-escaping even if the current output format supports it, or enable |
| auto-escaping even if the format by default doesn't escape (but it |
| supports it), or to enforce auto-escaping. Using this setting rarely |
| advisable, as it's potentially confusing for the template authors. |
| (Instead, escaping can be turned on/off explicitly inside the |
| templates with the <literal>auto_esc</literal> parameter of the <link |
| linkend="ref_directive_ftl"><literal>ftl</literal> directive</link>, |
| or with the <link |
| linkend="ref_directive_autoesc"><literal>noautoesc</literal></link> |
| and <link linkend="ref_directive_autoesc"><literal>autoesc</literal> |
| directive</link>s.)</para> |
| |
| <para>To check if you have configured FreeMarker properly, you can use |
| this template:</para> |
| |
| <programlisting role="template"><p>Output format: ${.output_format} |
| <p>Auto-escaping: ${.auto_esc?c}</programlisting> |
| |
| <para>See the <link linkend="topic.predefinedOutputFormats">table of |
| predefined output formats here...</link></para> |
| |
| <para>Configuration examples:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>To enable automatic output format associations to |
| <literal>*.ftlh</literal> and <literal>*.ftlx</literal>, |
| either:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Use <literal>incompatible_improvements</literal> 2.3.24 |
| or higher; see <link |
| linkend="pgui_config_incompatible_improvements_how_to_set">how |
| to set |
| <literal>incompatible_improvements</literal></link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Or, enable standard file extension recognizing |
| explicitly:</para> |
| |
| <programlisting role="unspecified">// Where you initalize the Configuration singletion, add: |
| cfg.setRecognizeStandardFileExtensions(true);</programlisting> |
| |
| <para>or if you configure FreeMarker with Java |
| <literal>*.properties</literal> file:</para> |
| |
| <programlisting role="unspecified">recognizeStandardFileExtensions = true</programlisting> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Let's say that you want to associate all templates in the |
| <literal>mail</literal> directory to the HTML output format. You |
| could achieve that like this (assuming that you are getting the |
| templates with |
| <literal>cfg.getTemplate(<replaceable>...</replaceable>)</literal>, |
| and not instantiating them yourself):</para> |
| |
| <programlisting role="unspecified">// Where you initalize the Configuration singletion, add: |
| |
| TemplateConfiguration tcHTML = new TemplateConfiguration(); |
| tcHTML.setOutputFormat(HTMLOutputFormat.INSTANCE); |
| |
| cfg.setTemplateConfigurations( |
| new ConditionalTemplateConfigurationFactory( |
| new PathGlobMatcher("mail/**"), |
| tcHTML));</programlisting> |
| |
| <para>or if you are configuring FreeMarker from Java |
| <literal>*.properties</literal> file (the <literal>\</literal>-s |
| are required for the Java Properties file format only):</para> |
| |
| <programlisting role="unspecified">templateConfigurations = \ |
| ConditionalTemplateConfigurationFactory( \ |
| PathGlobMatcher("mail/**"), \ |
| TemplateConfiguration(outputFormat = HTMLOutputFormat()))</programlisting> |
| </listitem> |
| |
| <listitem> |
| <para>Let's say you want to associate templates with |
| <literal>xml</literal> file extension to the XML output format, |
| templates with <literal>html</literal> and <literal>htm</literal> |
| extension to the HTML output format, and templates with |
| <literal>rtf</literal> extension to the <literal>RTF</literal> |
| output format. You could achieve that like this (assuming that you |
| are getting the templates with |
| <literal>cfg.getTemplate(<replaceable>...</replaceable>)</literal>, |
| and not instantiating them yourself):</para> |
| |
| <programlisting role="unspecified">TemplateConfiguration tcHTML = new TemplateConfiguration(); |
| tcHTML.setOutputFormat(HTMLOutputFormat.INSTANCE); |
| |
| TemplateConfiguration tcXML = new TemplateConfiguration(); |
| tcXML.setOutputFormat(XMLOutputFormat.INSTANCE); |
| |
| TemplateConfiguration tcRTF = new TemplateConfiguration(); |
| tcRTF.setOutputFormat(RTFOutputFormat.INSTANCE); |
| |
| cfg.setTemplateConfigurations( |
| new FirstMatchTemplateConfigurationFactory( |
| new ConditionalTemplateConfigurationFactory( |
| new FileExtensionMatcher("xml"), |
| tcXML), |
| new ConditionalTemplateConfigurationFactory( |
| new OrMatcher( |
| new FileExtensionMatcher("html"), |
| new FileExtensionMatcher("htm")), |
| tcHTML), |
| new ConditionalTemplateConfigurationFactory( |
| new FileExtensionMatcher("rtf"), |
| tcRTF) |
| ).allowNoMatch(true) |
| );</programlisting> |
| |
| <para>or if you are configuring FreeMarker from Java |
| <literal>*.properties</literal> file (the <literal>\</literal>-s |
| are required for the Java Properties file format only):</para> |
| |
| <programlisting role="unspecified">templateConfigurations = \ |
| FirstMatchTemplateConfigurationFactory( \ |
| ConditionalTemplateConfigurationFactory( \ |
| FileExtensionMatcher("xml"), \ |
| TemplateConfiguration(outputFormat = XMLOutputFormat())), \ |
| ConditionalTemplateConfigurationFactory( \ |
| OrMatcher( \ |
| FileExtensionMatcher("html"), \ |
| FileExtensionMatcher("htm")), \ |
| TemplateConfiguration(outputFormat = HTMLOutputFormat())), \ |
| ConditionalTemplateConfigurationFactory( \ |
| FileExtensionMatcher("rtf"), \ |
| TemplateConfiguration(outputFormat = RTFOutputFormat())), \ |
| allowNoMatch = true)</programlisting> |
| </listitem> |
| </itemizedlist> |
| |
| <para>(You can find some more complex |
| <literal>template_configurations</literal> setups <link |
| linkend="pgui_config_templateconfigurations">here...</link>)</para> |
| </section> |
| |
| <section xml:id="pgui_config_custom_formats"> |
| <title>Custom number and date/time formats</title> |
| |
| <section> |
| <title>Overview</title> |
| |
| <note> |
| <para>Custom formats (of the kind described here) exists since |
| FreeMarker 2.3.24.</para> |
| </note> |
| |
| <para>FreeMarker allows you to define your own number and |
| date/time/datetime formats, and associate a name to them. This |
| mechanism has several applications:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Custom formatter algorithms: You can use your own |
| formatter algorithm instead of relying on those provided by |
| FreeMarker. For this, implement |
| <literal>freemarker.core.TemplateNumberFormatFactory</literal> |
| or <literal>freemarker.core.TemplateDateFormatFactory</literal>. |
| You will find a few examples of this <link |
| linkend="pgui_config_custom_formats_ex_cust_alg_simple">below</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Aliasing: You can give application-specific names (like |
| <quote>price</quote>, <quote>weight</quote>, |
| <quote>fileDate</quote>, <quote>logEventTime</quote>, etc.) to |
| other formats by using |
| <literal>AliasTemplateNumberFormatFactory</literal> and |
| <literal>AliasTemplateDateFormatFactory</literal>. Thus |
| templates can just refer to that name, like in |
| <literal>${lastModified?string.@fileDate}</literal>, instead of |
| specifying the format directly. Thus the formats can be |
| specified on a single central place (where you configure |
| FreeMarker), instead of being specified repeatedly in templates. |
| Also thus template authors don't have to enter complex and hard |
| to remember formatting patterns. <link |
| linkend="pgui_config_custom_formats_ex_alias">See example |
| below</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Model-sensitive formatting: Applications can put custom |
| <literal>freemarker.TemplateModel</literal>-s into the |
| data-model instead of dropping plain values (like |
| <literal>int</literal>-s, <literal>double</literal>-s, etc.) |
| into it, to attach rendering-related information to the value. |
| Custom formatters can utilize this information (for example, to |
| show the unit after numbers), as they receive the |
| <literal>TemplateModel</literal> itself, not the wrapped raw |
| value. <link |
| linkend="pgui_config_custom_formats_ex_model_aware">See example |
| below</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Format that prints markup instead of plain text: You might |
| want to use HTML tags (or other markup) in the formatted values, |
| such as coloring negative numbers to red or using HTML |
| <literal>sup</literal> element for exponents. This is possible |
| if you write a custom format as shown in previous cases, but |
| override the <literal>format</literal> method in the formatter |
| class so that it returns a |
| <literal>TemplateMarkupOutputModel</literal> instead of a |
| <literal>String</literal>. (You shouldn't just return the markup |
| as <literal>String</literal>, as then it might will be escaped; |
| see <link |
| linkend="dgui_misc_autoescaping">auto-escaping</link>.)</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Custom formats can be registered with the |
| <literal>custom_number_formats</literal> and |
| <literal>custom_date_formats</literal> configuration settings. After |
| that, anywhere where you can specify formats with a |
| <literal>String</literal>, now you can refer to your custom format |
| as <literal>"@<replaceable>name</replaceable>"</literal>. So for |
| example, if you have registered your number format implementation |
| with name <literal>"smart"</literal>, then you could set the |
| <literal>number_format</literal> setting |
| (<literal>Configurable.setNumberFormat(String)</literal>) to |
| <literal>"@smart"</literal>, or issue |
| <literal>${n?string.@smart}</literal> or <literal><#setting |
| number_format="@smart"></literal> in a template. Furthermore, you |
| can define parameters for your custom format, like <literal>"@smart |
| 2"</literal>, and the interpretation of the parameters is up to your |
| formatter implementation.</para> |
| </section> |
| |
| <section xml:id="pgui_config_custom_formats_ex_cust_alg_simple"> |
| <title>Simple custom number format example</title> |
| |
| <para>This custom number format shows numbers in hexadecimal |
| form:</para> |
| |
| <programlisting role="unspecified">package com.example; |
| |
| import java.util.Locale; |
| |
| import freemarker.template.TemplateModelException; |
| import freemarker.template.TemplateNumberModel; |
| import freemarker.template.utility.NumberUtil; |
| |
| public class HexTemplateNumberFormatFactory extends TemplateNumberFormatFactory { |
| |
| public static final HexTemplateNumberFormatFactory INSTANCE |
| = new HexTemplateNumberFormatFactory(); |
| |
| private HexTemplateNumberFormatFactory() { |
| // Defined to decrease visibility |
| } |
| |
| @Override |
| public TemplateNumberFormat get(String params, Locale locale, Environment env) |
| throws InvalidFormatParametersException { |
| TemplateFormatUtil.checkHasNoParameters(params); |
| return HexTemplateNumberFormat.INSTANCE; |
| } |
| |
| private static class HexTemplateNumberFormat extends TemplateNumberFormat { |
| |
| private static final HexTemplateNumberFormat INSTANCE = new HexTemplateNumberFormat(); |
| |
| private HexTemplateNumberFormat() { } |
| |
| @Override |
| public String formatToPlainText(TemplateNumberModel numberModel) |
| throws UnformattableValueException, TemplateModelException { |
| Number n = TemplateFormatUtil.getNonNullNumber(numberModel); |
| try { |
| return Integer.toHexString(NumberUtil.toIntExact(n)); |
| } catch (ArithmeticException e) { |
| throw new UnformattableValueException(n + " doesn't fit into an int"); |
| } |
| } |
| |
| @Override |
| public boolean isLocaleBound() { |
| return false; |
| } |
| |
| @Override |
| public String getDescription() { |
| return "hexadecimal int"; |
| } |
| |
| } |
| |
| }</programlisting> |
| |
| <para>We register the above format with name |
| <quote>hex</quote>:</para> |
| |
| <programlisting role="unspecified">// Where you initalize the application-wide Configuration singleton: |
| Configuration cfg = ...; |
| ... |
| Map<String, TemplateNumberFormatFactory> customNumberFormats = ...; |
| ... |
| customNumberFormats.put("hex", HexTemplateNumberFormatFactory.INSTANCE); |
| ... |
| cfg.setCustomNumberFormats(customNumberFormats);</programlisting> |
| |
| <para>Now we can use this format in templates:</para> |
| |
| <programlisting role="template">${x?string.@hex}</programlisting> |
| |
| <para>or even set it as the default number format:</para> |
| |
| <programlisting role="unspecified">cfg.setNumberFormat("@hex");</programlisting> |
| </section> |
| |
| <section xml:id="pgui_config_custom_formats_ex_cust_algo_advanced"> |
| <title>Advanced custom number format example</title> |
| |
| <para>This is a more complex custom number format that shows how to |
| deal with parameters in the format string, also how to delegate to |
| another format:</para> |
| |
| <programlisting role="unspecified">package com.example; |
| |
| import java.util.Locale; |
| |
| import freemarker.template.TemplateModelException; |
| import freemarker.template.TemplateNumberModel; |
| import freemarker.template.utility.NumberUtil; |
| import freemarker.template.utility.StringUtil; |
| |
| /** |
| * Shows a number in base N number system. Can only format numbers that fit into an {@code int}, |
| * however, optionally you can specify a fallback format. This format has one required parameter, |
| * the numerical system base. That can be optionally followed by "|" and a fallback format. |
| */ |
| public class BaseNTemplateNumberFormatFactory extends TemplateNumberFormatFactory { |
| |
| public static final BaseNTemplateNumberFormatFactory INSTANCE |
| = new BaseNTemplateNumberFormatFactory(); |
| |
| private BaseNTemplateNumberFormatFactory() { |
| // Defined to decrease visibility |
| } |
| |
| @Override |
| public TemplateNumberFormat get(String params, Locale locale, Environment env) |
| throws InvalidFormatParametersException { |
| TemplateNumberFormat fallbackFormat; |
| { |
| int barIdx = params.indexOf('|'); |
| if (barIdx != -1) { |
| String fallbackFormatStr = params.substring(barIdx + 1); |
| params = params.substring(0, barIdx); |
| try { |
| fallbackFormat = env.getTemplateNumberFormat(fallbackFormatStr, locale); |
| } catch (TemplateValueFormatException e) { |
| throw new InvalidFormatParametersException( |
| "Couldn't get the fallback number format (specified after the \"|\"), " |
| + StringUtil.jQuote(fallbackFormatStr) + ". Reason: " + e.getMessage(), |
| e); |
| } |
| } else { |
| fallbackFormat = null; |
| } |
| } |
| |
| int base; |
| try { |
| base = Integer.parseInt(params); |
| } catch (NumberFormatException e) { |
| if (params.length() == 0) { |
| throw new InvalidFormatParametersException( |
| "A format parameter is required to specify the numerical system base."); |
| } |
| throw new InvalidFormatParametersException( |
| "The format paramter must be an integer, but was (shown quoted): " |
| + StringUtil.jQuote(params)); |
| } |
| if (base < 2) { |
| throw new InvalidFormatParametersException("A base must be at least 2."); |
| } |
| return new BaseNTemplateNumberFormat(base, fallbackFormat); |
| } |
| |
| private static class BaseNTemplateNumberFormat extends TemplateNumberFormat { |
| |
| private final int base; |
| private final TemplateNumberFormat fallbackFormat; |
| |
| private BaseNTemplateNumberFormat(int base, TemplateNumberFormat fallbackFormat) { |
| this.base = base; |
| this.fallbackFormat = fallbackFormat; |
| } |
| |
| @Override |
| public String formatToPlainText(TemplateNumberModel numberModel) |
| throws TemplateModelException, TemplateValueFormatException { |
| Number n = TemplateFormatUtil.getNonNullNumber(numberModel); |
| try { |
| return Integer.toString(NumberUtil.toIntExact(n), base); |
| } catch (ArithmeticException e) { |
| if (fallbackFormat == null) { |
| throw new UnformattableValueException( |
| n + " doesn't fit into an int, and there was no fallback format " |
| + "specified."); |
| } else { |
| return fallbackFormat.formatToPlainText(numberModel); |
| } |
| } |
| } |
| |
| @Override |
| public boolean isLocaleBound() { |
| return false; |
| } |
| |
| @Override |
| public String getDescription() { |
| return "base " + base; |
| } |
| |
| } |
| |
| }</programlisting> |
| |
| <para>We register the above format with name |
| <quote>base</quote>:</para> |
| |
| <programlisting role="unspecified">// Where you initalize the application-wide Configuration singleton: |
| Configuration cfg = ...; |
| ... |
| Map<String, TemplateNumberFormatFactory> customNumberFormats = ...; |
| ... |
| customNumberFormats.put("base", BaseNTemplateNumberFormatFactory.INSTANCE); |
| ... |
| cfg.setCustomNumberFormats(customNumberFormats);</programlisting> |
| |
| <para>Now we can use this format in templates:</para> |
| |
| <programlisting role="template">${x?string.@base_8}</programlisting> |
| |
| <para>Above there the parameter string was <literal>"8"</literal>, |
| as FreeMarker allows separating that from the format name with |
| <literal>_</literal> instead of whitespace, so that you don't have |
| to write the longer |
| <literal><replaceable>n</replaceable>?string["@base 8"]</literal> |
| form.</para> |
| |
| <para>Of course, we could also set this as the default number format |
| like:</para> |
| |
| <programlisting role="unspecified">cfg.setNumberFormat("@base 8");</programlisting> |
| |
| <para>Here's an example of using the a fallback number format (which |
| is <literal>"0.0###"</literal>):</para> |
| |
| <programlisting role="unspecified">cfg.setNumberFormat("@base 8|0.0###");</programlisting> |
| |
| <para>Note that this functionality, with the <literal>|</literal> |
| syntax and all, is purely implemented in the example code |
| earlier.</para> |
| </section> |
| |
| <section xml:id="pgui_config_custom_formats_ex_cust_algo_date"> |
| <title>Custom date/time format example</title> |
| |
| <para>This simple date format formats the date/time value to the |
| milliseconds since the epoch:</para> |
| |
| <programlisting role="unspecified">package com.example; |
| |
| import java.util.Date; |
| import java.util.Locale; |
| import java.util.TimeZone; |
| |
| import freemarker.template.TemplateDateModel; |
| import freemarker.template.TemplateModelException; |
| |
| public class EpochMillisTemplateDateFormatFactory extends TemplateDateFormatFactory { |
| |
| public static final EpochMillisTemplateDateFormatFactory INSTANCE |
| = new EpochMillisTemplateDateFormatFactory(); |
| |
| private EpochMillisTemplateDateFormatFactory() { |
| // Defined to decrease visibility |
| } |
| |
| @Override |
| public TemplateDateFormat get(String params, int dateType, |
| Locale locale, TimeZone timeZone, boolean zonelessInput, |
| Environment env) |
| throws InvalidFormatParametersException { |
| TemplateFormatUtil.checkHasNoParameters(params); |
| return EpochMillisTemplateDateFormat.INSTANCE; |
| } |
| |
| private static class EpochMillisTemplateDateFormat extends TemplateDateFormat { |
| |
| private static final EpochMillisTemplateDateFormat INSTANCE |
| = new EpochMillisTemplateDateFormat(); |
| |
| private EpochMillisTemplateDateFormat() { } |
| |
| @Override |
| public String formatToPlainText(TemplateDateModel dateModel) |
| throws UnformattableValueException, TemplateModelException { |
| return String.valueOf(TemplateFormatUtil.getNonNullDate(dateModel).getTime()); |
| } |
| |
| @Override |
| public boolean isLocaleBound() { |
| return false; |
| } |
| |
| @Override |
| public boolean isTimeZoneBound() { |
| return false; |
| } |
| |
| @Override |
| public Date parse(String s, int dateType) throws UnparsableValueException { |
| try { |
| return new Date(Long.parseLong(s)); |
| } catch (NumberFormatException e) { |
| throw new UnparsableValueException("Malformed long"); |
| } |
| } |
| |
| @Override |
| public String getDescription() { |
| return "millis since the epoch"; |
| } |
| |
| } |
| |
| }</programlisting> |
| |
| <para>We register the above format with name |
| <quote>epoch</quote>:</para> |
| |
| <programlisting role="unspecified">// Where you initalize the application-wide Configuration singleton: |
| Configuration cfg = ...; |
| ... |
| Map<String, TemplateDateFormatFactory> customDateFormats = ...; |
| ... |
| customDateFormats.put("epoch", EpochMillisTemplateDateFormatFactory.INSTANCE); |
| ... |
| cfg.setCustomDateFormats(customDateFormats);</programlisting> |
| |
| <para>Now we can use this format in templates:</para> |
| |
| <programlisting role="template">${t?string.@epoch}</programlisting> |
| |
| <para>Of course, we could also set this as the default date-time |
| format like:</para> |
| |
| <programlisting role="unspecified">cfg.setDateTimeFormat("@epoch");</programlisting> |
| |
| <para>For a more complex that for example uses format parameters, |
| refer to the <link |
| linkend="pgui_config_custom_formats_ex_cust_algo_advanced">advanced |
| number format example</link>. Doing that with date formats is very |
| similar.</para> |
| </section> |
| |
| <section xml:id="pgui_config_custom_formats_ex_alias"> |
| <title>Alias format example</title> |
| |
| <para>In this example we specify some number formats and date |
| formats that are aliases to another format:</para> |
| |
| <programlisting role="unspecified">// Where you initalize the application-wide Configuration singleton: |
| Configuration cfg = ...; |
| |
| Map<String, TemplateNumberFormatFactory> customNumberFormats |
| = new HashMap<String, TemplateNumberFormatFactory>(); |
| customNumberFormats.put("price", new AliasTemplateNumberFormatFactory(",000.00")); |
| customNumberFormats.put("weight", |
| new AliasTemplateNumberFormatFactory("0.##;; roundingMode=halfUp")); |
| cfg.setCustomNumberFormats(customNumberFormats); |
| |
| Map<String, TemplateDateFormatFactory> customDateFormats |
| = new HashMap<String, TemplateDateFormatFactory>(); |
| customDateFormats.put("fileDate", new AliasTemplateDateFormatFactory("dd/MMM/yy hh:mm a")); |
| customDateFormats.put("logEventTime", new AliasTemplateDateFormatFactory("iso ms u")); |
| cfg.setCustomDateFormats(customDateFormats);</programlisting> |
| |
| <para>So now you can do this in a template:</para> |
| |
| <programlisting role="template">${product.price?string.@price} |
| ${product.weight?string.@weight} |
| ${lastModified?string.@fileDate} |
| ${lastError.timestamp?string.@logEventTime}</programlisting> |
| |
| <para>Note that the constructor parameter of |
| <literal>AliasTemplateNumberFormatFactory</literal> can naturally |
| refer to a custom format too:</para> |
| |
| <programlisting role="unspecified">Map<String, TemplateNumberFormatFactory> customNumberFormats |
| = new HashMap<String, TemplateNumberFormatFactory>(); |
| customNumberFormats.put("base", BaseNTemplateNumberFormatFactory.INSTANCE); |
| customNumberFormats.put("oct", new AliasTemplateNumberFormatFactory("@base 8")); |
| cfg.setCustomNumberFormats(customNumberFormats);</programlisting> |
| |
| <para>So now |
| <literal><replaceable>n</replaceable>?string.@oct</literal> will |
| format the number to octal form.</para> |
| </section> |
| |
| <section xml:id="pgui_config_custom_formats_ex_model_aware"> |
| <title>Model-aware format example</title> |
| |
| <para>In this example we specify a number format that automatically |
| show the unit after the number if that was put into the data-model |
| as <literal>UnitAwareTemplateNumberModel</literal>. First let's see |
| <literal>UnitAwareTemplateNumberModel</literal>:</para> |
| |
| <programlisting role="unspecified">package com.example; |
| |
| import freemarker.template.TemplateModelException; |
| import freemarker.template.TemplateNumberModel; |
| |
| public class UnitAwareTemplateNumberModel implements TemplateNumberModel { |
| |
| private final Number value; |
| private final String unit; |
| |
| public UnitAwareTemplateNumberModel(Number value, String unit) { |
| this.value = value; |
| this.unit = unit; |
| } |
| |
| @Override |
| public Number getAsNumber() throws TemplateModelException { |
| return value; |
| } |
| |
| public String getUnit() { |
| return unit; |
| } |
| |
| }</programlisting> |
| |
| <para>When you fill the data-model, you could do something like |
| this:</para> |
| |
| <programlisting role="unspecified">Map<String, Object> dataModel = new HashMap<>(); |
| dataModel.put("weight", new UnitAwareTemplateNumberModel(1.5, "kg")); |
| // Rather than just: dataModel.put("weight", 1.5);</programlisting> |
| |
| <para>Then if we have this in the template:</para> |
| |
| <programlisting role="template">${weight}</programlisting> |
| |
| <para>we want to see this:</para> |
| |
| <programlisting role="output">1.5 kg</programlisting> |
| |
| <para>To achieve that, we define this custom number format:</para> |
| |
| <programlisting role="unspecified">package com.example; |
| |
| import java.util.Locale; |
| |
| import freemarker.core.Environment; |
| import freemarker.core.TemplateNumberFormat; |
| import freemarker.core.TemplateNumberFormatFactory; |
| import freemarker.core.TemplateValueFormatException; |
| import freemarker.template.TemplateModelException; |
| import freemarker.template.TemplateNumberModel; |
| |
| /** |
| * A number format that takes any other number format as parameter (specified as a string, as |
| * usual in FreeMarker), then if the model is a {@link UnitAwareTemplateNumberModel}, it shows |
| * the unit after the number formatted with the other format, otherwise it just shows the formatted |
| * number without unit. |
| */ |
| public class UnitAwareTemplateNumberFormatFactory extends TemplateNumberFormatFactory { |
| |
| public static final UnitAwareTemplateNumberFormatFactory INSTANCE |
| = new UnitAwareTemplateNumberFormatFactory(); |
| |
| private UnitAwareTemplateNumberFormatFactory() { |
| // Defined to decrease visibility |
| } |
| |
| @Override |
| public TemplateNumberFormat get(String params, Locale locale, Environment env) |
| throws TemplateValueFormatException { |
| return new UnitAwareNumberFormat(env.getTemplateNumberFormat(params, locale)); |
| } |
| |
| private static class UnitAwareNumberFormat extends TemplateNumberFormat { |
| |
| private final TemplateNumberFormat innerFormat; |
| |
| private UnitAwareNumberFormat(TemplateNumberFormat innerFormat) { |
| this.innerFormat = innerFormat; |
| } |
| |
| @Override |
| public String formatToPlainText(TemplateNumberModel numberModel) |
| throws TemplateModelException, TemplateValueFormatException { |
| String innerResult = innerFormat.formatToPlainText(numberModel); |
| return numberModel instanceof UnitAwareTemplateNumberModel |
| ? innerResult + " " + ((UnitAwareTemplateNumberModel) numberModel).getUnit() |
| : innerResult; |
| } |
| |
| @Override |
| public boolean isLocaleBound() { |
| return innerFormat.isLocaleBound(); |
| } |
| |
| @Override |
| public String getDescription() { |
| return "unit-aware " + innerFormat.getDescription(); |
| } |
| |
| } |
| |
| }</programlisting> |
| |
| <para>Finally, we set the above custom format as the default number |
| format:</para> |
| |
| <programlisting role="unspecified">// Where you initalize the application-wide Configuration singleton: |
| Configuration cfg = ...; |
| |
| Map<String, TemplateNumberFormatFactory> customNumberFormats = new HashMap<>(); |
| customNumberFormats.put("ua", UnitAwareTemplateNumberFormatFactory.INSTANCE); |
| cfg.setCustomNumberFormats(customNumberFormats); |
| |
| // Note: "0.####;; roundingMode=halfUp" is a standard format specified in FreeMarker. |
| cfg.setNumberFormat("@ua 0.####;; roundingMode=halfUp");</programlisting> |
| </section> |
| </section> |
| |
| <section xml:id="pgui_config_incompatible_improvements"> |
| <title>The "incompatible improvements" setting</title> |
| |
| <indexterm> |
| <primary>incompatible improvements</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>incompatible_improvements</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>incompatibleImprovements</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>backward compatibility</primary> |
| </indexterm> |
| |
| <section> |
| <title>What does it do</title> |
| |
| <para>This setting specifies the FreeMarker version number where the |
| not 100% backward compatible bug fixes and improvements |
| <emphasis>that you want to enable</emphasis> were already |
| implemented. Usually, it's a bad idea to left it on its default, |
| which is 2.3.0 (maximum backward compatibility).</para> |
| |
| <para>In new projects you should set this to the fixed FreeMarker |
| version (like <literal>Configuration.VERSION_2_3_28</literal>) that |
| you are actually using when starting the project. In older projects |
| it's also usually better to keep this high , however you should |
| check the changes activated (find them in <link |
| xlink:href="https://freemarker.apache.org/docs/api/freemarker/template/Configuration.html#Configuration-freemarker.template.Version-">the |
| API JavaDoc of the <literal>Configuration(Version)</literal> |
| constructor</link>), especially if not only the 3rd version number |
| (the micro version) of <quote>incompatible improvements</quote> |
| setting is increased. Generally, as far as you only increase the |
| last (3rd) version number of this setting, the changes are low risk, |
| and whether you can afford that risk depends on the concrete |
| application. Never use a dynamic value like |
| <literal>Configuration.getVersion()</literal> though, as that way |
| upgrading FreeMarker can break your application!</para> |
| |
| <para>Bug fixes and improvements that are fully backward compatible, |
| also those that are important security fixes, are enabled regardless |
| of the <quote>incompatible improvements</quote> setting.</para> |
| |
| <para>An important consequence of setting this setting is that now |
| your application will check if the stated minimum FreeMarker version |
| requirement is met. Like if you set this setting to 2.3.22, but |
| accidentally the application is deployed with FreeMarker 2.3.21, |
| then FreeMarker will fail, telling that a higher version is |
| required. After all, the fixes/improvements you have requested |
| aren't available on a lower version.</para> |
| </section> |
| |
| <section xml:id="pgui_config_incompatible_improvements_how_to_set"> |
| <title>How to set it</title> |
| |
| <para>The incompatible improvements setting exists on the |
| <literal>Configuration</literal> level. It can be set on multiple |
| ways:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Create the |
| <literal>freemarker.template.Configuration</literal> object |
| like:</para> |
| |
| <programlisting role="unspecified">... = new Configuration(Configuration.VERSION_2_3_28)</programlisting> |
| </listitem> |
| |
| <listitem> |
| <para>Or, alter the <literal>Configuration</literal> singleton |
| where you initialize its other settings like:</para> |
| |
| <programlisting role="unspecified">cfg.setIncompatibleImprovements(Configuration.VERSION_2_3_28)</programlisting> |
| </listitem> |
| |
| <listitem> |
| <para>Or, if you are configuring FreeMarker with properties |
| (<literal>*.properties</literal> file or |
| <literal>java.util.Properties</literal> object), add:</para> |
| |
| <programlisting role="unspecified">incompatible_improvements=2.3.28</programlisting> |
| </listitem> |
| |
| <listitem> |
| <para>Or, if you are configuring FreeMarker through |
| <literal>FreemarkerServlet</literal>, add this |
| <literal>init-param</literal> to it in the |
| <literal>web.xml</literal>:</para> |
| |
| <programlisting role="unspecified"><init-param> |
| <param-name>incompatible_improvements</param-name> |
| <param-value>2.3.28</param-value> |
| </init-param></programlisting> |
| </listitem> |
| </itemizedlist> |
| |
| <para>But, <emphasis>if you set the |
| <literal>object_wrapper</literal> setting</emphasis> (same as |
| <literal>Configuration.setObjectWrapper(ObjectWrapper)</literal>) of |
| your configuration, then it's important to know that |
| <literal>BeansWrapper</literal> and its subclasses (most |
| importantly, <literal>DefaultObjectWrapper</literal>) has its own |
| independent <literal>incompatibleImprovements</literal> property, |
| and some fixes/improvements are activated by that, not by |
| <literal>Configuration</literal>'s similar setting. You don't have |
| to be aware of this complication if you aren't setting the |
| <literal>object_wrapper</literal> configuration setting anywhere, |
| because the default <literal>object_wrapper</literal> has the same |
| <quote>incompatible improvements</quote> as of the |
| <literal>Configuration</literal>. But if you are setting the |
| <literal>object_wrapper</literal>, then you must not forget to set |
| the <literal>incompatibleImprovements</literal> property of the |
| <literal>ObjectWrapper</literal> itself, in additionally to that of |
| the <literal>Configuration</literal>. (Note that it's fine to have |
| different <quote>incompatible improvements</quote> for the |
| <literal>Configuration</literal> and for the |
| <literal>ObjectWrapper</literal>, only it should be a conscious |
| decision.) <link |
| linkend="topic.setDefaultObjectWrapperIcIIndividually">See here how |
| to set it</link> in the case of |
| <literal>DefaultObjectWrapper</literal> (for |
| <literal>BeansWrapper</literal> it's the same, only with different |
| class name of course).</para> |
| |
| <warning> |
| <para>Do not ever use |
| <literal>Configuration.getVersion()</literal> to set the |
| <quote>incompatible improvements</quote> setting. Always use a |
| fixed value, like <literal>Configuration.VERSION_2_3_28</literal>. |
| Otherwise your application can break as you upgrade FreeMarker. |
| The whole point of <quote>incompatible improvements</quote> is to |
| protect you from that, while you still always get the |
| fixes/improvements that are backward compatible.</para> |
| </warning> |
| </section> |
| </section> |
| </chapter> |
| |
| <chapter xml:id="pgui_misc"> |
| <title>Miscellaneous</title> |
| |
| <para>This is just an introductory guide. See the <olink |
| targetdoc="api">FreeMarker Java API documentation</olink> for the |
| details.</para> |
| |
| <section xml:id="pgui_misc_var"> |
| <title>Variables, scopes</title> |
| |
| <indexterm> |
| <primary>variables</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>variable scopes</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>scopes</primary> |
| </indexterm> |
| |
| <para>This chapter explains what happens when a template tries to |
| access a variable, and how the variables are stored.</para> |
| |
| <para>When you call <literal>Template.process</literal> it will |
| internally create an <literal>Environment</literal> object that will |
| be in use until <literal>process</literal> returns. This object stores |
| the runtime state of template processing. Among other things, it |
| stores the variables created by the template with directives like |
| <literal>assign</literal>, <literal>macro</literal>, |
| <literal>local</literal> or <literal>global</literal>. It never tries |
| to modify the data-model object that you pass to the |
| <literal>process</literal> call, nor does it create or replace shared |
| variables stored in the configuration.</para> |
| |
| <para>When you try to read a variable, FreeMarker will seek the |
| variable in this order, and stops when it finds a variable with the |
| right name:</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>In the Environment:</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>If you are in a loop, in the set of loop variables. Loop |
| variables are the variables created by directives like |
| <literal>list</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If you are inside a macro, in the local variable set of |
| the macro. Local variables can be created with the |
| <literal>local</literal> directive. Also, the parameters of |
| macros are local variables.</para> |
| </listitem> |
| |
| <listitem> |
| <para>In the current <link |
| linkend="dgui_misc_namespace">namespace</link>. You can put |
| variables into a namespace with the <literal>assign</literal> |
| directive.</para> |
| </listitem> |
| |
| <listitem> |
| <para>In the set of variables created with |
| <literal>global</literal> directive. FTL handles these |
| variables as if they were normal members of the data-model. |
| That is, they are visible in all namespaces, and you can |
| access them as if they would be in the data-model.</para> |
| </listitem> |
| </orderedlist> |
| </listitem> |
| |
| <listitem> |
| <para>In the data-model object you have passed to the |
| <literal>process</literal> method</para> |
| </listitem> |
| |
| <listitem> |
| <para>In the set of shared variables stored in the |
| <literal>Configuration</literal></para> |
| </listitem> |
| </orderedlist> |
| |
| <para>In practice, from the viewpoint of template authors these 6 |
| layers are only 4 layers, since from that viewpoint the last 3 layers |
| (variables created with <literal>global</literal>, the actual |
| data-model object, shared variables) together constitute the set of |
| global variables.</para> |
| |
| <para>Note that it is possible to get variables from a specific layer |
| in FTL with <link linkend="ref_specvar">special |
| variables</link>.</para> |
| </section> |
| |
| <section xml:id="pgui_misc_charset"> |
| <title>Charset issues</title> |
| |
| <indexterm> |
| <primary>charset</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>encoding</primary> |
| </indexterm> |
| |
| <para>FreeMarker, as most Java applications, works with "<link |
| linkend="gloss.unicode">UNICODE</link> text" (UTF-16). Nonetheless, |
| there are situations when it must deal with <link |
| linkend="gloss.charset">charsets</link>, because it has to exchange |
| data with the outer world that may use various other charsets.</para> |
| |
| <section> |
| <title>The charset of the input</title> |
| |
| <para>When FreeMarker has to load a template file (or an unparsed |
| text file), then it must know the charset of the file, since files |
| are just raw byte sequences. You can use the |
| <literal>encoding</literal> <link |
| linkend="pgui_config_settings">setting</link> to specify the |
| charset. This setting takes effect only when FreeMarker loads a |
| template (parsed or unparsed) with the |
| <literal>getTemplate</literal> method of |
| <literal>Configuration</literal>. Note that the <link |
| linkend="ref.directive.include"><literal>include</literal> |
| directive</link> uses this method internally, so the value of the |
| <literal>encoding</literal> setting is significant for an already |
| loaded template if the template contains <literal>include</literal> |
| directive call.</para> |
| |
| <para>The getter and setter method of the |
| <literal>encoding</literal> setting is special in the first |
| (configuration) layer. The getter method guesses the return value |
| based on a <literal>Locale</literal> passed as parameter; it looks |
| up the encoding in a table that maps locales to encodings (called |
| encoding map), and if the locale was not found there, it returns the |
| default encoding. You can fill the encoding map with the |
| <literal>setEncoding(Locale locale, String encoding)</literal> |
| method of the configuration; the encoding map is initially empty. |
| The default encoding is initially the value of the |
| <literal>file.encoding</literal> system property, but you always |
| should set a default default with the |
| <literal>setDefaultEncoding</literal> method, rather than relying on |
| that. For new projects, a popular default encoding is |
| <literal>utf-8</literal>.</para> |
| |
| <para>You can give the charset directly by overriding the |
| <literal>encoding</literal> setting in the template layer or runtime |
| environment layer (When you specify an encoding as the parameter of |
| <literal>getTemplate</literal> method, you override the |
| <literal>encoding</literal> setting in the template layer.). If you |
| don't override it, the effective value will be what the |
| <literal>configuration.getEncoding(Locale)</literal> method returns |
| for the effective value of the <literal>locale</literal> |
| setting.</para> |
| |
| <para>Also, instead of relying on this charset guessing mechanism, |
| you can specify the charset of the template in the template file |
| itself, with the <link linkend="ref.directive.ftl"><link |
| linkend="ref.directive.ftl"><literal>ftl</literal></link> |
| directive</link>, like <literal><#ftl |
| encoding="utf-8"></literal>.</para> |
| |
| <para>Note that the charset of the template is independent from the |
| charset of the output that the tempalte generates (unless the |
| enclosing software deliberately sets the output charset to the same |
| as the template charset).</para> |
| </section> |
| |
| <section> |
| <title>The charset of the output</title> |
| |
| <note> |
| <para>The <literal>output_encoding</literal> setting/variable and |
| the <link linkend="ref_builtin_url"><literal>url</literal> |
| built-in</link> is available since FreeMarker 2.3.1. It doesn't |
| exist in 2.3.</para> |
| </note> |
| |
| <para><indexterm> |
| <primary>output encoding</primary> |
| </indexterm><indexterm> |
| <primary>output charset</primary> |
| </indexterm>In principle FreeMarker does not deal with the charset |
| of the output, since it writes the output to a |
| <literal>java.io.Writer</literal>. Since the |
| <literal>Writer</literal> is made by the software that encapsulates |
| FreeMarker (such as a Web application framework), the output charset |
| is controlled by the encapsulating software. Still, FreeMarker has a |
| setting called <literal>output_encoding</literal> (starting from |
| FreeMarker version 2.3.1). The enclosing software should set this |
| setting (to the charset that the <literal>Writer</literal> uses), to |
| inform FreeMarker what charset is used for the output (otherwise |
| FreeMarker can't find it out). Some features, such as the <link |
| linkend="ref_builtin_url"><literal>url</literal> built-in</link>, |
| and the <link |
| linkend="ref_specvar"><literal>output_encoding</literal> special |
| variable</link> utilize this information. Thus, if the enclosing |
| software doesn't set this setting then FreeMarker features that need |
| to know the output charset can't be used.</para> |
| |
| <para>If you write software that will use FreeMarker, you may wonder |
| what output charset should you choose. Of course it depends on the |
| consumer of the FreeMarker output, but if the consumer is flexible |
| regarding this question, then the common practice is either using |
| the charset of the template file for the output, or using UTF-8. |
| Using UTF-8 is usually a better practice, because arbitrary text may |
| comes from the data-model, which then possibly contains characters |
| that couldn't be encoded with the charset of the template.</para> |
| |
| <para>FreeMarker settings can be set for each individual template |
| processing if you use |
| <literal>Template.createProcessingEnvironment(<replaceable>...</replaceable>)</literal> |
| plus |
| <literal>Environment.process(<replaceable>...</replaceable>)</literal> |
| instead of |
| <literal>Template.process(<replaceable>...</replaceable>)</literal>. |
| Thus, you can set the <literal>output_encoding</literal> setting for |
| each template execution independently:</para> |
| |
| <programlisting role="unspecified">Writer w = new OutputStreamWriter(out, outputCharset); |
| Environment env = template.createProcessingEnvironment(dataModel, w); |
| env.setOutputEncoding(outputCharset); |
| env.process();</programlisting> |
| </section> |
| </section> |
| |
| <section xml:id="pgui_misc_multithreading"> |
| <title>Multithreading</title> |
| |
| <indexterm> |
| <primary>multithreading</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>thread-safety</primary> |
| </indexterm> |
| |
| <para>In a multithreaded environment <literal>Configuration</literal> |
| instances, <literal>Template</literal> instances and data-models |
| should be handled as immutable (read-only) objects. That is, you |
| create and initialize them (for example with |
| <literal>set<replaceable>...</replaceable></literal> methods), and |
| then you don't modify them later (e.g. you don't call |
| <literal>set<replaceable>...</replaceable></literal>). This allows us |
| to avoid expensive synchronized blocks in a multithreaded environment. |
| Beware with <literal>Template</literal> instances; when you get a |
| <literal>Template</literal> instance with |
| <literal>Configuration.getTemplate</literal>, you may get an instance |
| from the template cache that is already used by other threads, so do |
| not call its <literal>set<replaceable>...</replaceable></literal> |
| methods (calling <literal>process</literal> is of course fine).</para> |
| |
| <para>The above restrictions do not apply if you access all objects |
| from the <emphasis>same</emphasis> single thread only.</para> |
| |
| <para>It is impossible to modify the data-model object or a <link |
| linkend="pgui_config_sharedvariables">shared variable</link> with FTL, |
| unless you put methods (or other objects) into the data-model that do |
| that. We discourage you from writing methods that modify the |
| data-model object or the shared variables. Try to use variables that |
| are stored in the environment object instead (this object is created |
| for a single <literal>Template.process</literal> call to store the |
| runtime state of processing), so you don't modify data that are |
| possibly used by multiple threads. For more information read: <xref |
| linkend="pgui_misc_var"/></para> |
| </section> |
| |
| <section xml:id="pgui_misc_beanwrapper"> |
| <title>Bean wrapper</title> |
| |
| <indexterm> |
| <primary>wrapping</primary> |
| |
| <secondary>reflection</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>wrapping</primary> |
| |
| <secondary>beans</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>beans</primary> |
| |
| <secondary>wrapping</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>BeansWrapper</primary> |
| </indexterm> |
| |
| <note> |
| <para>Using <literal>BeansWrapper</literal> directly is not |
| recommended anymore. Use its subclass, |
| <literal>DefaultObjectWrapper</literal> instead, though by ensuring |
| that its <literal>incompatibleImprovements</literal> property is at |
| least 2.3.22. <literal>DefaultObjectWrapper</literal> gives cleaner |
| data-model (less confusing multi-type FTL values) and is usually |
| faster. <link linkend="pgui_datamodel_defaultObjectWrapper">See more |
| about DefaultObjectWrapper here...</link></para> |
| </note> |
| |
| <para>The <literal>freemarker.ext.beans.BeansWrapper</literal> is an |
| <link linkend="pgui_datamodel_objectWrapper">object wrapper</link> |
| that was originally added to FreeMarker so arbitrary POJO-s (Plain Old |
| Java Objects) can be wrapped into <literal>TemplateModel</literal> |
| interfaces. Since then it has became the normal way of doing things, |
| and in fact the <literal>DefaultObjectWrapper</literal> itself is a |
| <literal>BeansWrapper</literal> extension. So everything described |
| here goes for the <literal>DefaultObjectWrapper</literal> too, except |
| that the <literal>DefaultObjectWrapper</literal> will wrap |
| <literal>String</literal>, <literal>Number</literal>, |
| <literal>Date</literal>, <literal>array</literal>, |
| <literal>Collection</literal> (like <literal>List</literal>), |
| <literal>Map</literal>, <literal>Boolean</literal> and |
| <literal>Iterator</literal> objects with the |
| <literal>freemarker.template.Simple<replaceable>Xxx</replaceable></literal> |
| classes, and W3C DOM nodes with |
| <literal>freemarker.ext.dom.NodeModel</literal> (<link |
| linkend="xgui">more about wrapped W3C DOM...</link>), so for those the |
| above described rules doesn't apply.</para> |
| |
| <para>You will want to use <literal>BeansWrapper</literal> instead of |
| <literal>DefaultObjectWrapper</literal> when any of these |
| stands:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The <literal>Collection</literal>-s and |
| <literal>Map</literal>-s of the model should be allowed to be |
| modified during template execution. |
| (<literal>DefaultObjectWrapper</literal> prevents that, since it |
| creates a copy of the collections when they are wrapped, and the |
| copies will be read-only.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>If the identity of the <literal>array</literal>, |
| <literal>Collection</literal> and <literal>Map</literal> objects |
| must be kept when they are passed to a wrapped object's method in |
| the template. That is, if those methods must get exactly the same |
| object that was earlier wrapped.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If the Java API of the earlier listed classes |
| (<literal>String</literal>, <literal>Map</literal>, |
| <literal>List</literal> ...etc) should be visible for the |
| templates. Even with <literal>BeansWrapper</literal>, they are not |
| visible by default, but it can be achieved by setting the exposure |
| level (see later). Note that this is usually a bad practice; try |
| to use <link linkend="ref_builtins">the built-ins</link> (like |
| <literal>foo?size</literal>, <literal>foo?upper_case</literal>, |
| <literal>foo?replace('_', '-')</literal> ...etc) instead of the |
| Java API.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Below is a summary of the <literal>TemplateModel</literal>-s |
| that the <literal>BeansWrapper</literal> creates. Let's assume that |
| the object is called <literal>obj</literal> before wrapping, and |
| <literal>model</literal> after wrapping for the sake of the following |
| discussion.</para> |
| |
| <section xml:id="beanswrapper_hash"> |
| <title>TemplateHashModel functionality</title> |
| |
| <para>Every object will be wrapped into a |
| <literal>TemplateHashModel</literal> that will expose JavaBeans |
| properties and methods of the object. This way, you can use |
| <literal>model.foo</literal> in the template to invoke |
| <literal>obj.getFoo()</literal> or <literal>obj.isFoo()</literal> |
| methods. (Note that public fields are not visible directly; you must |
| write a getter method for them.) Public methods are also retrievable |
| through the hash model as template method models, therefore you can |
| use the <literal>model.doBar()</literal> to invoke |
| <literal>object.doBar()</literal>. More on this on discussion of |
| method model functionality.</para> |
| |
| <para>If the requested key can not be mapped to a bean property or |
| method, the framework will attempt to locate the so-called "generic |
| get method", that is a method with signature public |
| <literal><replaceable>any-return-type</replaceable> |
| get(String)</literal> or public |
| <literal><replaceable>any-return-type</replaceable> |
| get(Object)</literal> and invoke that method with the requested key. |
| Note that this allows convenient access to mappings in a |
| <literal>java.util.Map</literal> and similar classes - as long as |
| the keys of the map are <literal>String</literal>s and some property |
| or method name does not shadow the mapping. (There is a solution to |
| avoid shadowing, read on.) Also note that the models for |
| <literal>java.util.ResourceBundle</literal> objects use the |
| <literal>getObject(String)</literal> as the generic get |
| method.</para> |
| |
| <para>If you call <literal>setExposeFields(true)</literal> on a |
| <literal>BeansWrapper</literal> instance, it will also expose |
| public, non-static fields of classes as hash keys and values. I.e. |
| if <literal>foo</literal> is a public, non-static field of the class |
| <literal>Bar</literal>, and <literal>bar</literal> is a template |
| variable wrapping an instance of <literal>Bar</literal>, then |
| <literal>bar.foo</literal> expression will evaluate as the value of |
| the field <literal>foo</literal> of the <literal>bar</literal> |
| object. The public fields in all superclasses of the class are also |
| exposed.</para> |
| </section> |
| |
| <section> |
| <title>A word on security</title> |
| |
| <para>By default, you will not be able to access several methods |
| that are considered not safe for templating. For instance, you can't |
| use synchronization methods (<literal>wait</literal>, |
| <literal>notify</literal>, <literal>notifyAll</literal>), thread and |
| thread group management methods (<literal>stop</literal>, |
| <literal>suspend</literal>, <literal>resume</literal>, |
| <literal>setDaemon</literal>, <literal>setPriority</literal>), |
| reflection (<literal>Field</literal> |
| <literal>set<replaceable>Xxx</replaceable></literal> methods, |
| <literal>Method.invoke</literal>, |
| <literal>Constructor.newInstance</literal>, |
| <literal>Class.newInstance</literal>, |
| <literal>Class.getClassLoader</literal> etc.) and various dangerous |
| methods in <literal>System</literal> and <literal>Runtime</literal> |
| classes (<literal>exec</literal>, <literal>exit</literal>, |
| <literal>halt</literal>, <literal>load</literal>, etc.). The |
| <literal>BeansWrapper</literal> has several security levels (called |
| "levels of method exposure"), and the default called |
| <literal>EXPOSE_SAFE</literal> is probably suited for most |
| applications. There is a no-safeguard level called |
| <literal>EXPOSE_ALL</literal> that allows you to call even the above |
| unsafe methods, and a strict level |
| <literal>EXPOSE_PROPERTIES_ONLY</literal> that will expose only bean |
| property getters. Finally, there is a level named |
| <literal>EXPOSE_NOTHING</literal> that will expose no properties and |
| no methods. The only data you will be able to access through hash |
| model interface in this case are items in maps and resource bundles, |
| as well as objects returned from a call to generic |
| <literal>get(Object)</literal> or <literal>get(String)</literal> |
| methods - provided the affected objects have such method.</para> |
| </section> |
| |
| <section> |
| <title>TemplateScalarModel functionality</title> |
| |
| <para>Models for <literal>java.lang.String</literal> objects will |
| implement <literal>TemplateScalarModel</literal> whose |
| <literal>getAsString()</literal> method simply delegates to |
| <literal>toString()</literal>. Note that wrapping |
| <literal>String</literal> objects into Bean wrappers provides much |
| more functionality than just them being scalars: because of the hash |
| interface described above, the models that wrap |
| <literal>String</literal>s also provide access to all |
| <literal>String</literal> methods (<literal>indexOf</literal>, |
| <literal>substring</literal>, etc.), though most of them has native |
| FreeMarker equivalent which are better to use |
| (<literal>s?index_of(n)</literal>, |
| <literal>s[start..<end]</literal>, etc).</para> |
| </section> |
| |
| <section> |
| <title>TemplateNumberModel functionality</title> |
| |
| <para>Model wrappers for objects that are instances of |
| <literal>java.lang.Number</literal> implement |
| <literal>TemplateNumberModel</literal> whose |
| <literal>getAsNumber()</literal> method returns the wrapped number |
| object. Note that wrapping <literal>Number</literal> objects into |
| Bean wrappers provides much more functionality than just them being |
| number models: because of the hash interface described above, the |
| models that wrap <literal>Number</literal>s also provide access to |
| all their methods.</para> |
| </section> |
| |
| <section> |
| <title>TemplateCollectionModel functionality</title> |
| |
| <para>Model wrappers for native Java arrays and all classes that |
| implement <literal>java.util.Collection</literal> will implement |
| <literal>TemplateCollectionModel</literal> and thus gain the |
| additional capability of being usable through |
| <literal>list</literal> directive.</para> |
| </section> |
| |
| <section> |
| <title>TemplateSequenceModel functionality</title> |
| |
| <para>Model wrappers for native Java arrays and all classes that |
| implement <literal>java.util.List</literal> will implement |
| <literal>TemplateSequenceModel</literal> and thus their elements |
| will be accessible by index using the <literal>model[i]</literal> |
| syntax. You can also query the length of the array or the size of |
| the list using the <literal>model?size</literal> built-in.</para> |
| |
| <para>Also, every method that takes a single parameter that is |
| assignable through reflective method invocation from a |
| <literal>java.lang.Integer</literal> (these are |
| <literal>int</literal>, <literal>long</literal>, |
| <literal>float</literal>, <literal>double</literal>, |
| <literal>java.lang.Object</literal>, |
| <literal>java.lang.Number</literal>, and |
| <literal>java.lang.Integer</literal>) also implements this |
| interface. What this means is that you have a convenient way for |
| accessing the so-called indexed bean properties: |
| <literal>model.foo[i]</literal> will translate into |
| <literal>obj.getFoo(i)</literal>.</para> |
| </section> |
| |
| <section xml:id="beanswrapper_method"> |
| <title>TemplateMethodModel functionality</title> |
| |
| <para>All methods of an object are represented as |
| <literal>TemplateMethodModelEx</literal> objects accessible using a |
| hash key with method name on their object's model. When you call a |
| method using |
| <literal>model.<replaceable>method</replaceable>(<replaceable>arg1</replaceable>, |
| <replaceable>arg2</replaceable>, |
| <replaceable>...</replaceable>)</literal> the arguments are passed |
| to the method as template models. The method will first try to |
| unwrap them - see below for details about unwrapping. These |
| unwrapped arguments are then used for the actual method call. In |
| case the method is overloaded, the most specific method will be |
| selected using the same rules that are used by the Java compiler to |
| select a method from several overloaded methods. In case that no |
| method signature matches the passed parameters, or that no method |
| can be chosen without ambiguity, a |
| <literal>TemplateModelException</literal> is thrown.</para> |
| |
| <para>Methods of return type <literal>void</literal> return |
| <literal>TemplateModel.NOTHING</literal>, so they can be safely |
| called with the <literal>${obj.method(args)}</literal> |
| syntax.</para> |
| |
| <para>Models for instances of <literal>java.util.Map</literal> also |
| implement <literal>TemplateMethodModelEx</literal> as a means for |
| invoking their <literal>get()</literal> method. As it was discussed |
| previously, you can use the hash functionality to access the "get" |
| method as well, but it has several drawbacks: it's slower because |
| first property and method names are checked for the key; keys that |
| conflict with property and method names will be shadowed by them; |
| finally you can use <literal>String</literal> keys only with that |
| approach. In contrast, invoking <literal>model(key)</literal> |
| translates to <literal>model.get(key)</literal> directly: it's |
| faster because there's no property and method name lookup; it is |
| subject to no shadowing; and finally it works for non-String keys |
| since the argument is unwrapped just as with ordinary method calls. |
| In effect, <literal>model(key)</literal> on a <literal>Map</literal> |
| is equal to <literal>model.get(key)</literal>, only shorter to |
| write.</para> |
| |
| <para>Models for <literal>java.util.ResourceBundle</literal> also |
| implement <literal>TemplateMethodModelEx</literal> as a convenient |
| way of resource access and message formatting. A single-argument |
| call to a bundle will retrieve the resource with the name that |
| corresponds to the <literal>toString()</literal> value of the |
| unwrapped argument. A multiple-argument call to a bundle will also |
| retrieve the resource with the name that corresponds to the |
| <literal>toString()</literal> value of the unwrapped argument, but |
| it will use it as a format pattern and pass it to |
| <literal>java.text.MessageFormat</literal> using the unwrapped |
| values of second and later arguments as formatting parameters. |
| <literal>MessageFormat</literal> objects will be initialized with |
| the locale of the bundle that originated them.</para> |
| </section> |
| |
| <section> |
| <title>Unwrapping rules</title> |
| |
| <para>When invoking a Java method from a template, its arguments |
| need to be converted from template models back to Java objects. |
| Assuming that the target type (the declared type of the method's |
| formal parameter) is denoted as <literal>T</literal>, the following |
| rules are tried in the following order:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>If the model is the null model for this wrapper, Java |
| <literal>null</literal> is returned.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If the model implements |
| <literal>AdapterTemplateModel</literal>, the result of |
| <literal>model.getAdaptedObject(T)</literal> is returned if it |
| is instance of <literal>T</literal> or it is a number and can be |
| converted to <literal>T</literal> using numeric coercion as |
| described three bullets lower. <phrase role="forProgrammers">All |
| models created by the BeansWrapper are themselves |
| AdapterTemplateModel implementations, so unwrapping a model that |
| was created by BeansWrapper for an underlying Java object always |
| yields the original Java object.</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para>If the model implements the deprecated |
| <literal>WrapperTemplateModel</literal>, the result of |
| <literal>model.getWrappedObject()</literal> is returned if it is |
| instance of <literal>T</literal> or it is a number and can be |
| converted to <literal>T</literal> using numeric coercion as |
| described two bullets lower.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If <literal>T</literal> is |
| <literal>java.lang.String</literal>, then if model implements |
| <literal>TemplateScalarModel</literal> its string value is |
| returned. <phrase role="forProgrammers">Note that if the model |
| doesn't implement TemplateScalarModel we don't attempt to |
| automatically convert the model to string using |
| String.valueOf(model). You'll have to use the ?string built-in |
| explicitly to pass non-scalars as strings.</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para>If <literal>T</literal> is a primitive numeric type or |
| <literal>java.lang.Number</literal> is assignable from |
| <literal>T</literal>, and model implements |
| <literal>TemplateNumberModel</literal>, then its numeric value |
| is returned if it is instance of <literal>T</literal> or its |
| boxing type (if <literal>T</literal> is primitive type). |
| Otherwise, if <literal>T</literal> is a built-in Java numeric |
| type (primitive type or a standard subclass of |
| <literal>java.lang.Number</literal>, including |
| <literal>BigInteger</literal> and <literal>BigDecimal</literal>) |
| a new object of class <literal>T</literal> or its boxing type is |
| created with the number model's appropriately coerced |
| value.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If <literal>T</literal> is <literal>boolean</literal> or |
| <literal>java.lang.Boolean</literal>, and model implements |
| <literal>TemplateBooleanModel</literal>, then its boolean value |
| is returned.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If <literal>T</literal> is |
| <literal>java.util.Map</literal> and the model implements |
| <literal>TemplateHashModel</literal>, then a special Map |
| representation of the hash model is returned.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If <literal>T</literal> is |
| <literal>java.util.List</literal> and the model implements |
| <literal>TemplateSequenceModel</literal>, then a special List |
| representation of the sequence model is returned.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If <literal>T</literal> is |
| <literal>java.util.Set</literal> and the model implements |
| <literal>TemplateCollectionModel</literal>, then a special Set |
| representation of the collection model is returned.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If <literal>T</literal> is |
| <literal>java.util.Collection</literal> or |
| <literal>java.lang.Iterable</literal> and the model implements |
| either <literal>TemplateCollectionModel</literal> or |
| <literal>TemplateSequenceModel</literal>, then a special Set or |
| List representation of the collection or sequence model |
| (respectively) is returned.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If <literal>T</literal> is a Java array type and the model |
| implements <literal>TemplateSequenceModel</literal>, then a new |
| array of the specified type is created and its elements |
| unwrapped into the array recursively using the array's component |
| type as <literal>T</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If <literal>T</literal> is <literal>char</literal> or |
| <literal>java.lang.Character</literal>, and model implements |
| <literal>TemplateScalarModel</literal>, and its string |
| representation contains exactly one character, then a |
| <literal>java.lang.Character</literal> with that value is |
| retured.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If <literal>java.util.Date</literal> is assignable from |
| <literal>T</literal>, and model implements |
| <literal>TemplateDateModel</literal>, and its date value is |
| instance of <literal>T</literal>, then its date value is |
| returned.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If model is a number model, and its numeric value is |
| instance of <literal>T</literal>, the numeric value is returned. |
| <phrase role="forProgrammers">You can have a custom subclass of |
| java.lang.Number that implements a custom interface, and T might |
| be that interface. (*)</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para>If model is a date model, and its date value is instance |
| of <literal>T</literal>, the date value is returned. <phrase |
| role="forProgrammers">Similar consideration as for |
| (*)</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para>If model is a scalar model, and <literal>T</literal> is |
| assignable from <literal>java.lang.String</literal>, the string |
| value is returned. <phrase role="forProgrammers">This covers |
| cases when T is java.lang.Object, java.lang.Comparable, and |
| java.io.Serializable (**)</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para>If model is a boolean model, and <literal>T</literal> is |
| assignable from <literal>java.lang.Boolean</literal>, the |
| boolean value is returned. <phrase role="forProgrammers">Same as |
| (**)</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para>If model is a hash model, and <literal>T</literal> is |
| assignable from |
| <literal>freemarker.ext.beans.HashAdapter</literal>, a hash |
| adapter is returned. <phrase role="forProgrammers">Same as |
| (**)</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para>If model is a sequence model, and <literal>T</literal> is |
| assignable from |
| <literal>freemarker.ext.beans.SequenceAdapter</literal>, a |
| sequence adapter is returned. <phrase role="forProgrammers">Same |
| as (**)</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para>If model is a collection model, and <literal>T</literal> |
| is assignable from |
| <literal>freemarker.ext.beans.SetAdapter</literal>, a set |
| adapter for the collection is returned. <phrase |
| role="forProgrammers">Same as (**)</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para>If the model is instance of <literal>T</literal>, the |
| model itself is returned. <phrase role="forProgrammers">This |
| covers the case where the method explicitly declared a |
| FreeMarker-specific model interface, as well as allows returning |
| directive, method and transform models when java.lang.Object is |
| requested.</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para>An exception signifying no conversion is possible is |
| thrown.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Accessing static methods</title> |
| |
| <indexterm> |
| <primary>static method</primary> |
| |
| <secondary>accessing from templates</secondary> |
| </indexterm> |
| |
| <para>The <literal>TemplateHashModel</literal> returned from |
| <literal>BeansWrapper.getStaticModels()</literal> can be used to |
| create hash models for accessing static methods and fields of an |
| arbitrary class.</para> |
| |
| <programlisting role="unspecified">BeansWrapper wrapper = BeansWrapper.getDefaultInstance(); |
| TemplateHashModel staticModels = wrapper.getStaticModels(); |
| TemplateHashModel fileStatics = |
| (TemplateHashModel) staticModels.get("java.io.File");</programlisting> |
| |
| <para>And you will get a template hash model that exposes all static |
| methods and static fields (both final and non-final) of the |
| <literal>java.lang.System</literal> class as hash keys. Suppose that |
| you put the previous model in your root model:</para> |
| |
| <programlisting role="unspecified">root.put("File", fileStatics);</programlisting> |
| |
| <para>From now on, you can use <literal>${File.SEPARATOR}</literal> |
| to insert the file separator character into your template, or you |
| can even list all roots of your file system by:</para> |
| |
| <programlisting role="template"><#list File.listRoots() as fileSystemRoot>...</#list></programlisting> |
| |
| <para>Of course, you must be aware of the potential security issues |
| this model brings.</para> |
| |
| <para>You can even give the template authors complete freedom over |
| which classes' static methods they use by placing the static models |
| hash into your template root model with</para> |
| |
| <programlisting role="unspecified">root.put("statics", BeansWrapper.getDefaultInstance().getStaticModels());</programlisting> |
| |
| <para>This object exposes just about any class' static methods if |
| it's used as a hash with class name as the key. You can then use |
| expression like |
| <literal>${statics["java.lang.System"].currentTimeMillis()}</literal> |
| in your template. Note, however that this has even more security |
| implications, as someone could even invoke |
| <literal>System.exit()</literal> using this model if the method |
| exposure level is weakened to <literal>EXPOSE_ALL</literal>.</para> |
| |
| <para>Note that in above examples, we always use the default |
| <literal>BeansWrapper</literal> instance. This is a convenient |
| static wrapper instance that you can use in most cases. You are also |
| free to create your own <literal>BeansWrapper</literal> instances |
| and use them instead especially when you want to modify some of its |
| characteristics (like model caching, security level, or the null |
| model representation).</para> |
| </section> |
| |
| <section xml:id="jdk_15_enums"> |
| <title>Accessing enums</title> |
| |
| <indexterm> |
| <primary>enum</primary> |
| </indexterm> |
| |
| <para>The <literal>TemplateHashModel</literal> returned from |
| <literal>BeansWrapper.getEnumModels()</literal> can be used to |
| create hash models for accessing values of enums. (An attempt to |
| invoke this method on an earlier JRE will result in an |
| <literal>UnsupportedOperationException</literal>.)</para> |
| |
| <programlisting role="unspecified">BeansWrapper wrapper = BeansWrapper.getDefaultInstance(); |
| TemplateHashModel enumModels = wrapper.getEnumModels(); |
| TemplateHashModel roundingModeEnums = |
| (TemplateHashModel) enumModels.get("java.math.RoundingMode");</programlisting> |
| |
| <para>And you will get a template hash model that exposes all enum |
| values of the <literal>java.math.RoundingMode</literal> class as |
| hash keys. Suppose that you put the previous model in your root |
| model:</para> |
| |
| <programlisting role="unspecified">root.put("RoundingMode", roundingModeEnums);</programlisting> |
| |
| <para>From now on, you can use <literal>RoundingMode.UP</literal> as |
| an expression to reference the <literal>UP</literal> enum value in |
| your template.</para> |
| |
| <para>You can even give the template authors complete freedom over |
| which enum classes they use by placing the enum models hash into |
| your template root model with</para> |
| |
| <programlisting role="unspecified">root.put("enums", BeansWrapper.getDefaultInstance().getEnumModels());</programlisting> |
| |
| <para>This object exposes any enum class if it's used as a hash with |
| class name as the key. You can then use expression like |
| <literal>${enums["java.math.RoundingMode"].UP}</literal> in your |
| template.</para> |
| |
| <para>The exposed enum values can be used as scalars (they'll |
| delegate to their <literal>toString()</literal> method), and can be |
| used in equality and inequality comparisons as well.</para> |
| |
| <para>Note that in above examples, we always use the default |
| <literal>BeansWrapper</literal> instance. This is a convenient |
| static wrapper instance that you can use in most cases. You are also |
| free to create your own <literal>BeansWrapper</literal> instances |
| and use them instead especially when you want to modify some of its |
| characteristics (like model caching, security level, or the null |
| model representation).</para> |
| </section> |
| </section> |
| |
| <section xml:id="pgui_misc_logging"> |
| <title>Logging</title> |
| |
| <indexterm> |
| <primary>logging</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>SLF4J</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>Log4j2</primary> |
| </indexterm> |
| |
| <section> |
| <title>Logging library selection</title> |
| |
| <para>Is short, the recommended setup in contemporary application |
| (as of 2015) is using SLF4J API for logging everywhere. To get |
| FreeMarker 2.3.x. to use SLF4J, simply add the |
| <literal>org.slf4j:log4j-over-slf4j</literal> dependency to your |
| project, and ensure that <literal>log4j:log4j</literal> isn't |
| present. (Starting from FreeMarker 2.4.x you don't need |
| <literal>log4j-over-slf4j</literal> anymore, though it does no harm |
| either.)</para> |
| |
| <para>Read on if you are curious about the details, or if you can't |
| use SLF4J...</para> |
| |
| <para>FreeMarker integrates with the following logging libraries: |
| <link xlink:href="http://www.slf4j.org/">SLF4J</link>, <link |
| xlink:href="http://commons.apache.org/logging/">Apache Commons |
| Logging</link>, <link |
| xlink:href="http://jakarta.apache.org/log4j">Log4J</link> 1.x, <link |
| xlink:href="http://jakarta.apache.org/avalon/logkit">Avalon |
| LogKit</link>, and <link |
| xlink:href="http://java.sun.com/j2se/1.4/docs/api/java/util/logging/package-summary.html"><literal>java.util.logging</literal></link>. |
| By default, FreeMarker will look for the these logging libraries in |
| the following order, and will automatically use the first one it |
| finds (in 2.3.x): <remark>[2.4 - un-remark this] SLF4J, Apache |
| Commons Logging, </remark>Log4J (will use SLF4J instead if it's a |
| properly installed <literal>log4j-over-slf4j</literal>, since |
| 2.3.22), Apache Avalon LogKit, <literal>java.util.logging</literal>. |
| As you can see, Log4j has the highest priority. The presence of |
| Log4j is simply detected from the presence of the |
| <literal>org.apache.log4j.Logger</literal> class, which means that |
| Log4j redirections like <literal>log4j-over-slf4j</literal> or |
| <literal>log4j-1.2-api</literal> will also get the highest |
| priority.</para> |
| |
| <para>Prior to FreeMarker 2.4, SLF4J and Apache Commons Logging |
| aren't searched automatically due to backward compatibility |
| constraints. But if you have |
| <literal>org.slf4j:log4j-over-slf4j</literal> properly installed |
| (means, you have no real Log4j in your class path, and SLF4J has a |
| backing implementation like <literal>logback-classic</literal>), |
| then FreeMarker will use the SLF4J API directly instead of the Log4j |
| API (since FreeMarker 2.3.22).</para> |
| |
| <para>Note that a similar trick can be applied for logging into |
| Log4j2: If <literal>org.apache.logging.log4j:log4j-1.2-api</literal> |
| is present, FreeMarker 2.3.x will pick that as it looks like Log4j, |
| but all the messages will actually go to Log4j2.</para> |
| |
| <para>If the auto detection doesn't give you the result that you |
| want, you can set the |
| <literal>org.freemarker.loggerLibrary</literal> system property to |
| select a logger library explicitly (since 2.3.22), like:</para> |
| |
| <programlisting role="unspecified">java <replaceable>...</replaceable> -Dorg.freemarker.loggerLibrary=SLF4J</programlisting> |
| |
| <para>The supported system property values are: |
| <literal>SLF4J</literal>, <literal>CommonsLogging</literal>, |
| <literal>JUL</literal> (for <literal>java.util.logging</literal>), |
| <literal>Avalon</literal>, <literal>auto</literal> (the default |
| behavior), <literal>none</literal> (disables logging).</para> |
| |
| <para>Note that for reliable operation, the system property should |
| be set when the JVM starts (like above), not later from Java |
| code.</para> |
| |
| <para>Using SLF4J is recommended, as it works best with FreeMarker, |
| and also because it will be the highest priority auto detected |
| logger starting from FreeMarker 2.4.</para> |
| </section> |
| |
| <section> |
| <title>Logging categories</title> |
| |
| <para>All log messages produced by FreeMarker are logged with a |
| logger category that starts with <literal>freemarker.</literal>. The |
| currently used logger categories are:</para> |
| |
| <informaltable border="1"> |
| <thead> |
| <tr> |
| <th>Log category name</th> |
| |
| <th>Purpose</th> |
| </tr> |
| </thead> |
| |
| <tbody> |
| <tr> |
| <td><literal>freemarker.beans</literal></td> |
| |
| <td>Logs messages of the Beans wrapper module.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>freemarker.cache</literal></td> |
| |
| <td>Logs messages related to template loading and |
| caching.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>freemarker.runtime</literal></td> |
| |
| <td>Logs messages related to template execution that doesn't |
| fit any of the more specific categories. Most importantly, it |
| logs template exceptions thrown during template processing |
| (however that should be disabled in modern application; see |
| later).</td> |
| </tr> |
| |
| <tr> |
| <td><literal>freemarker.runtime.attempt</literal></td> |
| |
| <td>Logs template exceptions thrown during template processing |
| and caught by |
| <literal>attempt</literal>/<literal>recover</literal> |
| directives, with DEBUG severity. Note that such exceptions |
| will be still also logged with their normal logger (like |
| <literal>freemarker.runtime</literal>).</td> |
| </tr> |
| |
| <tr> |
| <td><literal>freemarker.servlet</literal></td> |
| |
| <td>Logs messages of the <literal>FreemarkerServlet</literal> |
| class.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>freemarker.jsp</literal></td> |
| |
| <td>Logs messages of the FreeMarker JSP support.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>freemarker.configuration</literal></td> |
| |
| <td>Logs messages related to configuring FreeMarker, and not |
| fitting any other categories.</td> |
| </tr> |
| </tbody> |
| </informaltable> |
| |
| <para>One quirk relating this is that FreeMarker will log exceptions |
| during template execution under the |
| <literal>freemarker.runtime</literal> category even if the exception |
| continues propagating and so eventually will be thrown by |
| <literal>Template.process</literal> or |
| <literal>Environment.process</literal> anyway. (Those are the API |
| calls with which the template was invoked from the application or |
| the application framework.) Well behaving applications log the |
| exceptions thrown at them, or rarely, handle them and deliberately |
| don't want to log them. But as FreeMarker has already logged that |
| exception, you will end up one more log entry than expected. To fix |
| that (since 2.3.22), set the |
| <literal>log_template_exceptions</literal> |
| (<literal>Configurable.setLogTemplateExceptions(boolean)</literal>) |
| setting to <literal>false</literal>.</para> |
| </section> |
| </section> |
| |
| <section xml:id="pgui_misc_servlet"> |
| <title>Using FreeMarker with servlets</title> |
| |
| <anchor xml:id="topic.servlet"/> |
| |
| <indexterm> |
| <primary>Servlet</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>HTTP</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>JSP</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>Model 2</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>Struts</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>Jakarta</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>Web application framework</primary> |
| </indexterm> |
| |
| <para>In a fundamental sense, using FreeMarker in the web application |
| space is no different from anywhere else; FreeMarker writes its output |
| to a <literal>Writer</literal> that you pass to the |
| <literal>Template.process</literal> method, and it does not care if |
| that <literal>Writer</literal> prints to the console or to a file or |
| to the output stream of <literal>HttpServletResponse</literal>. |
| FreeMarker knows nothing about servlets and Web; it just merges Java |
| object with template files and generates text output from them. From |
| here, it is up to you how to build a Web application around |
| this.</para> |
| |
| <para>But, probably you want to use FreeMarker with some already |
| existing Web application framework. Many frameworks rely on the |
| <quote>Model 2</quote> architecture, where JSP pages handle |
| presentation. If you use such a framework (for example, <link |
| xlink:href="http://jakarta.apache.org/struts">Apache Struts</link>), |
| then read on. For other frameworks please refer to the documentation |
| of the framework.</para> |
| |
| <note> |
| <para>FreeMarker supports both traditional <quote>javax</quote> |
| Servet/JSP, and Jakarta Servlet/JSP. However, you have to use a |
| different Java package for them: |
| <literal>freemarker.ext.servet</literal>, and |
| <literal>freemarker.ext.jsp</literal> for <quote>javax</quote>, and |
| <literal>freemarker.ext.jakarta.servet</literal>, and |
| <literal>freemarker.ext.jakarta.jsp</literal> for Jakarta. On modern |
| Servlet containers you must use the Jakarta packages, while on older |
| ones you must use the non-Jakarte packages.</para> |
| </note> |
| |
| <section xml:id="pgui_misc_servlet_model2"> |
| <title>Using FreeMarker for <quote>Model 2</quote></title> |
| |
| <para>Many frameworks follow the strategy that the HTTP request is |
| dispatched to user-defined <quote>action</quote> classes that put |
| data into <literal>ServletContext</literal>, |
| <literal>HttpSession</literal> and |
| <literal>HttpServletRequest</literal> objects as attributes, and |
| then the request is forwarded by the framework to a JSP page (the |
| view) that will generate the HTML page using the data sent with the |
| attributes. This is often referred as Model 2.</para> |
| |
| <mediaobject> |
| <imageobject> |
| <imagedata fileref="figures/model2sketch.png"/> |
| </imageobject> |
| </mediaobject> |
| |
| <para>With these frameworks you can simply use FTL files instead of |
| JSP files. But, since your servlet container (Web application |
| server), unlike with JSP files, does not know out-of-the-box what to |
| do with FTL files, a little extra configuring is needed for your Web |
| application:</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>Copy <literal>freemarker.jar</literal> (from the |
| <literal>lib</literal> directory of the FreeMarker distribution) |
| into the <literal>WEB-INF/lib</literal> directory of your Web |
| application.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Insert the following section to the |
| <literal>WEB-INF/web.xml</literal> file of your Web application |
| (and adjust it if required):</para> |
| </listitem> |
| </orderedlist> |
| |
| <programlisting role="unspecified"><servlet> |
| <servlet-name>freemarker</servlet-name> |
| |
| <servlet-class><emphasis>freemarker.ext.servlet.FreemarkerServlet</emphasis></servlet-class> |
| <!-- Or freemarker.ext.<emphasis>jakarta</emphasis>.servlet.FreemarkerServlet! --> |
| |
| <!-- |
| Init-param documentation: |
| <link xlink:href="https://freemarker.apache.org/docs/api/freemarker/ext/servlet/FreemarkerServlet.html">https://freemarker.apache.org/docs/api/freemarker/ext/servlet/FreemarkerServlet.html</link> |
| --> |
| |
| <!-- FreemarkerServlet settings: --> |
| <init-param> |
| <param-name>TemplatePath</param-name> |
| <param-value>/</param-value> |
| </init-param> |
| <init-param> |
| <param-name>NoCache</param-name> |
| <param-value>true</param-value> |
| </init-param> |
| <init-param> |
| <param-name>ResponseCharacterEncoding</param-name> |
| <!-- Use the output_encoding setting of FreeMarker: --> |
| <param-value>fromTemplate</param-value> |
| </init-param> |
| <init-param> |
| <param-name>ExceptionOnMissingTemplate</param-name> |
| <!-- true => HTTP 500 on missing template, instead of HTTP 404. --> |
| <param-value>true</param-value> |
| </init-param> |
| |
| <!-- FreeMarker engine settings: --> |
| <init-param> |
| <param-name>incompatible_improvements</param-name> |
| <param-value>2.3.27</param-value> |
| <!-- |
| Recommended to set to a high value. |
| See: https://freemarker.apache.org/docs/pgui_config_incompatible_improvements.html |
| --> |
| </init-param> |
| <init-param> |
| <param-name>template_exception_handler</param-name> |
| <!-- Use "html_debug" during development! --> |
| <param-value>rethrow</param-value> |
| </init-param> |
| <init-param> |
| <param-name>template_update_delay</param-name> |
| <!-- Use 0 during development! Consider what value you need otherwise. --> |
| <param-value>30 s</param-value> |
| </init-param> |
| <init-param> |
| <param-name>default_encoding</param-name> |
| <!-- The encoding of the template files: --> |
| <param-value>UTF-8</param-value> |
| </init-param> |
| <init-param> |
| <param-name>output_encoding</param-name> |
| <!-- The encoding of the template output; Note that you must set |
| "ResponseCharacterEncodring" to "fromTemplate" for this to work! --> |
| <param-value>UTF-8</param-value> |
| </init-param> |
| <init-param> |
| <param-name>locale</param-name> |
| <!-- Influences number and date/time formatting, etc. --> |
| <param-value>en_US</param-value> |
| </init-param> |
| <init-param> |
| <param-name>number_format</param-name> |
| <param-value>0.##########</param-value> |
| </init-param> |
| |
| <load-on-startup>1</load-on-startup> |
| </servlet> |
| |
| <servlet-mapping> |
| <servlet-name>freemarker</servlet-name> |
| <url-pattern><emphasis>*.ftl</emphasis></url-pattern> |
| <!-- HTML and XML auto-escaped if incompatible_improvements >= 2.3.24: --> |
| <url-pattern><emphasis>*.ftlh</emphasis></url-pattern> |
| <url-pattern><emphasis>*.ftl</emphasis>x</url-pattern> |
| </servlet-mapping> |
| |
| <replaceable>...</replaceable> |
| |
| <!-- |
| Prevent the visiting of MVC Views from outside the servlet container. |
| RequestDispatcher.forward/include should, and will still work. |
| Removing this may open security holes! |
| --> |
| <security-constraint> |
| <web-resource-collection> |
| <web-resource-name>FreeMarker MVC Views</web-resource-name> |
| <url-pattern>*.ftl</url-pattern> |
| <url-pattern>*.ftlh</url-pattern> |
| <url-pattern>*.ftlx</url-pattern> |
| </web-resource-collection> |
| <auth-constraint> |
| <!-- Nobody is allowed to visit these directly. --> |
| </auth-constraint> |
| </security-constraint></programlisting> |
| |
| <para>After this, you can use FTL files (<literal>*.ftl</literal>) |
| in the same manner as JSP (<literal>*.jsp</literal>) files. (Of |
| course you can choose another extension besides |
| <literal>ftl</literal>; it is just the convention)</para> |
| |
| <note> |
| <para>How does it work? Let's examine how JSP-s work. Many servlet |
| container handles JSP-s with a servlet that is mapped to the |
| <literal>*.jsp</literal> request URL pattern. That servlet will |
| receive all requests where the request URL ends with |
| <literal>.jsp</literal>, find the JSP file based on the request |
| URL, and internally compiles it to a <literal>Servlet</literal>, |
| and then call the generated servlet to generate the page. The |
| <literal>FreemarkerServlet</literal> mapped here to the |
| <literal>*.ftl</literal> URL pattern does the same, except that |
| FTL files are not compiled to <literal>Servlet</literal>-s, but to |
| <literal>Template</literal> objects, and then the |
| <literal>process</literal> method of <literal>Template</literal> |
| will be called to generate the page.</para> |
| </note> |
| |
| <para><anchor xml:id="topic.servlet.scopeAttr"/>For example, instead |
| of this JSP file (note that it heavily uses Struts tag-libs to save |
| designers from embedded Java monsters):</para> |
| |
| <programlisting role="template"><%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> |
| <%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %> |
| |
| <html> |
| <head><title>Acmee Products International</title> |
| <body> |
| <h1>Hello <bean:write name="user"/>!</h1> |
| <p>These are our latest offers: |
| <ul> |
| <logic:iterate name="latestProducts" id="prod"> |
| <li><bean:write name="prod" property="name"/> |
| for <bean:write name="prod" property="price"/> Credits. |
| </logic:iterate> |
| </ul> |
| </body> |
| </html></programlisting> |
| |
| <para>you can use this FTL file (use <literal>ftl</literal> file |
| extension instead of <literal>jsp</literal>):</para> |
| |
| <programlisting role="template"><html> |
| <head><title>Acmee Products International</title> |
| <body> |
| <h1>Hello ${user}!</h1> |
| <p>These are our latest offers: |
| <ul> |
| <#list latestProducts as prod> |
| <li>${prod.name} for ${prod.price} Credits. |
| </#list> |
| </ul> |
| </body> |
| </html></programlisting> |
| |
| <warning> |
| <para>In FreeMarker <literal><html:form |
| action="/query"><replaceable>...</replaceable></html:form></literal> |
| is just static text, so it is printed to the output as is, like |
| any other XML or HTML markup. JSP tags are just FreeMarker |
| directives, nothing special, so you <emphasis>use FreeMarker |
| syntax</emphasis> for calling them, not JSP syntax: |
| <literal><@html.form |
| action="/query"><replaceable>...</replaceable></@html.form></literal>. |
| Note that in the FreeMarker syntax you <emphasis>don't use |
| <literal>${<replaceable>...</replaceable>}</literal> in |
| parameters</emphasis> as in JSP, and you <emphasis>don't quote the |
| parameter values</emphasis>. So this is |
| <emphasis>WRONG</emphasis>:</para> |
| |
| <programlisting role="template"><#-- WRONG: --> |
| <@my.jspTag color="${aVariable}" name="aStringLiteral" |
| width="100" height=${a+b} /></programlisting> |
| |
| <para>and this is good:</para> |
| |
| <programlisting role="template"><#-- Good: --> |
| <@my.jspTag color=aVariable name="aStringLiteral" |
| width=100 height=a+b /></programlisting> |
| </warning> |
| |
| <para>In both templates, when you refer to <literal>user</literal> |
| and <literal>latestProduct</literal>, it will first try to find a |
| variable with that name that was created in the template (like |
| <literal>prod</literal>; if you master JSP: a page scope attribute). |
| If that fails, it will try to look up an attribute with that name in |
| the <literal>HttpServletRequest</literal>, and if it is not there |
| then in the <literal>HttpSession</literal>, and if it still doesn't |
| find it then in the <literal>ServletContext</literal>. In the case |
| of FTL this works because <literal>FreemarkerServlet</literal> |
| builds the data-model from the attributes of the mentioned 3 |
| objects. That is, in this case the root hash is not a |
| <literal>java.util.Map</literal> (as it was in some example codes in |
| this manual), but |
| <literal>ServletContext</literal>+<literal>HttpSession</literal>+<literal>HttpServletRequest</literal>; |
| FreeMarker is pretty flexible about what the data-model is. So if |
| you want to put variable <literal>"name"</literal> into the |
| data-model, then you call |
| <literal>servletRequest.setAttribute("name", "Fred")</literal>; this |
| is the logic of Model 2, and FreeMarker adapts itself to it.</para> |
| |
| <para><literal>FreemarkerServlet</literal> also puts 3 hashes into |
| the data-model, by which you can access the attributes of the 3 |
| objects directly. The hash variables are: |
| <literal>Request</literal>, <literal>Session</literal>, |
| <literal>Application</literal> (corresponds to |
| <literal>ServletContext</literal>). It also exposes another hash |
| named <literal>RequestParameters</literal> that provides access to |
| the parameters of the HTTP request.</para> |
| |
| <para><literal>FreemarkerServlet</literal> has various init-params. |
| It can be set up to load templates from an arbitrary directory, from |
| the classpath, or relative to the Web application directory. You can |
| set the charset used for templates, the default locale used by |
| templates, what object wrapper do you want to use, etc.</para> |
| |
| <para><literal>FreemarkerServlet</literal> is easily tailored to |
| special needs through subclassing. Say, if you need to have |
| additional variables available in your data-model for all templates, |
| subclass the servlet and override the |
| <literal>preTemplateProcess()</literal> method to shove any |
| additional data you need into the model before the template gets |
| processed. Or subclass the servlet, and set these globally available |
| variables as <link linkend="pgui_config_sharedvariables">shared |
| variables</link> in the <literal>Configuration</literal>.</para> |
| |
| <para>For more information please read the Java API documentation of |
| the class.</para> |
| </section> |
| |
| <section xml:id="pgui_misc_servlet_include"> |
| <title>Including content from other web application |
| resources</title> |
| |
| <indexterm> |
| <primary>include</primary> |
| |
| <secondary>servlet</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>include</primary> |
| |
| <secondary>JSP</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>servlet</primary> |
| |
| <secondary>include</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>JSP</primary> |
| |
| <secondary>include</secondary> |
| </indexterm> |
| |
| <para>You can use the <literal><@include_page |
| path="..."/></literal> custom directive provided by the |
| <literal>FreemarkerServlet</literal> (since 2.3.15) to include the |
| contents of another web application resource into the output; this |
| is often useful to integrate output of JSP pages (living alongside |
| the FreeMarker templates in the same web server) into the FreeMarker |
| template output. Using:</para> |
| |
| <programlisting role="template"><@include_page path="path/to/some.jsp"/></programlisting> |
| |
| <para>is identical to using this tag in JSP:</para> |
| |
| <programlisting role="template"><jsp:include page="path/to/some.jsp"></programlisting> |
| |
| <note> |
| <para><literal><@include_page ...></literal> is not to be |
| confused with <literal><#include ...></literal>, as the last |
| is for including FreeMarker templates without involving the |
| Servlet container. An <literal><#include ...></literal>-ed |
| template shares the template processing state with the including |
| template, such as the data-model and the template-language |
| variables, while <literal><@include_page ...></literal> |
| starts an independent HTTP request processing.</para> |
| </note> |
| |
| <note> |
| <para>Some Web Application Frameworks provide their own solution |
| for this, in which case you possibly should use that instead. Also |
| some Web Application Frameworks don't use |
| <literal>FreemarkerServlet</literal>, so |
| <literal>include_page</literal> is not available.</para> |
| </note> |
| |
| <para>The path can be relative or absolute. Relative paths are |
| interpreted relative to the URL of the current HTTP request (one |
| that triggered the template processing), while absolute paths are |
| absolute in the current servlet context (current web application). |
| You can not include pages from outside the current web application. |
| Note that you can include any page, not just a JSP page; we just |
| used page with path ending in <literal>.jsp</literal> as an |
| illustration.</para> |
| |
| <para>In addition to the <literal>path</literal> parameter, you can |
| also specify an optional parameter named |
| <literal>inherit_params</literal> with a boolean value (defaults to |
| true when not specified) that specifies whether the included page |
| will see the HTTP request parameters of the current request or |
| not.</para> |
| |
| <para>Finally, you can specify an optional parameter named |
| <literal>params</literal> that specifies new request parameters that |
| the included page will see. In case inherited parameters are passed |
| too, the values of specified parameters will get prepended to the |
| values of inherited parameters of the same name. The value of |
| <literal>params</literal> must be a hash, with each value in it |
| being either a string, or a sequence of strings (if you need |
| multivalued parameters). Here's a full example:</para> |
| |
| <programlisting role="template"><@include_page path="path/to/some.jsp" inherit_params=true params={"foo": "99", "bar": ["a", "b"]}/></programlisting> |
| |
| <para>This will include the page |
| <literal>path/to/some.jsp</literal>, pass it all request parameters |
| of the current request, except for "foo" and "bar", which will be |
| set to "99" and multi-value of "a", "b", respectively. In case the |
| original request already had values for these parameters, the new |
| values will be prepended to the existing values. I.e. if "foo" had |
| values "111" and "123", then it will now have values "99", "111", |
| "123".</para> |
| |
| <para><phrase role="forProgrammers">It is in fact possible to pass |
| non-string values for parameter values within |
| <literal>params</literal>. Such a value will be converted to a |
| suitable Java object first (i.e. a Number, a Boolean, a Date, etc.), |
| and then its Java <literal>toString()</literal> method will be used |
| to obtain the string value. It is better to not rely on this |
| mechanism, though, and instead explicitly ensure that parameter |
| values that aren't strings are converted to strings on the template |
| level where you have control over formatting using the |
| <literal>?string</literal> and <literal>?c</literal> built-ins. |
| </phrase></para> |
| </section> |
| |
| <section> |
| <title>Using JSP custom tags in FTL</title> |
| |
| <indexterm> |
| <primary>JSP</primary> |
| |
| <secondary>taglib</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>custom tags</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>taglib</primary> |
| </indexterm> |
| |
| <para><literal>FreemarkerServlet</literal> puts the |
| <literal>JspTaglibs</literal> hash into the data-model, which you |
| can use to access JSP taglibs. The JSP custom tags will be |
| accessible as plain user-defined directives, and the custom EL |
| functions (since FreeMarker 2.3.22) as methods. For example, for |
| this JSP file:</para> |
| |
| <programlisting role="template"><%@ page contentType="text/html;charset=ISO-8859-2" language="java"%> |
| <%@ taglib prefix="e" uri="/WEB-INF/example.tld" %> |
| <%@ taglib prefix="oe" uri="/WEB-INF/other-example.tld" %> |
| <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> |
| <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> |
| |
| <%-- Custom JSP tags and functions: --%> |
| |
| <e:someTag numParam="123" boolParam="true" strParam="Example" anotherParam="${someVar}"> |
| ... |
| </e:someTag> |
| |
| <oe:otherTag /> |
| |
| ${e:someELFunction(1, 2)} |
| |
| |
| <%-- JSTL: --%> |
| |
| <c:if test="${foo}"> |
| Do this |
| </c:if> |
| |
| <c:choose> |
| <c:when test="${x == 1}"> |
| Do this |
| </c:when> |
| <c:otherwise> |
| Do that |
| </c:otherwise> |
| </c:choose> |
| |
| <c:forEach var="person" items="${persons}"> |
| ${person.name} |
| </c:forEach> |
| |
| ${fn:trim(bar)}</programlisting> |
| |
| <para>the about equivalent FTL is:</para> |
| |
| <programlisting role="template"><#assign e=JspTaglibs["/WEB-INF/example.tld"]> |
| <#assign oe=JspTaglibs["/WEB-INF/other-example.tld"]> |
| |
| <#-- Custom JSP tags and functions: --#> |
| |
| <@e.someTag numParam=123 boolParam=true strParam="Example" anotherParam=someVar> |
| ... |
| </@e.someTag> |
| |
| <@oe.otherTag /> |
| |
| ${e.someELFunction(1, 2)} |
| |
| |
| <#-- JSTL - Instead, use native FTL constructs: --> |
| |
| <#if foo> |
| Do this |
| </#if> |
| |
| <#if x == 1> |
| Do this |
| <#else> |
| Do that |
| </#if> |
| |
| <#list persons as person> |
| ${person.name} |
| </#list> |
| |
| ${bar?trim}</programlisting> |
| |
| <note> |
| <para>Parameter values don't use quotation and |
| <literal>"${<replaceable>...</replaceable>}"</literal> like in |
| JSP. See more explanation later.</para> |
| </note> |
| |
| <note> |
| <para><literal>JspTaglibs</literal> is not a core FreeMarker |
| feature; it only exists when the template is called through the |
| <literal>FreemarkerServlet</literal>. That's because JSP |
| tags/functions assume a servlet environment (FreeMarker doesn't), |
| plus some Servlet concepts have to be emulated in the special |
| FreeMarker data-model that <literal>FreemarkerServlet</literal> |
| builds. Many modern frameworks use FreeMarker on a pure way, not |
| through <literal>FreemarkerServlet</literal>.</para> |
| </note> |
| |
| <para>Since JSP custom tags are written to operate in JSP |
| environment, they assume that variables (often referred as |
| <quote>beans</quote> in JSP world) are stored in 4 scopes: page |
| scope, request scope, session scope and application scope. FTL has |
| no such notation (the 4 scopes), but |
| <literal>FreemarkerServlet</literal> provides emulated JSP |
| environment for the custom JSP tags, which maintains correspondence |
| between the <quote>beans</quote> of JSP scopes and FTL variables. |
| For the custom JSP tags, the request, session and application scopes |
| are exactly the same as with real JSP: the attributes of the |
| <literal>javax.servlet.ServletContext</literal>, |
| <literal>HttpSession</literal> and <literal>ServletRequest</literal> |
| objects. From the FTL side you see these 3 scopes together as the |
| data-model, as it was explained earlier. The page scope corresponds |
| to the FTL global variables (see the <link |
| linkend="ref.directive.global"><literal>global</literal> |
| directive</link>). That is, if you create a variable with the |
| <literal>global</literal> directive, it will be visible for the |
| custom tags as page scope variable through the emulated JSP |
| environment. Also, if a JSP-tag creates a new page scope variable, |
| the result will be the same as if you create a variable with the |
| <literal>global</literal> directive. Note that the variables in the |
| data-model are not visible as page-scope attributes for the JSP |
| tags, despite that they are globally visible, since the data-model |
| corresponds to the request, session and application scopes, not the |
| page-scope.</para> |
| |
| <para>On JSP pages you quote all attribute values, it does not mater |
| if the type of the parameter is string or boolean or number. But |
| since custom tags are accessible in FTL templates as user-defined |
| FTL directives, you have to use the FTL syntax rules inside the |
| custom tags, not the JSP rules. So when you specify the value of an |
| <quote>attribute</quote>, then on the right side of the |
| <literal>=</literal> there is an <link |
| linkend="dgui_template_exp">FTL expression</link>. Thus, |
| <emphasis>you must not quote boolean and numerical parameter |
| values</emphasis> (e.g. <literal><@tiles.insert |
| page="/layout.ftl" flush=true/></literal>), or they are |
| interpreted as string values, and this will cause a type mismatch |
| error when FreeMarker tries to pass the value to the custom tag that |
| expects non-string value. Also note that, naturally, you can use any |
| FTL expression as attribute value, such as variables, calculated |
| values, etc. (e.g. <literal><@tiles.insert page=layoutName |
| flush=foo && bar/></literal>).</para> |
| |
| <para>FreeMarker does not rely on the JSP support of the servlet |
| container in which it is run when it uses JSP taglibs since it |
| implements its own lightweight JSP runtime environment. There is |
| only one small detail to pay attention to: to enable the FreeMarker |
| JSP runtime environment to dispatch events to JSP taglibs that |
| register event listeners in their TLD files, you should add this to |
| the <literal>WEB-INF/web.xml</literal> of your Web |
| application:</para> |
| |
| <programlisting role="unspecified"><listener> |
| <listener-class>freemarker.ext.jsp.EventForwarding</listener-class> |
| <!-- Or freemarker.ext.<emphasis>jakarta</emphasis>.jsp.EventForwarding! --> |
| </listener></programlisting> |
| |
| <para>Note that you can use JSP taglibs with FreeMarker even if the |
| servlet container has no native JSP support, just make sure that the |
| <literal>javax.servlet.jsp.*</literal> packages for JSP 2.0 (or |
| later) are available to your Web application.</para> |
| |
| <para>As of this writing, JSP features up to JSP 2.1 are |
| implemented, except the "tag files" feature of JSP 2 (i.e., custom |
| JSP tags <emphasis>implemented</emphasis> in JSP language). The tag |
| files had to be compiled to Java classes to be usable under |
| FreeMarker.</para> |
| |
| <para><literal>JspTaglibs[<replaceable>uri</replaceable>]</literal> |
| will have to find the TLD for the URI specified, just like JSP's |
| <literal>@taglib</literal> directive has to. For this, it implements |
| the TLD discovery mechanism described in the JSP specification. See |
| more there, but in a nutshell, it searches TLD-s in |
| <literal>WEB-INF/web.xml</literal> <literal>taglib</literal> |
| elements, at <literal>WEB-INF/**/*.tld</literal>, and in |
| <literal>WEB-INF/lib/*.{jar,zip}/META-INF/**/*.tld</literal>. |
| Additionally, it can discover TLD-s that are visible for the class |
| loader even if they are outside the WAR structure, when you set that |
| up with the <literal>MetaInfTldSources</literal> and/or |
| <literal>ClasspathTlds</literal> |
| <literal>FreemarkerServlet</literal> init-params (since 2.3.22). See |
| the Java API documentation of <literal>FreemarkerServlet</literal> |
| for the description of these. It's also possible to set these from |
| Java system properties, which can be handy when you want to change |
| these in the Eclipse run configuration without modifying the |
| <literal>web.xml</literal>; again, see the |
| <literal>FreemarkerServlet</literal> API docs. |
| <literal>FreemarkerServlet</literal> also recognizes the |
| <literal>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</literal> |
| servlet context attribute, and adds the entries from it to |
| <literal>MetaInfTldSources</literal>.</para> |
| </section> |
| |
| <section> |
| <title>Embed FTL into JSP pages</title> |
| |
| <indexterm> |
| <primary>JSP</primary> |
| |
| <secondary>taglib</secondary> |
| </indexterm> |
| |
| <para>There is a taglib that allows you to put FTL fragments into |
| JSP pages. The embedded FTL fragment can access the attributes |
| (Beans) of the 4 JSP scopes. You can find a working example and the |
| taglib in the FreeMarker distribution.</para> |
| </section> |
| </section> |
| |
| <section xml:id="pgui_misc_secureenv"> |
| <title>Configuring security policy for FreeMarker</title> |
| |
| <indexterm> |
| <primary>security</primary> |
| </indexterm> |
| |
| <para>When FreeMarker is used in a Java virtual machine with a |
| security manager installed, you have to grant it few permissions to |
| ensure it operates properly. Most notably, you need these entries to |
| your security policy file for |
| <literal>freemarker.jar</literal>:</para> |
| |
| <programlisting role="unspecified">grant codeBase "file:/path/to/freemarker.jar" |
| { |
| permission java.util.PropertyPermission "file.encoding", "read"; |
| permission java.util.PropertyPermission "freemarker.*", "read"; |
| }</programlisting> |
| |
| <para>Additionally, if you are loading templates from a directory, you |
| need to give FreeMarker permissions to read files from that directory |
| using the following permission:</para> |
| |
| <programlisting role="unspecified">grant codeBase "file:/path/to/freemarker.jar" |
| { |
| ... |
| permission java.io.FilePermission "/path/to/templates/-", "read"; |
| }</programlisting> |
| |
| <para>Finally, if you're just using the default template loading |
| mechanism which loads templates from the current directory, then |
| specify these permissions additionally: (note that the expression |
| <literal>${user.dir}</literal> will be evaluated at run time by the |
| policy interpreter, pretty much as if it were a FreeMarker |
| template)</para> |
| |
| <programlisting role="unspecified"> |
| grant codeBase "file:/path/to/freemarker.jar" |
| { |
| ... |
| permission java.util.PropertyPermission "user.dir", "read"; |
| permission java.io.FilePermission "${user.dir}/-", "read"; |
| }</programlisting> |
| |
| <para>Naturally, if you're running under Windows, use double backslash |
| instead of a single slash for separating directory components in |
| paths.</para> |
| </section> |
| |
| <section xml:id="pgui_misc_xml_legacy"> |
| <title>Legacy XML wrapper implementation</title> |
| |
| <note> |
| <para><emphasis>The legacy XML wrapper is deprecated.</emphasis> |
| FreeMarker 2.3 has introduced support for a new XML processing |
| model. To support this, a new XML wrapper package was introduced, |
| <literal>freemarker.ext.dom</literal>. For new usage, we encourage |
| you to use that. It is documented in the part <xref |
| linkend="xgui"/>.</para> |
| </note> |
| |
| <para>The class <literal>freemarker.ext.xml.NodeListModel</literal> |
| provides a template model for wrapping XML documents represented as |
| node trees. Every node list can contain zero or more XML nodes |
| (documents, elements, texts, processing instructions, comments, entity |
| references, CDATA sections, etc.). The node list implements the |
| following template model interfaces with the following |
| semantics:</para> |
| |
| <section> |
| <title>TemplateScalarModel</title> |
| |
| <para>When used as a scalar, the node list will render the XML |
| fragment that represents its contained nodes. This makes it handy |
| for use in XML-to-XML transforming templates.</para> |
| </section> |
| |
| <section> |
| <title>TemplateCollectionModel</title> |
| |
| <para>When used as a collection with <literal>list</literal> |
| directive, it will simply enumerate its nodes. Every node will be |
| returned as a new node list consisting of a single node.</para> |
| </section> |
| |
| <section> |
| <title>TemplateSequenceModel</title> |
| |
| <para>When used as a sequence, it will return the i-th node as a new |
| node list consisting of the single requested node. I.e. to return |
| the 3rd <literal><chapter></literal> element of the |
| <literal><book></literal> element, you'd use the following |
| (note indexes are zero-based):</para> |
| |
| <programlisting role="template"><#assign thirdChapter = xmldoc.book.chapter[2]></programlisting> |
| </section> |
| |
| <section> |
| <title>TemplateHashModel</title> |
| |
| <para>When used as a hash, it is basically used to traverse |
| children. That is, if you have a node list named |
| <literal>book</literal> that wraps an element node with several |
| chapters, then the <literal>book.chapter</literal> will yield a node |
| list with all chapter elements of that book element. The at sign is |
| used to refer to attributes: <literal>book.@title</literal> yields a |
| node list with a single attribute node, that is the title attribute |
| of the book element.</para> |
| |
| <para>It is important to realize the consequence that, for example, |
| if <literal>book</literal> has no <literal>chapter</literal>-s then |
| <literal>book.chapter</literal> is an empty sequence, so |
| <literal>xmldoc.book.chapter??</literal> will |
| <emphasis>not</emphasis> be <literal>false</literal>, it will be |
| always <literal>true</literal>! Similarly, |
| <literal>xmldoc.book.somethingTotallyNonsense??</literal> will not |
| be <literal>false</literal> either. To check if there was no |
| children found, use <literal>xmldoc.book.chapter?size == |
| 0</literal>.</para> |
| |
| <para>The hash defines several "magic keys" as well. All these keys |
| start with an underscore. The most notable is the |
| <literal>_text</literal> key which retrieves the text of the node: |
| <literal>${book.@title._text}</literal> will render the value of the |
| attribute into the template. Similarly, <literal>_name</literal> |
| will retrieve the name of the element or attribute. |
| <literal>*</literal> or <literal>_allChildren</literal> returns all |
| direct children elements of all elements in the node list, while |
| <literal>@*</literal> or <literal>_allAttributes</literal> returns |
| all attributes of the elements in the node list. There are many more |
| such keys; here's a detailed summary of all the hash keys:</para> |
| |
| <informaltable border="1"> |
| <thead> |
| <tr> |
| <th>Key name</th> |
| |
| <th>Evaluates to</th> |
| </tr> |
| </thead> |
| |
| <tbody> |
| <tr> |
| <td><literal>*</literal> or <literal>_children</literal></td> |
| |
| <td>all direct element children of current nodes |
| (non-recursive). Applicable to element and document |
| nodes.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>@*</literal> or |
| <literal>_attributes</literal></td> |
| |
| <td>all attributes of current nodes. Applicable to elements |
| only.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>@<replaceable>attributeName</replaceable></literal></td> |
| |
| <td>named attributes of current nodes. Applicable to elements, |
| doctypes and processing instructions. On doctypes it supports |
| attributes <literal>publicId</literal>, |
| <literal>systemId</literal> and |
| <literal>elementName</literal>. On processing instructions, it |
| supports attributes <literal>target</literal> and |
| <literal>data</literal>, as well as any other attribute name |
| specified in data as <literal>name="value"</literal> pair. The |
| attribute nodes for doctype and processing instruction are |
| synthetic, and as such have no parent. Note, however that |
| <literal>@*</literal> does NOT operate on doctypes or |
| processing instructions.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>_ancestor</literal></td> |
| |
| <td>all ancestors up to root element (recursive) of current |
| nodes. Applicable to same node types as |
| <literal>_parent</literal>.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>_ancestorOrSelf</literal></td> |
| |
| <td>all ancestors of current nodes plus current nodes. |
| Applicable to same node types as |
| <literal>_parent</literal>.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>_content</literal></td> |
| |
| <td>the complete content of current nodes, including children |
| elements, text, entity references, and processing instructions |
| (non-recursive). Applicable to elements and documents.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>_descendant</literal></td> |
| |
| <td>all recursive descendant element children of current |
| nodes. Applicable to document and element nodes.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>_descendantOrSelf</literal></td> |
| |
| <td>all recursive descendant element children of current nodes |
| plus current nodes. Applicable to document and element |
| nodes.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>_document</literal></td> |
| |
| <td>all documents the current nodes belong to. Applicable to |
| all nodes except text.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>_doctype</literal></td> |
| |
| <td>doctypes of the current nodes. Applicable to document |
| nodes only.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>_filterType</literal></td> |
| |
| <td>is a filter-by-type template method model. When called, it |
| will yield a node list that contains only those current nodes |
| whose type matches one of types passed as argument. You should |
| pass arbitrary number of strings to this method containing the |
| names of types to keep. Valid type names are: "attribute", |
| "cdata", "comment", "document", "documentType", "element", |
| "entity", "entityReference", "processingInstruction", |
| "text".</td> |
| </tr> |
| |
| <tr> |
| <td><literal>_name</literal></td> |
| |
| <td>the names of current nodes, one string per node |
| (non-recursive). Applicable to elements and attributes |
| (returns their local names), entities, processing instructions |
| (returns its target), doctypes (returns its public ID)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>_nsprefix</literal></td> |
| |
| <td>the namespace prefixes of current nodes, one string per |
| node (non-recursive). Applicable to elements and |
| attributes</td> |
| </tr> |
| |
| <tr> |
| <td><literal>_nsuri</literal></td> |
| |
| <td>the namespace URIs of current nodes, one string per node |
| (non-recursive). Applicable to elements and attributes</td> |
| </tr> |
| |
| <tr> |
| <td><literal>_parent</literal></td> |
| |
| <td>parent elements of current nodes. Applicable to element, |
| attribute, comment, entity, processing instruction.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>_qname</literal></td> |
| |
| <td>the qualified names of current nodes in |
| <literal>[namespacePrefix:]localName</literal> form, one |
| string per node (non-recursive). Applicable to elements and |
| attributes</td> |
| </tr> |
| |
| <tr> |
| <td><literal>_registerNamespace(prefix, uri)</literal></td> |
| |
| <td>register a XML namespace with the specified prefix and URI |
| for the current node list and all node lists that are derived |
| from the current node list. After registering, you can use the |
| <literal>nodelist["prefix:localname"]</literal>, or |
| <literal>nodelist["@prefix:localname"]</literal> syntax (or |
| <literal>nodelist.prefix\:localname</literal>, or |
| <literal>nodelist.@prefix\:localname</literal>) to reach |
| elements, and attributes whose names are namespace-scoped. |
| Note that the namespace prefix need not match the actual |
| prefix used by the XML document itself since namespaces are |
| compared solely by their URI. Also note that if you do |
| <literal>doc.elem1._registerNamespace(<replaceable>...</replaceable>)</literal>, |
| and then later you use <literal>doc.elem1</literal> again, it |
| will not have the prefix registered, because each time you use |
| <literal>doc.elem1</literal>, it gives a completely new |
| object. In this example, you certainly should have used |
| <literal>doc._registerNamespace(<replaceable>...</replaceable>)</literal>.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>_text</literal></td> |
| |
| <td>the text of current nodes, one string per node |
| (non-recursive). Applicable to elements, attributes, comments, |
| processing instructions (returns its data) and CDATA sections. |
| The reserved XML characters ('<' and '&') are not |
| escaped.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>_type</literal></td> |
| |
| <td>Returns a node list containing one string per node |
| describing the type of the node. Possible node type names are: |
| "attribute", "cdata", "comment", "document", "documentType", |
| "element", "entity", "entityReference", |
| "processingInstruction", "text". If the type of the node is |
| unknown, returns "unknown".</td> |
| </tr> |
| |
| <tr> |
| <td><literal>_unique</literal></td> |
| |
| <td>a copy of the current nodes that keeps only the first |
| occurrence of every node, eliminating duplicates. Duplicates |
| can occur in the node list by applying uptree-traversals |
| <literal>_parent</literal>, <literal>_ancestor</literal>, |
| <literal>_ancestorOrSelf</literal>, and |
| <literal>_document</literal>. I.e. |
| <literal>foo._children._parent</literal> will return a node |
| list that has duplicates of nodes in foo - each node will have |
| the number of occurrences equal to the number of its children. |
| In these cases, use |
| <literal>foo._children._parent._unique</literal> to eliminate |
| duplicates. Applicable to all node types.</td> |
| </tr> |
| |
| <tr> |
| <td>any other key</td> |
| |
| <td>element children of current nodes with name matching the |
| key. This allows for convenience child traversal in |
| <literal>book.chapter.title</literal> style syntax. Note that |
| <literal>nodeset.childname</literal> is technically equivalent |
| to <literal>nodeset("childname")</literal>, but is both |
| shorter to write and evaluates faster. Applicable to document |
| and element nodes.</td> |
| </tr> |
| </tbody> |
| </informaltable> |
| </section> |
| |
| <section> |
| <title>TemplateMethodModel</title> |
| |
| <para>When used as a method model, it returns a node list that is |
| the result of evaluating an XPath expression on the current contents |
| of the node list. For this feature to work, you must have the |
| <literal>Jaxen</literal> library in your classpath. For |
| example:</para> |
| |
| <programlisting role="template"><#assign firstChapter=xmldoc("//chapter[first()]")></programlisting> |
| </section> |
| |
| <section> |
| <title>Namespace handling</title> |
| |
| <para>For purposes of traversal of children elements that have |
| namespace-scoped names, you can register namespace prefixes with the |
| node list. You can do it either in Java, calling the</para> |
| |
| <programlisting role="unspecified">public void registerNamespace(String prefix, String uri);</programlisting> |
| |
| <para>method, or inside a template using the</para> |
| |
| <programlisting role="template">${<replaceable>nodelist</replaceable>._registerNamespace(<replaceable>prefix</replaceable>, <replaceable>uri</replaceable>)}</programlisting> |
| |
| <para>syntax. From there on, you can refer to children elements in |
| the namespace denoted by the particular URI through the |
| syntax</para> |
| |
| <programlisting role="metaTemplate"><literal><replaceable>nodelist</replaceable>["<replaceable>prefix</replaceable>:<replaceable>localName</replaceable>"]</literal></programlisting> |
| |
| <para>and</para> |
| |
| <programlisting role="metaTemplate"><literal><replaceable>nodelist</replaceable>["@<replaceable>prefix</replaceable>:<replaceable>localName</replaceable>"]</literal></programlisting> |
| |
| <para>as well as use these namespace prefixes in XPath expressions. |
| Namespaces registered with a node list are propagated to all node |
| lists that are derived from the original node list. Note also that |
| namespaces are matched by their URI only, so you can safely use a |
| prefix for a namespace inside your template that differs from the |
| prefix in the actual XML document - a prefix is just a local alias |
| for the URI both in the template and in the XML document.</para> |
| </section> |
| </section> |
| |
| <section xml:id="pgui_misc_ant"> |
| <title>Using FreeMarker with Ant</title> |
| |
| <indexterm> |
| <primary>ant task</primary> |
| </indexterm> |
| |
| <para>There are two <quote>FreeMarker Ant tasks</quote> that we know |
| about:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>FreemarkerXmlTask</literal>: It comes with the |
| FreeMarker distribution, packed into the |
| <literal>freemarker.jar</literal>. This is a lightweight, |
| easy-to-use Ant task for transforming XML documents with |
| FreeMarker templates. Its approach is that the source files (input |
| files) are XML files, which are rendered to corresponding output |
| files, by a single template. That is, for each XML file, the |
| template will be executed (with the XML document in the |
| data-model), and the template output will be written into a file |
| of similar name than the name of the XML file. Thus, the template |
| file plays a similar role as an XSLT style sheet, but it is FTL, |
| not XSLT.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>command-line</primary> |
| </indexterm> FMPP: It's a more heavyweight, less XML centric, |
| third party Ant task (and standalone command-line tool). Its |
| primary approach is that the source files (input files) are |
| template files that generate the corresponding output files |
| themselves, but it also supports the approach of |
| <literal>FreemarkerXmlTask</literal> for the source files that are |
| XML-s. Also, it has extra features over the |
| <literal>FreemarkerXmlTask</literal>. What's its drawback then? As |
| it is more complex and more generalized, it's harder to learn and |
| use it.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>This section introduces the |
| <literal>FreemarkerXmlTask</literal>. For more information about FMPP |
| visit its homepage: <link |
| xlink:href="http://fmpp.sourceforge.net/">http://fmpp.sourceforge.net/</link>.</para> |
| |
| <para>In order to use the <literal>FreemarkerXmlTask</literal>, you |
| must first define the |
| <literal>freemarker.ext.ant.FreemarkerXmlTask</literal> inside your |
| Ant buildfile, then call the task. Suppose you want to transform |
| several XML documents to HTML using the hypothetical "xml2html.ftl" |
| template, with XML documents located in the directory "xml" and HTML |
| documents generated into directory "html". You would write something |
| like:</para> |
| |
| <programlisting role="unspecified"><taskdef name="freemarker" classname="freemarker.ext.ant.FreemarkerXmlTask"> |
| <classpath> |
| <pathelement location="freemarker.jar" /> |
| </classpath> |
| </taskdef> |
| <mkdir dir="html" /> |
| <freemarker basedir="xml" destdir="html" includes="**/*.xml" template="xml2html.ftl" /></programlisting> |
| |
| <para>The task would invoke the template for every XML document. Every |
| document would be parsed into a DOM tree, then wrapped as a FreeMarker |
| node variable. When template processing begins, the special variable, |
| <literal>.node</literal>, is set to the root node of the XML |
| document.</para> |
| |
| <para>Note that if you are using the legacy (FreeMarker 2.2.x and |
| earlier) XML adapter implementation, that still works, and the root of |
| the XML tree is placed in the data-model as the variable |
| <literal>document</literal>. That contains an instance of the legacy |
| <literal>freemarker.ext.xml.NodeListModel</literal> class.</para> |
| |
| <para>Note that all properties defined by the build file would be made |
| available as a hash model named "properties". Several other models are |
| made available; for detailed description of what variables are made |
| available to templates as well as what other attributes can the task |
| accept, see the JavaDoc for |
| <literal>freemarker.ext.ant.FreemarkerXmlTask</literal>.</para> |
| </section> |
| |
| <section xml:id="pgui_misc_jythonwrapper"> |
| <title>Jython wrapper</title> |
| |
| <indexterm> |
| <primary>wrapping</primary> |
| |
| <secondary>jython</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>jython</primary> |
| |
| <secondary>wrapping</secondary> |
| </indexterm> |
| |
| <para>The <literal>freemarker.ext.jython</literal> package consists of |
| models that enable any Jython object to be used as a |
| <literal>TemplateModel</literal>. In the very basic case, you only |
| need to call the</para> |
| |
| <programlisting role="unspecified">public TemplateModel wrap(Object obj);</programlisting> |
| |
| <para>method of the |
| <literal>freemarker.ext.jython.JythonWrapper</literal> class. This |
| method will wrap the passed object into an appropriate |
| <literal>TemplateModel</literal>. Below is a summary of the properties |
| of returned model wrappers. Let's assume that the model that resulted |
| from the <literal>JythonWrapper</literal> call on object |
| <literal>obj</literal> is named <literal>model</literal> in the |
| template model root for the sake of the following discussion.</para> |
| |
| <section> |
| <title>TemplateHashModel functionality</title> |
| |
| <para><literal>PyDictionary</literal> and |
| <literal>PyStringMap</literal> will be wrapped into a hash model. |
| Key lookups are mapped to the <literal>__finditem__</literal> |
| method; if an item is not found, a model for <literal>None</literal> |
| is returned.</para> |
| </section> |
| |
| <section> |
| <title>TemplateScalarModel functionality</title> |
| |
| <para>Every python object will implement |
| <literal>TemplateScalarModel</literal> whose |
| <literal>getAsString()</literal> method simply delegates to |
| <literal>toString()</literal>.</para> |
| </section> |
| |
| <section> |
| <title>TemplateBooleanModel functionality</title> |
| |
| <para>Every python object will implement |
| <literal>TemplateBooleanModel</literal> whose |
| <literal>getAsBoolean()</literal> method simply delegates to |
| <literal>__nonzero__()</literal> in accordance with Python semantics |
| of true/false.</para> |
| </section> |
| |
| <section> |
| <title>TemplateNumberModel functionality</title> |
| |
| <para>Model wrappers for <literal>PyInteger</literal>, |
| <literal>PyLong</literal>, and <literal>PyFloat</literal> objects |
| implement <literal>TemplateNumberModel</literal> whose |
| <literal>getAsNumber()</literal> method returns |
| <literal>__tojava__(java.lang.Number.class)</literal>.</para> |
| </section> |
| |
| <section> |
| <title>TemplateSequenceModel functionality</title> |
| |
| <para>Model wrappers for all classes that extend |
| <literal>PySequence</literal> will implement |
| <literal>TemplateSequenceModel</literal> and thus their elements |
| will be accessible by index using the <literal>model[i]</literal> |
| syntax, which will delegate to <literal>__finditem__(i)</literal>. |
| You can also query the length of the array or the size of the list |
| using the <literal>model?size</literal> built-in, which will |
| delegate to <literal>__len__()</literal>.</para> |
| </section> |
| </section> |
| </chapter> |
| </part> |
| |
| <part xml:id="ref"> |
| <title>Template Language Reference</title> |
| |
| <chapter xml:id="ref_builtins"> |
| <title>Built-in Reference</title> |
| |
| <indexterm> |
| <primary>built-in</primary> |
| </indexterm> |
| |
| <section xml:id="ref_builtins_alphaidx"> |
| <title>Alphabetical index</title> |
| |
| <note> |
| <para>As of FreeMarker 2.3.23, you can use camel case instead of |
| snake case for directive names, like <literal>startsWith</literal> |
| instead of <literal>starts_with</literal>. But know that then within |
| the same template, FreeMarker will enforce the usage of camel case |
| for all identifiers that are part of the template language (user |
| defined names are not affected).</para> |
| </note> |
| |
| <indexterm> |
| <primary>built-in</primary> |
| </indexterm> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><link linkend="ref_builtin_abs">abs</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_absolute_template_name">absolute_template_name</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_ancestors">ancestors</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_buitin_api_and_has_api">api</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_boolean">boolean</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_numType">byte</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>c <link linkend="ref_builtin_c">for numbers</link>, <link |
| linkend="ref_builtin_c_boolean">for booleans</link>, <link |
| linkend="ref_builtin_c_string">for strings</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_c_lower_case">c_lower_case</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_c_upper_case">c_upper_case</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_cap_first">cap_first</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_capitalize">capitalize</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_rounding">ceiling</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_children">children</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_chop_linebreak">chop_linebreak</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_chunk">chunk</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_cn">cn</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_contains">contains</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_counter">counter</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>date <link linkend="ref_builtin_date_datetype">for |
| dates</link>, <link linkend="ref_builtin_string_date">for |
| strings</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_date_if_unknown">date_if_unknown</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>datetime <link linkend="ref_builtin_date_datetype">for |
| dates</link>, <link linkend="ref_builtin_string_date">for |
| strings</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_date_if_unknown">datetime_if_unknown</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_numType">double</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_drop_while">drop_while</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_esc">esc</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_ends_with">ends_with</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_ensure_ends_with">ensure_ends_with</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_ensure_starts_with">ensure_starts_with</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_eval">eval</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_eval_json">eval_json</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_filter">filter</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_first">first</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_rounding">floor</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_groups">groups</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_numType">float</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_buitin_api_and_has_api">has_api</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_has_content">has_content</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_has_next">has_next</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_html">html</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_index">index</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_index_of">index_of</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_numType">int</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_interpret">interpret</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_item_cycle">item_cycle</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_item_parity">item_parity</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_item_parity_cap">item_parity_cap</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_is_even_item">is_even_item</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_first">is_first</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_is_infinite">is_infinite</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_is_last">is_last</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_is_nan">is_nan</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_is_odd_item">is_odd_item</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_isType">is_<replaceable>type</replaceable></link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_date_iso">iso, |
| iso_...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_j_string">j_string</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_join">join</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_js_string">js_string</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_keep_after">keep_after</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_keep_after_last">keep_after_last</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_keep_before">keep_before</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_keep_before_last">keep_before_last</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_keys">keys</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_last">last</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_last_index_of">last_index_of</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_left_pad">left_pad</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_length">length</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_numType">long</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_lower_abc">lower_abc</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_lower_case">lower_case</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_map">map</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_markup_string">markup_string</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_matches">matches</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_min_max">max</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_min_max">min</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_namespace">namespace</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_new">new</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_next_sibling">next_sibling</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_no_esc">no_esc</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_node_namespace">node_namespace</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_node_name">node_name</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_node_type">node_type</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_number">number</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_numToDate">number_to_date, |
| number_to_datetime, number_to_time</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_parent">parent</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_previous_sibling">previous_sibling</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_replace">replace</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_remove_beginning">remove_beginning</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_remove_ending">remove_ending</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_reverse">reverse</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_right_pad">right_pad</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_rounding">round</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_root">root</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_rtf">rtf</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_numType">short</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_size">size</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_sort">sort</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_seq_contains">seq_contains</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_seq_index_of">seq_index_of</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_seq_last_index_of">seq_last_index_of</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_sequence">sequence</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_sort_by">sort_by</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_split">split</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_starts_with">starts_with</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>string: <link linkend="ref_builtin_string_for_string">for |
| strings</link>, <link linkend="ref_builtin_string_for_number">for |
| numbers</link>, <link linkend="ref_builtin_string_for_boolean">for |
| booleans</link>, <link linkend="ref_builtin_string_for_date">for |
| date/time/date-time</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_substring">substring</link> |
| (deprecated)</para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_switch">switch</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_take_while">take_while</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_then">then</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>time <link linkend="ref_builtin_date_datetype">for |
| date/time/date-time</link>, <link |
| linkend="ref_builtin_string_date">for strings</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_date_if_unknown">time_if_unknown</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_trim">trim</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_truncate">truncate, |
| truncate_<replaceable>...</replaceable></link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_uncap_first">uncap_first</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_upper_abc">upper_abc</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_upper_case">upper_case</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_url">url</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_values">values</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_with_args">with_args</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_with_args_last">with_args_last</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_word_list">word_list</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_xhtml">xhtml</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtin_xml">xml</link></para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>See the built-ins filtered by left-hand-value type <link |
| linkend="ref_builtins">here</link>.</para> |
| |
| <para>If you don't find a built-in here that you have seen in a |
| working template, probably you will find it here: <xref |
| linkend="ref_deprecated"/></para> |
| </section> |
| |
| <section xml:id="ref_builtins_string"> |
| <title>Built-ins for strings</title> |
| |
| <indexterm> |
| <primary>string</primary> |
| |
| <secondary>built-ins</secondary> |
| </indexterm> |
| |
| <para>These built-ins act on a string left-value. However, if the |
| left-value is number or date/time/date-time or boolean (since 2.3.20), |
| it will automatically converted to string according the current |
| number-, date/time/date-time- and boolean-format settings (which are |
| the same formatters that are applied when inserting such values with |
| <literal>${<replaceable>...</replaceable>}</literal>).</para> |
| |
| <section xml:id="ref_builtin_boolean"> |
| <title>boolean</title> |
| |
| <indexterm> |
| <primary>type-casting</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting between types</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>boolean built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>string to boolean</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting string to boolean</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>parse string as boolean</primary> |
| </indexterm> |
| |
| <para>The string converted to boolean value. The string must be |
| <literal>true</literal> or <literal>false</literal> (case |
| sensitive!), or must be in the format specified by the |
| <literal>boolean_format</literal> setting.</para> |
| |
| <para>If the string is not in the appropriate format, an error will |
| abort template processing when you try to access this |
| built-in.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_cap_first"> |
| <title>cap_first</title> |
| |
| <indexterm> |
| <primary>cap_first built-in</primary> |
| </indexterm> |
| |
| <para>The string with the very first word of the string capitalized. |
| For the precise meaning of <quote>word</quote> see the <link |
| linkend="ref_builtin_word_list">word_list built-in</link>. |
| Example:</para> |
| |
| <programlisting role="template">${" green mouse"?cap_first} |
| ${"GreEN mouse"?cap_first} |
| ${"- green mouse"?cap_first}</programlisting> |
| |
| <para>The output:</para> |
| |
| <programlisting role="output"> Green mouse |
| GreEN mouse |
| - green mouse</programlisting> |
| |
| <para>In the case of <literal>"- green mouse"</literal>, the first |
| word is the <literal>-</literal>.</para> |
| |
| <para>Note that this uses locale-aware conversion, that is, the |
| result can be different depending on the current |
| <literal>locale</literal> (language, country).</para> |
| </section> |
| |
| <section xml:id="ref_builtin_c_string"> |
| <title>c (for string value)</title> |
| |
| <indexterm> |
| <primary>c built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>format</primary> |
| |
| <secondary>string</secondary> |
| </indexterm> |
| |
| <note> |
| <para>The <literal>c</literal> built-in also works <link |
| linkend="ref_builtin_c">on numbers</link>, and <link |
| linkend="ref_builtin_c_boolean">on booleans</link>!</para> |
| </note> |
| |
| <note> |
| <para>To provide a background, see <xref |
| linkend="dgui_misc_computer_vs_human_format"/></para> |
| </note> |
| |
| <note> |
| <para>The <literal>c</literal> built-in supports strings since |
| FreeMarker 2.3.32.</para> |
| </note> |
| |
| <para>This built-in converts a string to a <quote>computer |
| language</quote> literal, according the value of the <link |
| linkend="gloss.c_format"><literal>c_format</literal> |
| setting</link>.</para> |
| |
| <para>For the <literal>c_format</literal>-s that are built into |
| FreeMarker the rules are the following:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><quote>JSON</quote>, <quote>legacy</quote>: Gives a JSON |
| string literal, that is, it will be surrounded with quotation |
| marks (<literal>"</literal>), and will be escaped using |
| backslash (<literal>\</literal>) where needed. For the exact |
| escaping rules see <link linkend="ref_builtin_json_string">the |
| <literal>json_string</literal> built-in</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><quote>JavaScript</quote>: Almost the same as JSON, but |
| uses <literal>\x<replaceable>XX</replaceable></literal> instead |
| of <literal>\u<replaceable>XXXX</replaceable></literal> where |
| possible. For the exact escaping rules see <link |
| linkend="ref_builtin_js_string">the <literal>js_string</literal> |
| built-in</link>, except that this won't escape the apostrophe |
| quote (since it knows that it has used quotation marks around |
| the string literal).</para> |
| </listitem> |
| |
| <listitem> |
| <para><quote>Java</quote>: Gives a Java string literal, that is, |
| it will be surrounded with quotation marks |
| (<literal>"</literal>), and will be escaped using backslash |
| (<literal>\</literal>) where needed. For the exact escaping |
| rules see <link linkend="ref_builtin_j_string">the |
| <literal>j_string</literal> built-in</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><quote>XS</quote>: Leaves the string as is. The idea is |
| that you will insert the value as the body of an XML element, or |
| into an XML attribute, so it needs no quotation, or any other |
| special syntax. While it does need XML encoding, that should be |
| handled by the <link linkend="dgui_misc_autoescaping">automatic |
| escaping facility</link>, and not by the |
| <literal>c_format</literal> facility.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>If the value the <literal>c</literal> built-in is applied on |
| is <literal>null</literal>/missing, it will stop the template |
| processing with error, just like most other built-ins. If instead |
| you want to output a <literal>null</literal> literal, see the <link |
| linkend="ref_builtin_cn_string"><literal>cn</literal> |
| built-in</link>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_cn_string"> |
| <title>cn (for string value)</title> |
| |
| <indexterm> |
| <primary>cn built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>format</primary> |
| |
| <secondary>string</secondary> |
| </indexterm> |
| |
| <para>This does the same as the <link |
| linkend="ref_builtin_c_string"><literal>c</literal> built-in</link>, |
| but when applied on a <literal>null</literal>/missing value, it will |
| output a <literal>null</literal> value according the <link |
| linkend="gloss.c_format"><literal>c_format</literal> setting</link>. |
| See more details about formatting a <literal>null</literal> <link |
| linkend="ref_builtin_cn">here</link>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_c_lower_case"> |
| <title>c_lower_case</title> |
| |
| <indexterm> |
| <primary>c_lower_case built-in</primary> |
| </indexterm> |
| |
| <para>The string converted to lower case, for computer consumption |
| (<quote>c</quote> as in the <link |
| linkend="ref_builtin_c"><literal>c</literal> built-in</link>). Put |
| simply, it will be converted to lower case as in English, regardless |
| of the current <literal>locale</literal> (language, country). For |
| example <literal>"ITEM list"?c_lower_case</literal> will be |
| <literal>"item list"</literal>, always.</para> |
| |
| <para>For lower case conversion for human consumption use the <link |
| linkend="ref_builtin_lower_case"><literal>lower_case</literal> |
| built-in</link> instead!</para> |
| </section> |
| |
| <section xml:id="ref_builtin_c_upper_case"> |
| <title>c_upper_case</title> |
| |
| <indexterm> |
| <primary>c_upper_case built-in</primary> |
| </indexterm> |
| |
| <para>The string converted to upper case, for computer consumption |
| (<quote>c</quote> as in the <link |
| linkend="ref_builtin_c"><literal>c</literal> built-in</link>). Put |
| simply, it will be converted to upper case as in English, regardless |
| of the current <literal>locale</literal> (language, country). For |
| example <literal>"ITEM list"?c_upper_case</literal> will be |
| <literal>"ITEM LIST"</literal>, always.</para> |
| |
| <para>For upper case conversion for human consumption use the <link |
| linkend="ref_builtin_upper_case"><literal>upper_case</literal> |
| built-in</link> instead!</para> |
| </section> |
| |
| <section xml:id="ref_builtin_capitalize"> |
| <title>capitalize</title> |
| |
| <indexterm> |
| <primary>capitalize built-in</primary> |
| </indexterm> |
| |
| <para>The string with all words capitalized. For the precise meaning |
| of <quote>word</quote> see the <link |
| linkend="ref_builtin_word_list">word_list built-in</link>. |
| Example:</para> |
| |
| <programlisting role="template">${" green mouse"?capitalize} |
| ${"GreEN mouse"?capitalize}</programlisting> |
| |
| <para>The output:</para> |
| |
| <programlisting role="output"> Green Mouse |
| Green Mouse</programlisting> |
| </section> |
| |
| <section xml:id="ref_builtin_chop_linebreak"> |
| <title>chop_linebreak</title> |
| |
| <indexterm> |
| <primary>chop_linebreak built-in</primary> |
| </indexterm> |
| |
| <para>Returns the string without the <link |
| linkend="gloss.lineBreak">line-break</link> at its very end if there |
| was a line-break, otherwise the unchanged string. If the string ends |
| with multiple line-breaks, only the last line-break is |
| removed.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_contains"> |
| <title>contains</title> |
| |
| <indexterm> |
| <primary>contains built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.1. It |
| doesn't exist in 2.3.</para> |
| </note> |
| |
| <para>Returns if the substring specified as the parameter to this |
| built-in occurrs in the string. For example:</para> |
| |
| <programlisting role="template"><#if "piceous"?contains("ice")>It contains "ice"</#if></programlisting> |
| |
| <para>This will output:</para> |
| |
| <programlisting role="output">It contains "ice"</programlisting> |
| </section> |
| |
| <section xml:id="ref_builtin_string_date"> |
| <title>date, time, datetime</title> |
| |
| <indexterm> |
| <primary>type-casting</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting between types</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>date built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>time built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>datetime built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>string to date</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>string to time</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting string to date</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting string to time</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>parsing string as date</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>parsing string as time</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>XML Schema date parsing</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>XML Schema time parsing</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>ISO 8601 parsing</primary> |
| </indexterm> |
| |
| <para>The string value converted to a date, time, or date-time |
| value. It will expect the format specified by the <link |
| linkend="topic.dateTimeFormatSettings"><literal>date_format</literal>, |
| <literal>time_format</literal> and |
| <literal>datetime_format</literal> settings</link>. If the string is |
| not in the appropriate format, an error will abort template |
| processing when you try to access this built-in.</para> |
| |
| <programlisting role="template"><#-- The date_format, time_format and datetime_format settings must match this format! --> |
| <#assign someDate = "Oct 25, 1995"?date> |
| <#assign someTime = "3:05:30 PM"?time> |
| <#assign someDatetime = "Oct 25, 1995 03:05:00 PM"?datetime> |
| |
| <#-- Changing the setting value changes the expected format: --> |
| <#setting datetime_format="iso"> |
| <#assign someDatetime = "1995-10-25T15:05"?datetime> |
| </programlisting> |
| |
| <para>You can also specify the format explicitly like |
| <literal>?datetime.<replaceable>format</replaceable></literal> (and |
| hence also as |
| <literal>?datetime["<replaceable>format</replaceable>"]</literal>) |
| or |
| <literal>?datetime("<replaceable>format</replaceable>")</literal>; |
| these three forms do the same. The format can be specified similarly |
| with <literal>?date</literal> and <literal>?time</literal> too. For |
| the syntax and meaning of format values see the possible values of |
| the <link |
| linkend="topic.dateTimeFormatSettings"><literal>date_format</literal>, |
| <literal>time_format</literal> and |
| <literal>datetime_format</literal> settings</link>. Example:</para> |
| |
| <programlisting role="template"><#-- Parsing XML Schema xs:date, xs:time and xs:dateTime values: --> |
| <#assign someDate = "1995-10-25"?date.xs> |
| <#assign someTime = "15:05:30"?time.xs> |
| <#assign someDatetime = "1995-10-25T15:05:00"?datetime.xs> |
| |
| <#-- Parsing ISO 8601 (both extended and basic formats): --> |
| <#assign someDatetime = "1995-10-25T15:05"?datetime.iso> |
| <#assign someDatetime = "19951025T1505"?datetime.iso> |
| |
| <#-- Parsing with SimpleDateFormat patterns: --> |
| <#assign someDate = "10/25/1995"?date("MM/dd/yyyy")> |
| <#assign someTime = "15:05:30"?time("HH:mm:ss")> |
| <#assign someDatetime = "1995-10-25 03:05 PM"?datetime("yyyy-MM-dd hh:mm a")> |
| |
| <#-- Parsing with custom date formats: --> |
| <#assign someDatetime = "October/25/1995 03:05 PM"?datetime.@worklog></programlisting> |
| |
| <para>To prevent misunderstandings, the left-hand value need not be |
| a string literal. For example, when you read data from XML DOM (from |
| where all values come as unparsed strings), you may do things like |
| <literal>order.confirmDate?date.xs</literal> to convert the string |
| value to a real date.</para> |
| |
| <para>Of course, the format also can be a variable, like in |
| <literal>"<replaceable>...</replaceable>"?datetime(myFormat)</literal>.</para> |
| |
| <para>Note that since 2.3.24, these built-ins can also be called |
| with 0 arguments, like <literal>?date()</literal>. It's almost the |
| same as just writing <literal>?date</literal>. The difference is |
| highly technical and rarely matters: <literal>?date()</literal> and |
| such returns exactly the same Java object that the date parser |
| (<literal>freemarker.core.TemplateDateFormat</literal> |
| implementation) returns, while <literal>?date</literal> without the |
| <literal>()</literal> returns a tricky wrapper value that's a date |
| and a method and hash on the same time.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_ends_with"> |
| <title>ends_with</title> |
| |
| <indexterm> |
| <primary>ends_with built-in</primary> |
| </indexterm> |
| |
| <para>Returns whether this string ends with the substring specified |
| in the parameter. For example |
| <literal>"ahead"?ends_with("head")</literal> returns boolean |
| <literal>true</literal>. Also, |
| <literal>"head"?ends_with("head")</literal> will return |
| <literal>true</literal>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_ensure_ends_with"> |
| <title>ensure_ends_with</title> |
| |
| <indexterm> |
| <primary>ensure_ends_with built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.21.</para> |
| </note> |
| |
| <para>If the string doesn't end with the substring specified as the |
| 1st parameter, it adds it after the string, otherwise it returns the |
| original string. For example, both |
| <literal>"foo"?ensure_ends_with("/")</literal> and |
| <literal>"foo/"?ensure_ends_with("/")</literal> returns |
| <literal>"foo/"</literal>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_ensure_starts_with"> |
| <title>ensure_starts_with</title> |
| |
| <indexterm> |
| <primary>ensure_ends_with built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.21.</para> |
| </note> |
| |
| <para>If the string doesn't start with the substring specified as |
| the 1st parameter, it adds it before the string, otherwise it |
| returns the original string. For example, both |
| <literal>"foo"?ensure_starts_with("/")</literal> and |
| <literal>"/foo"?ensure_starts_with("/")</literal> returns |
| <literal>"/foo"</literal>.</para> |
| |
| <para>If you specify two parameters, then the 1st parameter is |
| interpreted as a Java regular expression, and if it doesn't match |
| the beginning of the string, then the string specified as the 2nd |
| parameter is added before the string. For example |
| <literal>someURL?ensure_starts_with("[a-zA-Z]+://", |
| "http://")</literal> will check if the string starts with something |
| that matches <literal>"[a-zA-Z]+://"</literal> (note that no |
| <literal>^</literal> is needed), and if it doesn't, it prepends |
| <literal>"http://"</literal>.</para> |
| |
| <para>This method also accepts a 3rd <link |
| linkend="ref_builtin_string_flags">flags parameter</link>. As |
| calling with 2 parameters implies <literal>"r"</literal> there |
| (i.e., regular expression mode), you rarely need this. One notable |
| case is when you don't want the 1st parameter to be interpreted as a |
| regular expression, only as plain text, but you want the comparison |
| to be case-insensitive, in which case you would use |
| <literal>"i"</literal> as the 3rd parameter.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_esc"> |
| <title>esc</title> |
| |
| <para><indexterm> |
| <primary>esc built-in</primary> |
| </indexterm></para> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.24.</para> |
| </note> |
| |
| <para>Escapes the value with the current <link |
| linkend="dgui_misc_autoescaping_outputformat">output format</link>, |
| and prevents the <link |
| linkend="dgui_misc_autoescaping">auto-escaping</link> of the |
| returned value (to avoid double escaping). Because of auto-escaping, |
| you usually only need this where auto-escaping was disabled:</para> |
| |
| <programlisting role="template"><#ftl output_format="HTML" <emphasis>auto_esc=false</emphasis>> |
| <#assign s = "R&D"> |
| ${s} |
| ${s?esc}</programlisting> |
| |
| <programlisting role="output">R&D |
| R&amp;D</programlisting> |
| |
| <para>In templates, where auto-escaping is on, using it is |
| redundant:</para> |
| |
| <programlisting role="template"><#ftl output_format="HTML"> |
| <#assign s = "R&D"> |
| ${s} |
| ${s?esc} <#-- ?esc is redundant here --></programlisting> |
| |
| <programlisting role="output">R&amp;D |
| R&amp;D</programlisting> |
| |
| <para>This built-in works by converting the string value to a <link |
| linkend="dgui_misc_autoescaping_movalues">markup output |
| value</link>, by escaping the string with the current output format, |
| and using the result as the markup. The resulting markup output |
| value belongs to the current output format at the point of the |
| invocation.</para> |
| |
| <para>This built-in can also be applied on markup output values, |
| which it will bypass without change, as far as the input markup |
| output value belongs to the current output format. If it doesn't, |
| then the markup has to be converted to the current output format, |
| which currently (as of 2.3.24) will be only successful if that value |
| was created by escaping plain text (usually, with |
| <literal>?esc</literal>).</para> |
| |
| <para>This built-in can't be used where the current output format is |
| a <link linkend="dgui_misc_autoescaping_nonmarkupof">non-markup |
| output format</link>. An attempt to do so will cause a <link |
| linkend="gloss.parseTimeError">parse-time error</link>.</para> |
| |
| <para>This built-in is not related to the deprecated <link |
| linkend="ref_directive_escape"><literal>escape</literal> and |
| <literal>noescape</literal> directives</link>. In fact, the parser |
| will prevent using them on the same place, to prevent |
| confusion.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_groups"> |
| <title>groups</title> |
| |
| <indexterm> |
| <primary>groups built-in</primary> |
| </indexterm> |
| |
| <para>This is used only with the result of the |
| <literal>matches</literal> built-in. See <link |
| linkend="ref_builtin_matches">there...</link></para> |
| </section> |
| |
| <section xml:id="ref_builtin_html"> |
| <title>html (deprecated)</title> |
| |
| <indexterm> |
| <primary>escaping</primary> |
| |
| <secondary>output</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>html built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is <emphasis>deprecated</emphasis> by the |
| <link linkend="dgui_misc_autoescaping">auto-escaping |
| mechanism</link> introduced in 2.3.24. To prevent double escaping |
| and confusion in general, using this built-in on places where |
| auto-escaping is active is a <link |
| linkend="gloss.parseTimeError">parse-time error</link>. To help |
| migration, this built-in silently bypasses HTML <link |
| linkend="dgui_misc_autoescaping_movalues">markup output |
| values</link> without changing them.</para> |
| </note> |
| |
| <para>The string as HTML markup. That is, the string with |
| all:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><</literal> replaced with |
| <literal>&lt;</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>></literal> replaced with |
| <literal>&gt;</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>&</literal> replaced with |
| <literal>&amp;</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>"</literal> replaced with |
| <literal>&quot;</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>'</literal> is replaced with |
| <literal>&#39;</literal> <emphasis>if</emphasis> the |
| programmers has <link |
| linkend="pgui_config_incompatible_improvements_how_to_set">set |
| the <literal>incompatible_improvements</literal> setting</link> |
| to 2.3.24 or higher (also if it's set to 2.3.20 or higher and |
| you are outside a string literal). Otherwise |
| <literal>'</literal> won't be replaced, so you must use |
| quotation mark (<literal>"</literal>, not <literal>'</literal>) |
| to quote attribute values where you want to insert a value |
| safely.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <programlisting role="template"><input type=text name=user value=<emphasis>"</emphasis>${user?html}<emphasis>"</emphasis>></programlisting> |
| |
| <warning> |
| <para>When inserting the value of an attribute, always quote it, |
| or else it can be exploited by attackers! This is WRONG: |
| <literal><input name="user" value=${user?xhtml}></literal>. |
| This is good: <literal><input name="user" |
| value="${user?xhtml}"></literal>.</para> |
| </warning> |
| |
| <para>Note that in HTML pages usually you want to use this built-in |
| for all interpolations. You can spare a lot of typing and lessen the |
| chances of accidental mistakes by using the <link |
| linkend="ref_directive_escape"><literal>escape</literal> |
| directive</link>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_index_of"> |
| <title>index_of</title> |
| |
| <indexterm> |
| <primary>index_of built-in</primary> |
| </indexterm> |
| |
| <para>Returns the index within this string of the first occurrence |
| of the specified substring. For example, |
| <literal>"abcabc"?index_of("bc")</literal> will return 1 (don't |
| forget that the index of the first character is 0). Also, you can |
| specify the index to start the search from: |
| <literal>"abcabc"?index_of("bc", 2)</literal> will return 4. There |
| is no restriction on the numerical value of the second parameter: if |
| it is negative, it has the same effect as if it were zero, and if it |
| is greater than the length of this string, it has the same effect as |
| if it were equal to the length of this string. Decimal values will |
| be truncated to integers.</para> |
| |
| <para>If the 1st parameter does not occur as a substring in this |
| string (starting from the given index, if you use the second |
| parameter), then it returns -1.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_j_string"> |
| <title>j_string</title> |
| |
| <indexterm> |
| <primary>j_string built-in</primary> |
| </indexterm> |
| |
| <para>Escapes the string with the escaping rules of Java language |
| string literals, so it's safe to insert the value into a string |
| literal. Note that it will <emphasis>not</emphasis> add quotation |
| marks around the inserted value; you meant to use this |
| <emphasis>inside</emphasis> the string literal.</para> |
| |
| <para>All characters under <link linkend="gloss.UCS">UCS</link> code |
| point 0x20 will be escaped. When they have no dedicated escape |
| sequence in the Java language (like <literal>\n</literal>, |
| <literal>\t</literal>, etc.), they will be replaced with a UNICODE |
| escape |
| (<literal>\u<replaceable>XXXX</replaceable></literal>).</para> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template"><#assign beanName = 'The "foo" bean.'> |
| String BEAN_NAME = "${beanName?j_string}";</programlisting> |
| |
| <para>will output:</para> |
| |
| <programlisting role="output">String BEAN_NAME = "The \"foo\" bean.";</programlisting> |
| </section> |
| |
| <section xml:id="ref_builtin_js_string"> |
| <title>js_string</title> |
| |
| <indexterm> |
| <primary>js_string built-in</primary> |
| </indexterm> |
| |
| <para>Escapes the string with the escaping rules of JavaScript |
| language string literals, so it's safe to insert the value into a |
| string literal. Note that it will <emphasis>not</emphasis> add |
| quotation marks around the inserted value; you meant to use this |
| <emphasis>inside</emphasis> the string literal.</para> |
| |
| <warning> |
| <para>When inserting into a JavaScript string literal that's |
| inside a HTML attribute, you also must escape the value with HTML |
| escaping. Thus, of you don't have <link |
| linkend="pgui_config_outputformatsautoesc">automatic HTML |
| escaping</link>, this is WRONG: <literal><p |
| onclick="alert('${message?js_string}')"></literal>, and this is |
| good: <literal><p |
| onclick="alert('${message?js_string?html}')"></literal>.</para> |
| </warning> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template"><#assign user = "Big Joe's \"right hand\""> |
| <script> |
| alert("Welcome ${user?js_string}!"); |
| </script></programlisting> |
| |
| <para>will output:</para> |
| |
| <programlisting role="output"><script> |
| alert("Welcome Big Joe\'s \"right hand\"!"); |
| </script></programlisting> |
| |
| <para>The exact escaping rules are:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>"</literal> is escaped as |
| <literal>\"</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>'</literal> is escaped as |
| <literal>\'</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>\</literal> is escaped as |
| <literal>\\</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>/</literal> is escaped as <literal>\/</literal> |
| if the <literal>/</literal> is directly after |
| <literal><</literal> in the escaped string, or if it's at the |
| beginning of the escaped string</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>></literal> is escaped as |
| <literal>\></literal> if the <literal>></literal> is |
| directly after <literal>]]</literal> or <literal>--</literal> in |
| the escaped string, or if it's at the beginning of the escaped |
| string, or if there's only a <literal>]</literal> or |
| <literal>-</literal> before it at the beginning of the escaped |
| string</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><</literal> is escaped as |
| <literal>\u003C</literal> if it's followed by |
| <literal>?</literal> or <literal>!</literal> in the escaped |
| string, or if it's at the end of the escaped string</para> |
| </listitem> |
| |
| <listitem> |
| <para>Control characters in <link linkend="gloss.UCS">UCS</link> |
| code point ranges U+0000...U+001f and U+007f...U+009f are |
| escaped as <literal>\r</literal>, <literal>\n</literal>, etc., |
| or as <literal>\x<replaceable>XX</replaceable></literal> where |
| there's no special escape for them in JavaScript.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Control characters with <link |
| linkend="gloss.UCS">UCS</link> code point U+2028 (Line |
| separator) and U+2029 (Paragraph separator) are escaped as |
| <literal>\u<replaceable>XXXX</replaceable></literal>, as they |
| are source code line-breaks in ECMAScript.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section xml:id="ref_builtin_json_string"> |
| <title>json_string</title> |
| |
| <indexterm> |
| <primary>json_string built-in</primary> |
| </indexterm> |
| |
| <para>Escapes the string with the escaping rules of JSON language |
| string literals, so it's safe to insert the value into a string |
| literal. Note that it will <emphasis>not</emphasis> add quotation |
| marks around the inserted value; you meant to use this |
| <emphasis>inside</emphasis> the string literal.</para> |
| |
| <para>This will not escape <literal>'</literal> characters, since |
| JSON strings must be quoted with <literal>"</literal>.</para> |
| |
| <para>The escaping rules are almost identical to those <link |
| linkend="ref_builtin_js_string">documented for |
| <literal>js_string</literal></link>. The differences are that |
| <literal>'</literal> is not escaped at all, that |
| <literal>></literal> is escaped as <literal>\u003E</literal> (not |
| as <literal>\></literal>), and that |
| <literal>\u<replaceable>XXXX</replaceable></literal> escapes are |
| used instead of <literal>\x<replaceable>XX</replaceable></literal> |
| escapes.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_keep_after"> |
| <title>keep_after</title> |
| |
| <indexterm> |
| <primary>keep_after built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.21.</para> |
| </note> |
| |
| <para>Removes the part of the string that is not after the first |
| occurrence of the given substring. For example:</para> |
| |
| <programlisting role="template">${"abcdefgh"?keep_after("de")}</programlisting> |
| |
| <para>will print</para> |
| |
| <programlisting role="output">fgh</programlisting> |
| |
| <para>If the parameter string is not found, it will return an empty |
| string. If the parameter string is a 0-length string, it will return |
| the original string unchanged.</para> |
| |
| <para>This method accepts an optional <link |
| linkend="ref_builtin_string_flags">flags parameter</link>, as its |
| 2nd parameter:</para> |
| |
| <programlisting role="template">${"foo : bar"?keep_after(r"\s*:\s*", "r")}</programlisting> |
| |
| <para>will print</para> |
| |
| <programlisting role="output">bar</programlisting> |
| </section> |
| |
| <section xml:id="ref_builtin_keep_after_last"> |
| <title>keep_after_last</title> |
| |
| <indexterm> |
| <primary>keep_after_last built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.22.</para> |
| </note> |
| |
| <para>Same as <link |
| linkend="ref_builtin_keep_after"><literal>keep_after</literal></link>, |
| but keeps the part after the last occurrence of the parameter, |
| rather than after the first. Example:</para> |
| |
| <programlisting role="template">${"foo.bar.txt"?keep_after_last(".")}</programlisting> |
| |
| <para>will print</para> |
| |
| <programlisting role="output">txt</programlisting> |
| |
| <para>while with <literal>keep_after</literal> you would get |
| <literal>bar.txt</literal>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_keep_before"> |
| <title>keep_before</title> |
| |
| <indexterm> |
| <primary>keep_before built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.21.</para> |
| </note> |
| |
| <para>Removes the part of the string that starts with the given |
| substring. For example:</para> |
| |
| <programlisting role="template">${"abcdef"?keep_before("de")}</programlisting> |
| |
| <para>will print</para> |
| |
| <programlisting role="output">abc</programlisting> |
| |
| <para>If the parameter string is not found, it will return the |
| original string unchanged. If the parameter string is a 0-length |
| string, it will return an empty string.</para> |
| |
| <para>This method accepts an optional <link |
| linkend="ref_builtin_string_flags">flags parameter</link>, as its |
| 2nd parameter:</para> |
| |
| <programlisting role="template">${"foo : bar"?keep_before(r"\s*:\s*", "r")}</programlisting> |
| |
| <para>will print</para> |
| |
| <programlisting role="output">foo</programlisting> |
| </section> |
| |
| <section xml:id="ref_builtin_keep_before_last"> |
| <title>keep_before_last</title> |
| |
| <indexterm> |
| <primary>keep_before_last built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.22.</para> |
| </note> |
| |
| <para>Same as <link |
| linkend="ref_builtin_keep_before"><literal>keep_before</literal></link>, |
| but keeps the part before the last occurrence of the parameter, |
| rather than after the first. Example:</para> |
| |
| <programlisting role="template">${"foo.bar.txt"?keep_before_last(".")}</programlisting> |
| |
| <para>will print</para> |
| |
| <programlisting role="output">foo.bar</programlisting> |
| |
| <para>while with <literal>keep_before</literal> you would get |
| <literal>foo</literal>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_last_index_of"> |
| <title>last_index_of</title> |
| |
| <indexterm> |
| <primary>last_index_of built-in</primary> |
| </indexterm> |
| |
| <para>Returns the index within this string of the last (rightmost) |
| occurrence of the specified substring. It returns the index of the |
| first (leftmost) character of the substring. For example: |
| <literal>"abcabc"?last_index_of("ab")</literal> will return 3. Also, |
| you can specify the index to start the search from. For example, |
| <literal>"abcabc"?last_index_of("ab", 2)</literal> will return 0. |
| Note that the second parameter indicates the maximum index of the |
| start of the substring. There is no restriction on the numerical |
| value of the second parameter: if it is negative, it has the same |
| effect as if it were zero, and if it is greater than the length of |
| this string, it has the same effect as if it were equal to the |
| length of this string. Decimal values will be truncated to |
| inegers.</para> |
| |
| <para>If the 1st parameter does not occur as a substring in this |
| string (before the given index, if you use the second parameter), |
| then it returns -1.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_left_pad"> |
| <title>left_pad</title> |
| |
| <indexterm> |
| <primary>left_pad built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>padding</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.1.</para> |
| </note> |
| |
| <para>If it's used with 1 parameter, then it inserts spaces on the |
| beginning of the string until it reaches the length that is |
| specified as the parameter. If the string is already as long or |
| longer than the specified length, then it does nothing. For example, |
| this:</para> |
| |
| <programlisting role="template">[${""?left_pad(5)}] |
| [${"a"?left_pad(5)}] |
| [${"ab"?left_pad(5)}] |
| [${"abc"?left_pad(5)}] |
| [${"abcd"?left_pad(5)}] |
| [${"abcde"?left_pad(5)}] |
| [${"abcdef"?left_pad(5)}] |
| [${"abcdefg"?left_pad(5)}] |
| [${"abcdefgh"?left_pad(5)}]</programlisting> |
| |
| <para>will output this:</para> |
| |
| <programlisting role="output">[ ] |
| [ a] |
| [ ab] |
| [ abc] |
| [ abcd] |
| [abcde] |
| [abcdef] |
| [abcdefg] |
| [abcdefgh]</programlisting> |
| |
| <para>If it's used with 2 parameters, then the 1st parameter means |
| the same as if you were using the built-in with only 1 parameter, |
| and the second parameter specifies what to insert instead of space |
| characters. For example:</para> |
| |
| <programlisting role="template">[${""?left_pad(5, "-")}] |
| [${"a"?left_pad(5, "-")}] |
| [${"ab"?left_pad(5, "-")}] |
| [${"abc"?left_pad(5, "-")}] |
| [${"abcd"?left_pad(5, "-")}] |
| [${"abcde"?left_pad(5, "-")}]</programlisting> |
| |
| <para>will output this:</para> |
| |
| <programlisting role="output">[-----] |
| [----a] |
| [---ab] |
| [--abc] |
| [-abcd] |
| [abcde]</programlisting> |
| |
| <para>The 2nd parameter can be a string whose length is greater than |
| 1. Then the string will be inserted periodically, for |
| example:</para> |
| |
| <programlisting role="template">[${""?left_pad(8, ".oO")}] |
| [${"a"?left_pad(8, ".oO")}] |
| [${"ab"?left_pad(8, ".oO")}] |
| [${"abc"?left_pad(8, ".oO")}] |
| [${"abcd"?left_pad(8, ".oO")}]</programlisting> |
| |
| <para>will output this:</para> |
| |
| <programlisting role="output">[.oO.oO.o] |
| [.oO.oO.a] |
| [.oO.oOab] |
| [.oO.oabc] |
| [.oO.abcd]</programlisting> |
| |
| <para>The 2nd parameter must be a string value, and it must be at |
| least 1 character long.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_length"> |
| <title>length</title> |
| |
| <indexterm> |
| <primary>length built-in</primary> |
| </indexterm> |
| |
| <para>The number of characters in the string.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_lower_case"> |
| <title>lower_case</title> |
| |
| <indexterm> |
| <primary>lower_case built-in</primary> |
| </indexterm> |
| |
| <para>The lower case version of the string, using rules that depend |
| on the current <literal>locale</literal> (language, country). For |
| example <literal>"KARIÅžIK iÅŸaretler"?lower_case</literal> will be |
| <literal>"kariÅŸik iÅŸaretler"</literal> in most locales, but will be |
| <literal>"karışık işaretler"</literal> in Turkish |
| (<literal>tr_TR</literal>) locale (note the missing dot above some |
| of the <quote>i</quote>-s).</para> |
| |
| <para>To convert to lower case for computer consumption (as opposed |
| to human consumption), use the <link |
| linkend="ref_builtin_c_lower_case"><literal>c_lower_case</literal> |
| built-in</link> instead!</para> |
| </section> |
| |
| <section xml:id="ref_builtin_matches"> |
| <title>matches</title> |
| |
| <indexterm> |
| <primary>matches built-in</primary> |
| </indexterm> |
| |
| <para>This is a <quote>power user</quote> built-in. Ignore it if you |
| don't know <link linkend="gloss.regularExpression">regular |
| expressions</link>.</para> |
| |
| <para>This built-in determines if the string exactly matches the |
| pattern. Also, it returns the list of matching sub-strings. The |
| return value is a multi-type value:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Boolean: <literal>true</literal>, if it the entire string |
| matches the pattern, otherwise <literal>false</literal>. For |
| example, <literal>"fooo"?matches('fo*')</literal> is |
| <literal>true</literal>, but |
| <literal>"fooo bar"?matches('fo*')</literal> is |
| <literal>false</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Sequence: the list of matched substrings of the string. |
| Possibly a 0 length sequence.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>For example:</para> |
| |
| <programlisting role="template"><#if "fxo"?matches("f.?o")>Matches.<#else>Does not match.</#if> |
| |
| <#assign res = "foo bar fyo"?matches("f.?o")> |
| <#if res>Matches.<#else>Does not match.</#if> |
| Matching sub-strings: |
| <#list res as m> |
| - ${m} |
| </#list></programlisting> |
| |
| <para>will print:</para> |
| |
| <programlisting role="output">Matches. |
| |
| Does not match. |
| Matching sub-strings: |
| - foo |
| - fyo</programlisting> |
| |
| <para>If the regular expression contains groups (parentheses), then |
| you can access them with the <literal>groups</literal> |
| built-in:</para> |
| |
| <programlisting role="template"><#-- Entire input match --> |
| <#assign res = "John Doe"?matches(r"(\w+) (\w+)")> |
| <#if res> <#-- Must not try to access groups if there was no match! --> |
| First name: ${res?groups[1]} |
| Second name: ${res?groups[2]} |
| </#if> |
| |
| <#-- Subtring matches --> |
| <#assign res = "aa/rx; ab/r;"?matches("(.+?)/*(.+?);")> |
| <#list res as m> |
| - "${m}" is "${m?groups[1]}" per "${m?groups[2]}" |
| </#list></programlisting> |
| |
| <para>This will print:</para> |
| |
| <programlisting role="output"> First name: John |
| Second name: Doe |
| |
| - "aa/rx;" is "a" per "a/rx" |
| - " ab/r;" is " " per "ab/r"</programlisting> |
| |
| <para>Notes regarding the behavior of the <literal>groups</literal> |
| built-in:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>It works both with substring matches and with the result |
| of entire string matching (as it was shown in the above |
| example)</para> |
| </listitem> |
| |
| <listitem> |
| <para>The first item in the sequence that |
| <literal>groups</literal> returns is the whole substring matched |
| by the regular expression. Hence, the index of the first |
| explicit regular expression group (with other words, of the |
| first <literal>(<replaceable>...</replaceable>)</literal> in the |
| regular expression) is 1, and not 0. Also, because of this, the |
| size of the sequence is one more than the number of explicit |
| regular expression groups.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The size of the sequence returned by |
| <literal>groups</literal> only depends on the number of explicit |
| groups in the regular expression, and so it will be the same |
| (non-0) even if there was no match found for the regular |
| expression. Attempting to access an item of the sequence (as in |
| <literal>res?groups[1]</literal>) when there was match will |
| cause an error. Thus, before accessing the groups, you should |
| always check if there was any match (as in <literal><#if |
| res><replaceable>access the groups |
| here</replaceable></#if></literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>When there's a match for the regular expression, but not |
| for a certain explicit group inside the regular expression, then |
| for that group the sequence will contain a 0 length string. So |
| accessing a group that matches nothing is safe, as far as the |
| containing regular expression has matched something.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para><literal>matches</literal> accepts an optional 2nd parameter, |
| the <link linkend="ref_builtin_string_flags">flags</link>. Note that |
| it doesn't support flag <literal>f</literal>, and ignores the |
| <literal>r</literal> flag.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_no_esc"> |
| <title>no_esc</title> |
| |
| <para><indexterm> |
| <primary>no_esc built-in</primary> |
| </indexterm></para> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.24.</para> |
| </note> |
| |
| <para>Prevents the <link |
| linkend="dgui_misc_autoescaping">auto-escaping</link> of a value. |
| For example:</para> |
| |
| <programlisting role="template"><#ftl output_format="HTML"> |
| <#assign s = "<b>Test</b>"> |
| ${s} |
| ${s?no_esc}</programlisting> |
| |
| <programlisting role="output">&lt;b&gt;Test&lt;/b&gt; |
| <b>Test</b></programlisting> |
| |
| <para>This works by converting the string value to a <link |
| linkend="dgui_misc_autoescaping_movalues">markup output |
| value</link>, which uses the string as the markup as is, and belongs |
| to the current <link |
| linkend="dgui_misc_autoescaping_outputformat">output format</link> |
| at the point of the invocation.</para> |
| |
| <para>This built-in can also be applied on markup output values, |
| which it will bypass without change, as far as the input markup |
| output value belongs to current output format. If it doesn't, then |
| the markup has to be converted to the current output format, which |
| currently (as of 2.3.24) will be only successful if that value was |
| created by escaping plain text (usually, with |
| <literal>?esc</literal>).</para> |
| |
| <para>This built-in can't be used where the current output format is |
| a <link linkend="dgui_misc_autoescaping_nonmarkupof">non-markup |
| output format</link>. An attempt to do so will cause a <link |
| linkend="gloss.parseTimeError">parse-time error</link>.</para> |
| |
| <para>This built-in is not related to the deprecated <link |
| linkend="ref_directive_escape"><literal>escape</literal> and |
| <literal>noescape</literal> directives</link>. In fact, the parser |
| will prevent using them on the same place, to prevent |
| confusion.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_number"> |
| <title>number</title> |
| |
| <indexterm> |
| <primary>type-casting</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting between types</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>number built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>string to number</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting string to number</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>parse string as number</primary> |
| </indexterm> |
| |
| <para>The string converted to numerical value. The number must be in |
| <quote>computer language</quote> format. That is, it must be in the |
| locale independent form, where the decimal separator is dot, and |
| there's no grouping.</para> |
| |
| <para>This built-in recognizes numbers in the format that the |
| FreeMarker template language uses. In additionally, it recognizes |
| scientific notation (e.g. <literal>"1.23E6"</literal>, |
| <literal>"1.5e-8"</literal>). Since FreeMarker 2.3.21, it also |
| recognizes all XML Schema number formats, like |
| <literal>NaN</literal>, <literal>INF</literal>, |
| <literal>-INF</literal>, plus the Java-native formats |
| <literal>Infinity</literal> and <literal>-Infinity</literal>.</para> |
| |
| <para>If the string is not in the appropriate format, an error will |
| abort template processing when you try to access this |
| built-in.</para> |
| |
| <para><phrase role="forProgrammers">In fact, the string is parsed by |
| the <literal>toNumber</literal> method of the current |
| <literal>arithmetic_engine</literal>, which is configuration |
| setting. However, that method should behave similarly as described |
| above.</phrase></para> |
| </section> |
| |
| <section xml:id="ref_builtin_replace"> |
| <title>replace</title> |
| |
| <indexterm> |
| <primary>replace built-in</primary> |
| </indexterm> |
| |
| <para>It is used to replace all occurrences of a string in the |
| original string with another string. It does not deal with word |
| boundaries. For example:</para> |
| |
| <programlisting role="template">${"this is a car acarus"?replace("car", "bulldozer")}</programlisting> |
| |
| <para>will print:</para> |
| |
| <programlisting role="output">this is a bulldozer abulldozerus</programlisting> |
| |
| <para>The replacing occurs in left-to-right order. This means that |
| this:</para> |
| |
| <programlisting role="template">${"aaaaa"?replace("aaa", "X")}</programlisting> |
| |
| <para>will print:</para> |
| |
| <programlisting role="output">Xaa</programlisting> |
| |
| <para>If the 1st parameter is an empty string, then all occurrences |
| of the empty string will be replaced, like |
| <literal>"foo"?replace("","|")</literal> will evaluate to |
| <literal>"|f|o|o|"</literal>.</para> |
| |
| <para><literal>replace</literal> accepts an optional <link |
| linkend="ref_builtin_string_flags">flags parameter</link>, as its |
| 3rd parameter.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_right_pad"> |
| <title>right_pad</title> |
| |
| <indexterm> |
| <primary>right_pad built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>padding</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.1. It |
| doesn't exist in 2.3.</para> |
| </note> |
| |
| <para>This is the same as <link |
| linkend="ref_builtin_left_pad"><literal>left_pad</literal></link>, |
| but it inserts the characters at the end of the string instead of |
| the beginning of the string.</para> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template">[${""?right_pad(5)}] |
| [${"a"?right_pad(5)}] |
| [${"ab"?right_pad(5)}] |
| [${"abc"?right_pad(5)}] |
| [${"abcd"?right_pad(5)}] |
| [${"abcde"?right_pad(5)}] |
| [${"abcdef"?right_pad(5)}] |
| [${"abcdefg"?right_pad(5)}] |
| [${"abcdefgh"?right_pad(5)}] |
| |
| [${""?right_pad(8, ".oO")}] |
| [${"a"?right_pad(8, ".oO")}] |
| [${"ab"?right_pad(8, ".oO")}] |
| [${"abc"?right_pad(8, ".oO")}] |
| [${"abcd"?right_pad(8, ".oO")}]</programlisting> |
| |
| <para>This will output this:</para> |
| |
| <programlisting role="output">[ ] |
| [a ] |
| [ab ] |
| [abc ] |
| [abcd ] |
| [abcde] |
| [abcdef] |
| [abcdefg] |
| [abcdefgh] |
| |
| [.oO.oO.o] |
| [aoO.oO.o] |
| [abO.oO.o] |
| [abc.oO.o] |
| [abcdoO.o]</programlisting> |
| </section> |
| |
| <section xml:id="ref_builtin_remove_beginning"> |
| <title>remove_beginning</title> |
| |
| <indexterm> |
| <primary>remove_beginning built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.21.</para> |
| </note> |
| |
| <para>Removes the parameter substring from the beginning of the |
| string, or returns the original string if it doesn't start with the |
| parameter substring. For example:</para> |
| |
| <programlisting role="template">${"abcdef"?remove_beginning("abc")} |
| ${"foobar"?remove_beginning("abc")}</programlisting> |
| |
| <para>will print:</para> |
| |
| <programlisting role="output">def |
| foobar</programlisting> |
| </section> |
| |
| <section xml:id="ref_builtin_remove_ending"> |
| <title>remove_ending</title> |
| |
| <indexterm> |
| <primary>remove_ending built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.21.</para> |
| </note> |
| |
| <para>Removes the parameter substring from the ending of the string, |
| or returns the original string if it doesn't end with the parameter |
| substring. For example:</para> |
| |
| <programlisting role="template">${"abcdef"?remove_ending("def")} |
| ${"foobar"?remove_ending("def")}</programlisting> |
| |
| <para>will print:</para> |
| |
| <programlisting role="output">abc |
| foobar</programlisting> |
| </section> |
| |
| <section xml:id="ref_builtin_rtf"> |
| <title>rtf (deprecated)</title> |
| |
| <note> |
| <para>This built-in is <emphasis>deprecated</emphasis> by the |
| <link linkend="dgui_misc_autoescaping">auto-escaping |
| mechanism</link> introduced in 2.3.24. To prevent double escaping |
| and confusion in general, using this built-in on places where |
| auto-escaping is active is a <link |
| linkend="gloss.parseTimeError">parse-time error</link>. To help |
| migration, this built-in silently bypasses RTF <link |
| linkend="dgui_misc_autoescaping_movalues">markup output |
| values</link> without changing them.</para> |
| </note> |
| |
| <indexterm> |
| <primary>rtf built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>escaping</primary> |
| |
| <secondary>output</secondary> |
| </indexterm> |
| |
| <para>The string as Rich text (RTF text). That is, the string with |
| all:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>\</literal> replaced with |
| <literal>\\</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>{</literal> replaced with |
| <literal>\{</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>}</literal> replaced with |
| <literal>\}</literal></para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section xml:id="ref_builtin_split"> |
| <title>split</title> |
| |
| <indexterm> |
| <primary>split built-in</primary> |
| </indexterm> |
| |
| <para>It is used to split a string into a sequence of strings along |
| the occurrences of another string. For example:</para> |
| |
| <programlisting role="template"><#list "someMOOtestMOOtext"?split("MOO") as x> |
| - ${x} |
| </#list></programlisting> |
| |
| <para>will print:</para> |
| |
| <programlisting role="output">- some |
| - test |
| - text</programlisting> |
| |
| <para>Note that it is assumed that all occurrences of the separator |
| is before a new item (except with <literal>"r"</literal> flag - see |
| later), thus:</para> |
| |
| <programlisting role="template"><#list "some,,test,text,"?split(",") as x> |
| - "${x}" |
| </#list></programlisting> |
| |
| <para>will print:</para> |
| |
| <programlisting role="output">- "some" |
| - "" |
| - "test" |
| - "text" |
| - ""</programlisting> |
| |
| <para><literal>split</literal> accepts an optional <link |
| linkend="ref_builtin_string_flags">flags parameter</link>, as its |
| 2nd parameter. There's a historical glitch with the |
| <literal>r</literal> (regular expression) flag; it removes the empty |
| elements from the end of the resulting list, so with |
| <literal>?split(",", "r")</literal> in the last example the last |
| <literal>""</literal> would be missing from the output.</para> |
| |
| <para>If the 1st parameter is an empty string, the string will be |
| split to characters (since FreeMarker 2.3.28 - earlier this has only |
| worked with the <literal>r</literal> flag).</para> |
| |
| <note> |
| <para>To check if a strings ends with something and append it |
| otherwise, use <link linkend="ref_builtin_ensure_ends_with">the |
| <literal>ensure_ends_with</literal> built-in</link>.</para> |
| </note> |
| </section> |
| |
| <section xml:id="ref_builtin_starts_with"> |
| <title>starts_with</title> |
| |
| <indexterm> |
| <primary>starts_with built-in</primary> |
| </indexterm> |
| |
| <para>Returns if this string starts with the specified substring. |
| For example <literal>"redirect"?starts_with("red")</literal> returns |
| boolean <literal>true</literal>. Also, |
| <literal>"red"?starts_with("red")</literal> will return |
| <literal>true</literal>.</para> |
| |
| <note> |
| <para>To check if a strings starts with something and prepend it |
| otherwise, use <link linkend="ref_builtin_ensure_starts_with">the |
| <literal>ensure_starts_with</literal> built-in</link>.</para> |
| </note> |
| </section> |
| |
| <section xml:id="ref_builtin_string_for_string"> |
| <title>string (when used with a string value)</title> |
| |
| <para>Does nothing, just returns the string as-is. The exception is |
| that if the value is a multi-type value (e.g. it is both string and |
| sequence at the same time), then the resulting value will be only a |
| simple string, not a multi-type value. This can be utilized to |
| prevent the artifacts of multi-typing.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_substring"> |
| <title>substring (deprecated)</title> |
| |
| <indexterm> |
| <primary>substring built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>substring</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is deprecated since FreeMarker 2.3.21 by <link |
| linkend="dgui_template_exp_stringop_slice">slicing |
| expressions</link>, like |
| <literal><replaceable>str</replaceable>[<replaceable>from</replaceable>..<<replaceable>toExclusive</replaceable>]</literal>, |
| <literal><replaceable>str</replaceable>[<replaceable>from</replaceable>..]</literal>, |
| and |
| <literal><replaceable>str</replaceable>[<replaceable>from</replaceable>..*<replaceable>maxLength</replaceable>]</literal>.</para> |
| |
| <para>A warning if you are processing XML: Since slicing |
| expressions work both for sequences and strings, and since XML |
| nodes are typically both sequences and strings at the same time, |
| there the equivalent expression is |
| <literal><replaceable>someXmlNode</replaceable>?string[<replaceable>from</replaceable>..<<replaceable>toExclusive</replaceable>]</literal> |
| and |
| <literal><replaceable>exp</replaceable>?string[<replaceable>from</replaceable>..]</literal>, |
| as without <literal>?string</literal> it would slice the node |
| sequence instead of the text value of the node.</para> |
| </note> |
| |
| <note> |
| <para>Some of the typical use-cases of string slicing is covered |
| by convenient built-ins: <link |
| linkend="ref_builtin_remove_beginning"><literal>remove_beginning</literal></link>, |
| <link |
| linkend="ref_builtin_remove_ending"><literal>remove_ending</literal></link>, |
| <link |
| linkend="ref_builtin_keep_before"><literal>keep_before</literal></link>, |
| <link |
| linkend="ref_builtin_keep_after"><literal>keep_after</literal></link>, |
| <link |
| linkend="ref_builtin_keep_before_last"><literal>keep_before_last</literal></link>, |
| <link |
| linkend="ref_builtin_keep_after_last"><literal>keep_after_last</literal></link></para> |
| </note> |
| |
| <para>Synopsis: |
| <literal><replaceable>exp</replaceable>?substring(<replaceable>from</replaceable>, |
| <replaceable>toExclusive</replaceable>)</literal>, also callable as |
| <literal><replaceable>exp</replaceable>?substring(<replaceable>from</replaceable>)</literal></para> |
| |
| <para>A substring of the string. |
| <literal><replaceable>from</replaceable></literal> is the index of |
| the first character. It must be a number that is at least 0 and less |
| than or equal with |
| <literal><replaceable>toExclusive</replaceable></literal>, or else |
| an error will abort the template processing. The |
| <literal><replaceable>toExclusive</replaceable></literal> is the |
| index of the character position after the last character of the |
| substring, or with other words, it is one greater than the index of |
| the last character. It must be a number that is at least 0 and less |
| than or equal to the length of the string, or else an error will |
| abort the template processing. If the |
| <literal><replaceable>toExclusive</replaceable></literal> is |
| omitted, then it defaults to the length of the string. If a |
| parameter is a number that is not an integer, only the integer part |
| of the number will be used.</para> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template">- ${'abc'?substring(0)} |
| - ${'abc'?substring(1)} |
| - ${'abc'?substring(2)} |
| - ${'abc'?substring(3)} |
| |
| - ${'abc'?substring(0, 0)} |
| - ${'abc'?substring(0, 1)} |
| - ${'abc'?substring(0, 2)} |
| - ${'abc'?substring(0, 3)} |
| |
| - ${'abc'?substring(0, 1)} |
| - ${'abc'?substring(1, 2)} |
| - ${'abc'?substring(2, 3)}</programlisting> |
| |
| <para>The output:</para> |
| |
| <programlisting role="output">- abc |
| - bc |
| - c |
| - |
| |
| - |
| - a |
| - ab |
| - abc |
| |
| - a |
| - b |
| - c</programlisting> |
| </section> |
| |
| <section xml:id="ref_builtin_trim"> |
| <title>trim</title> |
| |
| <indexterm> |
| <primary>trim built-in</primary> |
| </indexterm> |
| |
| <para>The string without leading and trailing white-space. |
| Example:</para> |
| |
| <programlisting role="template">(${" green mouse "?trim})</programlisting> |
| |
| <para>The output:</para> |
| |
| <programlisting role="output">(green mouse)</programlisting> |
| </section> |
| |
| <section xml:id="ref_builtin_truncate"> |
| <title>truncate, truncate_...</title> |
| |
| <indexterm> |
| <primary>truncate built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>truncate_c built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>truncate_w built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>truncate_m built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>truncate_c_m built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>truncate_w_m built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>If you just want to limit the length of string with |
| straightforward behavior, then do not use this built in, but the |
| <link linkend="dgui_template_exp_seqenceop_slice">sequence |
| slicing</link>, and <link |
| linkend="dgui_template_exp_direct_ranges">..* length limited |
| range</link> operators. For example, <literal>s[0 ..* |
| 10]</literal> will give the first 10 characters of |
| <literal>s</literal>, if <literal>s</literal> is longer than that, |
| otherwise it just gives <literal>s</literal> as is. While |
| <literal>s?truncate(10, '')</literal> expresses similar intent, it |
| has complicated rules to give a result that looks nicer for |
| humans, like it trims the right side at the cut, and sometimes |
| cuts a bit early to avoid cutting into the last word.</para> |
| </note> |
| |
| <para>Cuts off the end of a string if that's necessary to keep it |
| under the length given as parameter, and appends a terminator string |
| (<literal>[...]</literal> by default) to indicate that the string |
| was truncated. Example (assuming default FreeMarker configuration |
| settings):</para> |
| |
| <programlisting role="template"><#assign shortName='This is short'> |
| <#assign longName='This is a too long name'> |
| <#assign difficultName='This isoneveryverylongword'> |
| |
| No truncation needed: |
| ${shortName?truncate(16)} |
| |
| Truncated at word boundary: |
| ${longName?truncate(16)} |
| |
| Truncated at "character boundary": |
| ${difficultName?truncate(16)}</programlisting> |
| |
| <programlisting role="output">No truncation needed: |
| This is short |
| |
| Truncated at word boundary: |
| This is a [...] |
| |
| Truncated at "character boundary": |
| This isonev[...]</programlisting> |
| |
| <para>Notes on some tricky aspects for truncation:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The string is returned as is if its length doesn't exceed |
| the specified length (16 in this case).</para> |
| </listitem> |
| |
| <listitem> |
| <para>When the string exceeded that length, its end was cut off |
| in a way so that together with the added terminator string |
| (<literal>[...]</literal> here) its length won't exceed 16. The |
| result length is possibly shorter than 16, for the sake of |
| better look (see later). Actually, the result length can also be |
| longer than the parameter length, when the desired length is |
| shorter than the terminator string alone, in which case the |
| terminator is still returned as is. Also, an algorithm other |
| than the default might choses to return a longer string, as the |
| length parameter is in principle just a hint for the desired |
| visual length.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>truncate</literal> prefers cutting at word |
| boundary, rather than mid-word, however, if doing so would give |
| a result that's shorter than the 75% of the length specified |
| with the argument, it falls back to cut mid-word. In the last |
| line of the above example, <quote>This [...]</quote> would be |
| too short (11 < 16 * 75%), so it was cut mid-word |
| instead.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If the cut happened at word boundary, there's a space |
| between the word end and the terminator string, otherwise |
| there's no space between them. Only whitespace is treated as |
| word separator, not punctuation, so this generally gives |
| intuitive results. (Except, if the terminator string is set to |
| be 0 length, no space is added before it, starting from |
| FreeMarker 2.3.33.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Before adding the terminator string (possibly with a word |
| boundary space before it, as explained above) after the string |
| whose length was already cut, trailing whitespace is removed |
| from that. For example <literal>'1 |
| 67890A'?truncate(10)</literal>, where there are 4 spaces between |
| the <literal>1</literal> and <literal>6</literal>, will give |
| <quote><literal>1 [...]</literal></quote> (7 characters), not |
| <quote><literal>1 [...]</literal></quote> (10 |
| characters).</para> |
| </listitem> |
| </itemizedlist> |
| |
| <simplesect> |
| <title>Adjusting truncation rules</title> |
| |
| <para>Truncation rules are highly configurable by setting the |
| <literal>truncate_builtin_algorithm</literal> configuration |
| setting. This can be done by the programmers, not template |
| authors, so for more details and examples please see the JavaDoc |
| of <link |
| xlink:href="api/freemarker/core/Configurable.html#setTruncateBuiltinAlgorithm-freemarker.core.TruncateBuiltinAlgorithm-">Configurable.setTruncateBuiltinAlgorithm</link>.</para> |
| |
| <para>Truncation rules can also be influenced right in the |
| template to a smaller extent:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Specifying if the truncation should happen at word |
| boundary or not:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>truncate_w</literal> will always truncate |
| at word boundary. For example, |
| <literal>difficultName?truncate_w(16)</literal> returns |
| <quote>This [...]</quote>, rather than <quote>This |
| isonev[...]</quote> (as saw in earlier example).</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>truncate_c</literal> will truncate at any |
| character, not just at word ends. For example, |
| <literal>longName?truncate_c(16)</literal> returns |
| <quote>This is a t[...]</quote>, rather than <quote>This |
| is a [...]</quote> (as saw in earlier example). This tends |
| to give a string length closer to the length specified, |
| but still not an exact length, as it removes white-space |
| before the terminator string, and re-adds a space if we |
| are just after the end of a word, etc. (Except, space is |
| not re-added if the terminator string is set to be 0 |
| length, starting from FreeMarker 2.3.33.) If you need |
| exact length, simply use <literal>longName[0 ..* |
| 16]</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Specifying the terminator string (instead of relying on |
| its default): <literal>truncate</literal> and all |
| <literal>truncate_<replaceable>...</replaceable></literal> |
| built-ins have an optional 2nd parameter for that. After that, |
| a further optional parameter can specify the assumed length of |
| the terminator string (otherwise its real length will be |
| used). If you find yourself specifying the terminator string |
| often, then certainly the defaults should be configured |
| instead (via <literal>truncate_builtin_algorithm |
| configuration</literal> - see earlier). Example:</para> |
| |
| <programlisting role="template">${longName?truncate(16, '...')} |
| ${longName?truncate(16, '...', 1)}</programlisting> |
| |
| <programlisting role="output">This is a ... |
| This is a too ...</programlisting> |
| |
| <para>When the terminator string starts with dot |
| (<literal>.</literal>) or ellipsis (<literal>…</literal>), the |
| default algorithm will remove the dots and ellipses that the |
| terminator touches, to prevent ending up with more than 3 dots |
| at the end:</para> |
| |
| <programlisting role="template">${'Foo bar.baaz'?truncate(11, '---')} |
| ${'Foo bar.baaz'?truncate(11, '...')} (Not "Foo bar....") |
| ${'Fo bar. baaz'?truncate(11, '...')} (Word separator space prevents touching)</programlisting> |
| |
| <programlisting role="output">Foo bar.--- |
| Foo bar... (Not "Foo bar....") |
| Fo bar. ... (Word separator space prevents touching)</programlisting> |
| </listitem> |
| </itemizedlist> |
| </simplesect> |
| |
| <simplesect> |
| <title>Using markup as terminator string</title> |
| |
| <para>Each truncation built-in has a variation whose name ends |
| with <literal>_m</literal> (for markup). These allow using markup |
| (like HTML) as terminator, which is useful if you want the |
| terminator to be styled differently than the truncated text. By |
| default the markup terminator is <literal><span |
| class='truncateTerminator'>[&#8230;]</span></literal>, |
| (where <literal>&#8230;</literal> prints an ellipsis |
| character), but of course this can be changed with the |
| <literal>truncate_builtin_algorithm</literal> configuration |
| setting (see earlier). Example (see the variables used in earlier |
| example):</para> |
| |
| <programlisting role="template">${longName?truncate_m(16)} |
| ${difficultName?truncate_w_m(16)} |
| ${longName?truncate_c_m(16)}</programlisting> |
| |
| <programlisting role="output">This is a <span class='truncateTerminator'>[&#8230;]</span> |
| This <span class='truncateTerminator'>[&#8230;]</span> |
| This is a to<span class='truncateTerminator'>[&#8230;]</span></programlisting> |
| |
| <para>Note above that the terminator string was considered to be |
| only 3 characters long (<literal>'['</literal>, |
| <literal>'…'</literal>, <literal>']'</literal>) by the truncation |
| built-ins, because inside the terminator string they only count |
| the characters outside HTML/XML tags and comments, and they can |
| also interpret numeric character references (but not other entity |
| references). (The same applies when they decide if the terminator |
| starts with dot or ellipsis; preceding tags/comments are skipped, |
| etc.)</para> |
| |
| <para>If a markup terminator is used (like above), the return |
| value of the |
| <literal>truncate<replaceable>...</replaceable>_m</literal> |
| built-in will be markup as well, which means that <link |
| linkend="dgui_misc_autoescaping">auto-escaping</link> won't escape |
| it. Of course, the content of the truncated string itself will be |
| still auto-escaped:</para> |
| |
| <programlisting role="template"><#ftl output_format='HTML'> |
| ${'This is auto-escaped: <span>'} |
| ${'This is auto-escaped: <span>, but not the terminator string'?truncate_m(41)}</programlisting> |
| |
| <programlisting role="output">This is auto-escaped: &lt;span&gt; |
| This is auto-escaped: &lt;span&gt;, but not <span class='truncateTerminator'>[&#8230;]</span></programlisting> |
| </simplesect> |
| </section> |
| |
| <section xml:id="ref_builtin_uncap_first"> |
| <title>uncap_first</title> |
| |
| <indexterm> |
| <primary>uncap_first built-in</primary> |
| </indexterm> |
| |
| <para>The opposite of <link |
| linkend="ref_builtin_cap_first"><literal>cap_first</literal></link>. |
| The string with the very first word of the string un-capitalized. |
| Note that this uses locale-aware conversion, that is, the result can |
| be different depending on the current <literal>locale</literal> |
| (language, country).</para> |
| </section> |
| |
| <section xml:id="ref_builtin_upper_case"> |
| <title>upper_case</title> |
| |
| <indexterm> |
| <primary>upper_case built-in</primary> |
| </indexterm> |
| |
| <para>The upper case version of the string, using rules that depend |
| on the current <literal>locale</literal> (language, country). For |
| example <literal>"KARIÅžIK iÅŸaretler"?upper_case</literal> will be |
| <literal>"KARIÅžIK IÅžARETLER"</literal> in most locales, but with |
| Turkish locale it will be <literal>"KARIÅžIK Ä°ÅžARETLER"</literal> |
| (note the dot above the 2nd <quote>I</quote>).</para> |
| |
| <para>To convert to upper case for computer consumption (as opposed |
| to human consumption), use the <link |
| linkend="ref_builtin_c_upper_case"><literal>c_upper_case</literal> |
| built-in</link> instead!</para> |
| </section> |
| |
| <section xml:id="ref_builtin_url"> |
| <title>url</title> |
| |
| <indexterm> |
| <primary>url built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>escaping</primary> |
| |
| <secondary>URL</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>encoding</primary> |
| |
| <secondary>URL</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>URL escaping</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>URL encoding</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>url_escaping_charset</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.1. It |
| doesn't exist in 2.3.</para> |
| </note> |
| |
| <para>The string after URL escaping. This means that all |
| non-US-ASCII and reserved URL characters will be escaped with |
| <literal>%<replaceable>XX</replaceable></literal>. For |
| example:</para> |
| |
| <programlisting role="template"><#assign x = 'a/b c'> |
| ${x?url}</programlisting> |
| |
| <para>The output will be (assuming that the charset used for the |
| escaping is an US-ASCII compatible charset):</para> |
| |
| <programlisting role="output">a%2Fb%20c</programlisting> |
| |
| <para>Note that it escapes <emphasis>all</emphasis> reserved URL |
| characters (<literal>/</literal>, <literal>=</literal>, |
| <literal>&</literal>, ...etc), so this encoding can be used for |
| encoding query parameter values, for example:</para> |
| |
| <programlisting role="template"><a href="foo.cgi?x=${x?url}&y=${y?url}">Click here...</a></programlisting> |
| |
| <note> |
| <para>Above no HTML encoding (<literal>?html</literal>) was |
| needed, because URL escaping escapes all reserved HTML characters |
| anyway. But watch: always quote the attribute value, and always |
| with normal quotation mark (<literal>"</literal>), never with |
| apostrophe quotation mark (<literal>'</literal>), because |
| apostrophe quotation mark is not escaped by the URL |
| escaping.</para> |
| </note> |
| |
| <para>To do URL escaping a <link |
| linkend="gloss.charset">charset</link> must be chosen that will be |
| used for calculating the escaped parts |
| (<literal>%<replaceable>XX</replaceable></literal>). If you are HTML |
| page author and you don't really understand this, don't worry: the |
| programmers should configure FreeMarker so that it uses the proper |
| charset by default (<phrase role="forProgrammers">programmers: see |
| more below...</phrase>). If you are a more technical minded user, |
| then you may want to know that the charset used is specified by the |
| <literal>url_escaping_charset</literal> setting, that can be set in |
| template execution time (or, preferably, earlier by the |
| programmers). For example:</para> |
| |
| <programlisting role="template"><#-- |
| This will use the charset specified by the programmers |
| before the template execution has started. |
| --> |
| <a href="foo.cgi?x=${x?url}">foo</a> |
| |
| <#-- Use UTF-8 charset for URL escaping from now: --> |
| <emphasis><#setting url_escaping_charset="UTF-8"></emphasis> |
| |
| <#-- This will surely use UTF-8 charset --> |
| <a href="bar.cgi?x=${x?url}">bar</a></programlisting> |
| |
| <para>Furthermore, you can explicitly specify a charset for a single |
| URL escaping as the parameter to the built-in:</para> |
| |
| <programlisting role="template"><a href="foo.cgi?x=${x?url<emphasis>('ISO-8895-2')</emphasis>}">foo</a></programlisting> |
| |
| <para><phrase role="forProgrammers"><indexterm> |
| <primary>output encoding</primary> |
| </indexterm><indexterm> |
| <primary>output charset</primary> |
| </indexterm>If the <literal>url</literal> built-in has no |
| parameter, then it will use the charset specified as the value of |
| the <literal>url_escaping_charset</literal> setting. This setting |
| should be set by the software that encloses FreeMarker (e.g. a Web |
| application framework), because it is not set |
| (<literal>null</literal>) by default. If it is not set, then |
| FreeMarker falls back using the value of the |
| <literal>output_encoding</literal> setting, which is also not set by |
| default, so it is again the task of the enclosing software. If the |
| <literal>output_encoding</literal> setting is not set either, then |
| the parameterless <literal>url</literal> built-in can't be executed, |
| and it will cause execution time error. Of course, the |
| <literal>url</literal> built-in with parameter always |
| works.</phrase></para> |
| |
| <para><phrase role="forProgrammers">It's possible to set |
| <literal>url_escaping_charset</literal> in the template with the |
| <literal>setting</literal> directive, but it is bad practice, at |
| least in true MVC applications. The |
| <literal>output_encoding</literal> setting can't be set with the |
| <literal>setting</literal> directive, so that's surely the task of |
| the enclosing software. You may find more information regarding this |
| <link linkend="pgui_misc_charset">here...</link></phrase></para> |
| </section> |
| |
| <section xml:id="ref_builtin_url_path"> |
| <title>url_path</title> |
| |
| <indexterm> |
| <primary>url_path built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>escaping</primary> |
| |
| <secondary>URL path</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>encoding</primary> |
| |
| <secondary>URL path</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>URL escaping</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>URL encoding</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.21.</para> |
| </note> |
| |
| <para>This is the same as <link linkend="ref_builtin_url">the |
| <literal>url</literal> built-in</link>, except that it doesn't |
| escape slash (<literal>/</literal>) characters. This meant to be |
| used for converting paths (like paths coming from the OS or some |
| content repository) that use slash (not backslash!) to a path the |
| can be inserted into an URL. The most common reason why this |
| conversion is needed is that folder names or file names might |
| contain non-US-ASCII letters (<quote>national</quote> |
| characters).</para> |
| |
| <note> |
| <para>Just like with <link linkend="ref_builtin_url">the |
| <literal>url</literal> built-in</link>, the desired URL escaping |
| charset (or as a fall back, the output encoding) must be set in |
| the FreeMarker configuration settings, or else the built-in will |
| give error. Or, you you have to specify the charset like |
| <literal>somePath?url_path('utf-8')</literal>.</para> |
| </note> |
| </section> |
| |
| <section xml:id="ref_builtin_word_list"> |
| <title>word_list</title> |
| |
| <indexterm> |
| <primary>word_list built-in</primary> |
| </indexterm> |
| |
| <para>A sequence that contains all words of the string in the order |
| as they appear in the string. Words are continual character |
| sequences that contain any character but <link |
| linkend="gloss.whiteSpace">white-space</link>. Example:</para> |
| |
| <programlisting role="template"><#assign words = " a bcd, . 1-2-3"?word_list> |
| <#list words as word>[${word}]</#list> |
| </programlisting> |
| |
| <para>will output:</para> |
| |
| <programlisting role="output">[a][bcd,][.][1-2-3]</programlisting> |
| </section> |
| |
| <section xml:id="ref_builtin_xhtml"> |
| <title>xhtml (deprecated)</title> |
| |
| <note> |
| <para>This built-in is <emphasis>deprecated</emphasis> by the |
| <link linkend="dgui_misc_autoescaping">auto-escaping |
| mechanism</link> introduced in 2.3.24. To prevent double escaping |
| and confusion in general, using this built-in on places where |
| auto-escaping is active is a <link |
| linkend="gloss.parseTimeError">parse-time error</link>. To help |
| migration, this built-in silently bypasses HTML <link |
| linkend="dgui_misc_autoescaping_movalues">markup output |
| values</link> without changing them.</para> |
| </note> |
| |
| <indexterm> |
| <primary>xhtml built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>escaping</primary> |
| |
| <secondary>output</secondary> |
| </indexterm> |
| |
| <para>The string as XHTML text. That is, the string with all:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><</literal> replaced with |
| <literal>&lt;</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>></literal> replaced with |
| <literal>&gt;</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>&</literal> replaced with |
| <literal>&amp;</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>"</literal> replaced with |
| <literal>&quot;</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>'</literal> replaced with |
| <literal>&#39;</literal></para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>The only difference between this built-in and the |
| <literal>xml</literal> built-in is that the <literal>xhtml</literal> |
| built-in escapes <literal>'</literal> as |
| <literal>&#39;</literal> instead of as |
| <literal>&apos;</literal>, because some older browsers don't |
| know <literal>&apos;</literal>.</para> |
| |
| <warning> |
| <para>When inserting the value of an attribute, always quote it, |
| or else it can be exploited by attacker! This is WRONG: |
| <literal><input name="user" value=${user?xhtml}/></literal>. |
| These are good: <literal><input name="user" |
| value="${user?xhtml}"/></literal>, <literal><input |
| name="user" value='${user?xhtml}'/></literal>.</para> |
| </warning> |
| </section> |
| |
| <section xml:id="ref_builtin_xml"> |
| <title>xml (deprecated)</title> |
| |
| <note> |
| <para>This built-in is <emphasis>deprecated</emphasis> by the |
| <link linkend="dgui_misc_autoescaping">auto-escaping |
| mechanism</link> introduced in 2.3.24. To prevent double escaping |
| and confusion in general, using this built-in on places where |
| auto-escaping is active is a <link |
| linkend="gloss.parseTimeError">parse-time error</link>. To help |
| migration, this built-in silently bypasses XML and HTML <link |
| linkend="dgui_misc_autoescaping_movalues">markup output |
| values</link> without changing them.</para> |
| </note> |
| |
| <indexterm> |
| <primary>xml built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>escaping</primary> |
| |
| <secondary>output</secondary> |
| </indexterm> |
| |
| <para>The string as XML text. That is, the string with all:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><</literal> replaced with |
| <literal>&lt;</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>></literal> replaced with |
| <literal>&gt;</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>&</literal> replaced with |
| <literal>&amp;</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>"</literal> replaced with |
| <literal>&quot;</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>'</literal> replaced with |
| <literal>&apos;</literal></para> |
| </listitem> |
| </itemizedlist> |
| |
| <warning> |
| <para>When inserting the value of an attribute, always quote it, |
| or else it can be exploited by attackers! This is WRONG: |
| <literal><input name="user" value=${user?xml}/></literal>. |
| These are good: <literal><input name="user" |
| value="${user?xml}"/></literal>, <literal><input name="user" |
| value='${user?xml}'/></literal>.</para> |
| </warning> |
| </section> |
| |
| <section xml:id="ref_builtin_string_flags"> |
| <title>Common flags</title> |
| |
| <para>Many string built-ins accept an optional string parameter, the |
| so called <quote>flags</quote>. In this string, each letter |
| influences a certain aspect of the behavior of the built-in. For |
| example, letter <literal>i</literal> means that the built-in should |
| not differentiate the lower and upper-case variation of the same |
| letter. The order of the letters in the flags string is not |
| significant.</para> |
| |
| <para>This is the complete list of letters (flags):</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>i</literal>: Case insensitive: do not |
| differentiate the lower and upper-case variation of the same |
| letter.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>f</literal>: First only. That is, |
| replace/find/etc. only the first occurrence of something.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>regular expression</primary> |
| |
| <secondary>built-ins</secondary> |
| </indexterm> <literal>r</literal>: The substring to find is a |
| <link linkend="gloss.regularExpression">regular |
| expression</link>. FreeMarker uses the variation of regular |
| expressions described at <link |
| xlink:href="http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html">http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html</link> |
| (note that the presence of some pattern features depends on the |
| Java version used).</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>m</literal>: Multi-line mode for regular |
| expressions. In multi-line mode the expressions |
| <literal>^</literal> and <literal>$</literal> match just after |
| or just before, respectively, a line terminator or the end of |
| the string. By default these expressions only match at the |
| beginning and the end of the entire string. Note that |
| <literal>^</literal> and <literal>$</literal> doesn't match the |
| line-break character itself.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>s</literal>: Enables dot-all mode for regular |
| expressions (same as Perl singe-line mode). In dot-all mode, the |
| expression <literal>.</literal> matches any character, including |
| a line terminator. By default this expression does not match |
| line terminators.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>c</literal>: Permits whitespace and comments in |
| regular expressions.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template"><#assign s = 'foo bAr baar'> |
| ${s?replace('ba', 'XY')} |
| i: ${s?replace('ba', 'XY', 'i')} |
| if: ${s?replace('ba', 'XY', 'if')} |
| r: ${s?replace('ba*', 'XY', 'r')} |
| ri: ${s?replace('ba*', 'XY', 'ri')} |
| rif: ${s?replace('ba*', 'XY', 'rif')}</programlisting> |
| |
| <para>This outputs this:</para> |
| |
| <programlisting role="output">foo bAr XYar |
| i: foo XYr XYar |
| if: foo XYr baar |
| r: foo XYAr XYr |
| ri: foo XYr XYr |
| rif: foo XYr baar</programlisting> |
| |
| <para>This is the table of built-ins that use these common flags, |
| and which supports which flags:</para> |
| |
| <informaltable border="1"> |
| <thead> |
| <tr> |
| <th>Built-in</th> |
| |
| <th><literal>i</literal> (ignore case)</th> |
| |
| <th><literal>r</literal> (reg. exp.)</th> |
| |
| <th><literal>m</literal> (multi-line mode)</th> |
| |
| <th><literal>s</literal> (dot-all mode)</th> |
| |
| <th><literal>c</literal> (whitesp. and comments)</th> |
| |
| <th><literal>f</literal> (first only)</th> |
| </tr> |
| </thead> |
| |
| <tbody> |
| <tr> |
| <td><literal>replace</literal></td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Only with <literal>r</literal></td> |
| |
| <td>Only with <literal>r</literal></td> |
| |
| <td>Only with <literal>r</literal></td> |
| |
| <td>Yes</td> |
| </tr> |
| |
| <tr> |
| <td><literal>split</literal></td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Only with <literal>r</literal></td> |
| |
| <td>Only with <literal>r</literal></td> |
| |
| <td>Only with <literal>r</literal></td> |
| |
| <td>No</td> |
| </tr> |
| |
| <tr> |
| <td><literal>matches</literal></td> |
| |
| <td>Yes</td> |
| |
| <td>Ignored</td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>No</td> |
| </tr> |
| |
| <tr> |
| <td><literal>keep_after</literal></td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Ignored</td> |
| </tr> |
| |
| <tr> |
| <td><literal>keep_after_last</literal></td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Ignored</td> |
| </tr> |
| |
| <tr> |
| <td><literal>keep_before</literal></td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Ignored</td> |
| </tr> |
| |
| <tr> |
| <td><literal>keep_before_last</literal></td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Ignored</td> |
| </tr> |
| |
| <tr> |
| <td><literal>ensure_starts_with</literal></td> |
| |
| <td>Yes</td> |
| |
| <td>Ignored</td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Yes</td> |
| |
| <td>Ignored</td> |
| </tr> |
| </tbody> |
| </informaltable> |
| </section> |
| </section> |
| |
| <section xml:id="ref_builtins_number"> |
| <title>Built-ins for numbers</title> |
| |
| <indexterm> |
| <primary>number</primary> |
| |
| <secondary>built-ins</secondary> |
| </indexterm> |
| |
| <para>Related FAQs: Do you have things like 1,000,000 or 1Â 000Â 000 |
| instead of 1000000, or something like 3.14 instead of 3,14 or vice |
| versa? See <link linkend="faq_number_grouping">this</link> and <link |
| linkend="faq_number_decimal_point">this</link> FAQ entry, also note |
| the <literal>c</literal> built-in above.</para> |
| |
| <section xml:id="ref_builtin_abs"> |
| <title>abs</title> |
| |
| <indexterm> |
| <primary>abs built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>absolute value</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in exists since FreeMarker 2.3.20.</para> |
| </note> |
| |
| <para>Gives the absolute value of a number. For example |
| <literal>x?abs</literal> , if <literal>x</literal> is -5, will |
| evaluate to 5.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_c"> |
| <title>c (for numbers)</title> |
| |
| <indexterm> |
| <primary>c built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>type-casting</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting between types</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>format</primary> |
| |
| <secondary>number</secondary> |
| </indexterm> |
| |
| <note> |
| <para>The <literal>c</literal> built-in also works <link |
| linkend="ref_builtin_c_boolean">on booleans</link>, and <link |
| linkend="ref_builtin_c_string">on strings</link>!</para> |
| </note> |
| |
| <note> |
| <para>To provide a background, see <xref |
| linkend="dgui_misc_computer_vs_human_format"/></para> |
| </note> |
| |
| <para>This built-in converts a number to a <quote>computer |
| language</quote> literal, as opposed to format it for human reading. |
| This format is independent of the <literal>locale</literal> (human |
| language, country) and <literal>number_format</literal> settings of |
| FreeMarker. Instead, it depends on the <link |
| linkend="gloss.c_format"><literal>c_format</literal> setting</link>, |
| which is usually something like <literal>"JSON"</literal>; a |
| computer language.</para> |
| |
| <para>This built-in is crucial because by default (like with |
| <literal>${x}</literal>) numbers are converted to strings with the |
| locale specific number formatting, so 3000000 is possibly printed as |
| <literal>3,000,000</literal> (i.e., with grouping separators), or |
| <literal>3.14</literal> is possibly printed as |
| <literal>3,14</literal> (i.e., with a different decimal separator). |
| When the number is printed not for human audience (e.g., for a |
| database record ID used as the part of an URL, or as invisible field |
| value in a HTML form, or for printing CSS/JavaScript numerical |
| literals) you must use this built-in to format the number (i.e., use |
| <literal>${x?c}</literal> instead of <literal>${x}</literal>), or |
| else the output will be possibly unparsable for the consumer.</para> |
| |
| <para>The exact format of numbers depend on value of the |
| <literal>c_format</literal> setting, but for all the |
| <literal>c_format</literal>-s that are built into FreeMarker, these |
| sand:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>It always uses dot as decimal separator</para> |
| </listitem> |
| |
| <listitem> |
| <para>It always uses dot as decimal separator</para> |
| </listitem> |
| |
| <listitem> |
| <para>Never uses <quote>+</quote> sign (as in +1), except maybe |
| after the <quote>E</quote> that signifies the exponent |
| part</para> |
| </listitem> |
| |
| <listitem> |
| <para>No superfluous leading or trailing 0-s (like 03 or |
| 1.0)</para> |
| </listitem> |
| |
| <listitem> |
| <para>It usually avoids exponential form (like it will never |
| format 10000000000 as 1E10), but see the details below regarding |
| that.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Finder details:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Rounding:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>For all that are built into FreeMarker, except |
| <quote>legacy</quote> <literal>c_format </literal>: There's |
| no rounding.</para> |
| </listitem> |
| |
| <listitem> |
| <para>For the deprecated <literal>c_format</literal>, |
| <quote>legacy</quote>: The numbers are limited to 16 digits |
| after the decimal dot, so rounding can occur. The these |
| formats never use exponential form either, so the decimal |
| point place is fixed. Thus, for example, 1E-17 will be |
| formatted as <literal>0</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Special floating point values, positive infinity, negative |
| infinity, and NaN (for Not-a-Number):</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>For <literal>c_format</literal>-s <quote>JSON</quote>, |
| and <quote>JavaScript</quote>, <quote>JavaScript or |
| JSON</quote>: <literal>Infinity</literal>, |
| <literal>-Infinity</literal>, <literal>NaN</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>For <literal>c_format</literal> <quote>Java</quote>: |
| If the value has Java type <literal>double</literal> or |
| <literal>Double</literal>: |
| <literal>Double.POSITIVE_INFINITY</literal>, |
| <literal>Double.NEGATIVE_INFINITY</literal>, |
| <literal>Double.NaN</literal>. If the value has Java type |
| <literal>float</literal> or <literal>Float</literal>: |
| <literal>Float.POSITIVE_INFINITY</literal>, |
| <literal>Float.NEGATIVE_INFINITY</literal>, |
| <literal>Float.NaN</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>For <literal>c_format</literal> <quote>XS</quote>, and |
| also if <link |
| linkend="pgui_config_incompatible_improvements"><literal>incompatible_improvements</literal> |
| setting</link> is at least 2.3.21, for |
| <literal>c_format</literal>, <quote>legacy</quote>: |
| <literal>INF</literal>, <literal>-INF</literal>, and |
| <literal>NaN</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>For <literal>c_format</literal> <quote>legacy</quote>, |
| if <link |
| linkend="pgui_config_incompatible_improvements"><literal>incompatible_improvements</literal> |
| setting</link> is less than 2.3.21: Gives what |
| <literal>java.text.DecimalFormat</literal> does with US |
| locale, which are <literal>∞</literal>, |
| <literal>-∞</literal>, and <literal>NaN</literal> (before |
| Java 11 was <literal>�</literal>, i.e., U+FFFD, replacement |
| character).</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Exponential form is used by all |
| <literal>c_format</literal>-s that are built into FreeMarker, |
| except <quote>legacy</quote>:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>For a non-whole number whose absolute value is less |
| than 1E-6 (0.000001).</para> |
| </listitem> |
| |
| <listitem> |
| <para>For a whole number that has more than 100 digits in |
| non-exponential form</para> |
| </listitem> |
| |
| <listitem> |
| <para>For a whole numbers whose absolute value is too big |
| for the backing floating point type to be safe from rounding |
| errors. More specifically:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>For a whole number that's stored in a |
| <literal>double</literal>, or <literal>Double</literal> |
| on the Java side (i.e., as 64 bit floating point |
| number), and has an absolute value greater than |
| 9007199254740992. It's because that type can't store all |
| whole numbers outside that range. So if the intent was |
| to store some ID-s, they are likely already corrupted |
| (because they had to be rounded to the closest whole |
| number that the type can store), and you should use |
| <literal>long</literal> or <literal>BigInteger</literal> |
| on the Java side.</para> |
| </listitem> |
| |
| <listitem> |
| <para>For a whole (integer) value that's stored in a |
| <literal>float</literal>, or <literal>Float</literal> on |
| the Java side (i.e., as 32 bit floating point number), |
| and has an absolute value greater than 16777216. |
| Reasoning is the same as for |
| <literal>double</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Note that by default FreeMarker doesn't use |
| <literal>double</literal> or <literal>float</literal>, so |
| such values are likely come from the data-model.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Currently, in the <literal>c_format</literal>-s that are |
| built into FreeMarker, the output never contains superfluous |
| zeros after the decimal point. Thus, unlike in Java, you can't |
| tell apart a <literal>double</literal> from an |
| <literal>int</literal>, if they store the same number |
| mathematically, because the output will look the same for both. |
| (This is because the template language only have a single number |
| type, so you don't have a good control over the backing Java |
| type.)</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>If you only generate output that's computer language and isn't |
| read by end-users, you may prefer to set the |
| <literal>number_format</literal> configuration setting to |
| <literal>"c"</literal> (since FreeMarker 2.3.32, |
| <literal>"computer"</literal> before that), in which case |
| <literal>${<replaceable>aNumber</replaceable>}</literal> will have |
| the same output as |
| <literal>${<replaceable>aNumber</replaceable>?c}</literal>. (In this |
| case you should use a <literal>c_format</literal> like |
| <literal>"JavaScript or JSON"</literal>, and not |
| <literal>"legacy"</literal>, as that emulates some confusing old |
| glitches.)</para> |
| |
| <para>If the value the <literal>c</literal> built-in is applied on |
| is <literal>null</literal>/missing, it will stop the template |
| processing with error, just like most other built-ins. If instead |
| you want to output a <literal>null</literal> literal, see the <link |
| linkend="ref_builtin_cn"><literal>cn</literal> |
| built-in</link>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_cn"> |
| <title>cn (for numbers)</title> |
| |
| <indexterm> |
| <primary>cn built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>type-casting</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting between types</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>format</primary> |
| |
| <secondary>number</secondary> |
| </indexterm> |
| |
| <note> |
| <para><literal>cn</literal> works with all types that |
| <literal>c</literal> does, and thus for strings and booleans as |
| well. The formatting of <literal>null</literal>/missing doesn't |
| depend on the type of course (as we have no value that could have |
| a type).</para> |
| </note> |
| |
| <note> |
| <para>See <xref linkend="dgui_misc_computer_vs_human_format"/> for |
| background</para> |
| </note> |
| |
| <note> |
| <para>This built-in exists since FreeMarker 2.3.32</para> |
| </note> |
| |
| <para>This is the same as the <link |
| linkend="ref_builtin_c"><literal>c</literal> built-in</link>, except |
| if the value on its left side is <literal>null</literal>/missing, |
| this won't stop with error, but outputs a <literal>null</literal> |
| literal that's appropriate for the current |
| <literal>c_format</literal> setting:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>For <quote>JSON</quote>, <quote>Java</quote>, |
| <quote>JavaScript</quote>, and <quote>legacy</quote>: |
| <literal>null</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>For <quote>XS</quote> (used for generating XML that |
| follows XML Schema principles): 0 length string (i.e., |
| <literal>${<replaceable>thisIsNull</replaceable>?cn}</literal> |
| prints nothing), which is often not good enough (see below), but |
| we can't do better with a |
| <literal><replaceable>stringValue</replaceable>?c</literal> |
| alone. The idea is that you write something like |
| <literal><full-name>${fullName?nc}</full-name></literal>, |
| or <literal><user <replaceable>...</replaceable> |
| full-name="${fullName?nc}" /></literal>, and then, in case |
| <literal>fullName</literal> is <literal>null</literal>, the |
| output will be |
| <literal><full-name></full-name></literal>, and |
| <literal><user <replaceable>...</replaceable> full-name="" |
| /></literal>. Some applications accept that as the equivalent |
| of a <literal>null</literal>, at least where a string value is |
| expected according the XML Schema.</para> |
| |
| <para>Note that the XML Schema approach is that you skip |
| outputting the whole <literal>full-name</literal> XML element, |
| or XML attribute. For that you have to write <literal><#if |
| fullName??><full-name>${full-name?c}</full-name></#if></literal>, |
| and <literal><user <replaceable>...</replaceable> <#if |
| fullName??>full-name="${fullName?c}"</#if> |
| /></literal>. When using such condition, and the value is a |
| string (as with this example), you might as well just write |
| <literal>${fullName}</literal>, without the |
| <literal>?c</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section xml:id="ref_builtin_is_infinite"> |
| <title>is_infinite</title> |
| |
| <indexterm> |
| <primary>is_infinite built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>infinite</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in exists since FreeMarker 2.3.20.</para> |
| </note> |
| |
| <para>Tells if a number is floating point infinite (according to |
| IEEE 754). For example, <literal>someNumber?is_infinite</literal> |
| evaluates to <literal>true</literal> or <literal>false</literal> |
| depending on if the value of <literal>someNumber</literal> is |
| infinite or not. Of course, if the underlying number is not of |
| floating point type, this will always return |
| <literal>false</literal>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_is_nan"> |
| <title>is_nan</title> |
| |
| <indexterm> |
| <primary>is_nan built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>NaN</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in exists since FreeMarker 2.3.20.</para> |
| </note> |
| |
| <para>Tells if a number is floating point NaN (according to IEEE |
| 754). For example, <literal>someNumber?is_nan</literal> evaluates to |
| <literal>true</literal> or <literal>false</literal> depending on if |
| the value of <literal>someNumber</literal> is NaN or not. Of course, |
| if the underlying number is not of floating point type, this will |
| always return <literal>false</literal>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_lower_abc"> |
| <title>lower_abc</title> |
| |
| <indexterm> |
| <primary>lower_abc built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>ABC</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>alphabetical ordinals</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in exists since FreeMarker 2.3.22.</para> |
| </note> |
| |
| <para>Converts <literal>1</literal>, <literal>2</literal>, |
| <literal>3</literal>, etc., to the string <literal>"a"</literal>, |
| <literal>"b"</literal>, <literal>"c"</literal>, etc. When reaching |
| <literal>"z"</literal>, it continues like <literal>"aa"</literal>, |
| <literal>"ab"</literal>, etc. This is the same logic that you can |
| see in column labels in spreadsheet applications (like Excel or |
| Calc). The lowest allowed number is <literal>1</literal>. There's no |
| upper limit. If the number is <literal>0</literal> or less or it |
| isn't an integer number then the template processing will be aborted |
| with error.</para> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template"><#list 1..30 as n>${n?lower_abc} </#list></programlisting> |
| |
| <para>Prints:</para> |
| |
| <programlisting role="output">a b c d e f g h i j k l m n o p q r s t u v w x y z aa ab ac ad </programlisting> |
| |
| <para>See also: <link |
| linkend="ref_builtin_upper_abc"><literal>upper_abc</literal></link></para> |
| </section> |
| |
| <section xml:id="ref_builtin_rounding"> |
| <title>round, floor, ceiling</title> |
| |
| <indexterm> |
| <primary>rounding</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>floor built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>ceiling built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>round built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>The rounding built-ins exist since FreeMarker 2.3.13.</para> |
| </note> |
| |
| <para>Converts a number to a whole number using the specified |
| rounding rule:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>round</literal>: Rounds to the nearest whole |
| number. If the number ends with .5, then it rounds upwards |
| (i.e., towards positive infinity)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>floor</literal>: Rounds the number downwards |
| (i.e., towards neagative infinity)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>ceiling</literal>: Rounds the number upwards |
| (i.e., towards positive infinity)</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template"><#assign testlist=[ |
| 0, 1, -1, 0.5, 1.5, -0.5, |
| -1.5, 0.25, -0.25, 1.75, -1.75]> |
| <#list testlist as result> |
| ${result} ?floor=${result?floor} ?ceiling=${result?ceiling} ?round=${result?round} |
| </#list></programlisting> |
| |
| <para>Prints:</para> |
| |
| <programlisting role="output"> 0 ?floor=0 ?ceiling=0 ?round=0 |
| 1 ?floor=1 ?ceiling=1 ?round=1 |
| -1 ?floor=-1 ?ceiling=-1 ?round=-1 |
| 0.5 ?floor=0 ?ceiling=1 ?round=1 |
| 1.5 ?floor=1 ?ceiling=2 ?round=2 |
| -0.5 ?floor=-1 ?ceiling=0 ?round=0 |
| -1.5 ?floor=-2 ?ceiling=-1 ?round=-1 |
| 0.25 ?floor=0 ?ceiling=1 ?round=0 |
| -0.25 ?floor=-1 ?ceiling=0 ?round=0 |
| 1.75 ?floor=1 ?ceiling=2 ?round=2 |
| -1.75 ?floor=-2 ?ceiling=-1 ?round=-2</programlisting> |
| |
| <para>These built-ins may be useful in pagination operations and |
| like. If you just want to <emphasis>display</emphasis> numbers in |
| rounded form, then you should rather use the <link |
| linkend="ref_builtin_string_for_number"><literal>string</literal> |
| built-in</link> or the <link |
| linkend="ref.setting.number_format"><literal>number_format</literal> |
| setting</link>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_string_for_number"> |
| <title>string (when used with a numerical value)</title> |
| |
| <indexterm> |
| <primary>type-casting</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting between types</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>string built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>format</primary> |
| |
| <secondary>number</secondary> |
| </indexterm> |
| |
| <para>Converts a number to a string. In its simplest form |
| (<literal><replaceable>expression</replaceable>?string</literal>) it |
| uses the default format that the programmer has specified via the |
| <literal>number_format</literal> and the <literal>locale</literal> |
| configuration settings. You can also specify a number format |
| explicitly with this built-in, as it will be shown later.</para> |
| |
| <para>There are four predefined number formats: <literal>c</literal> |
| (since 2.3.32, before that it was called |
| <literal>computer</literal>, which still works), |
| <literal>currency</literal>, <literal>number</literal>, and |
| <literal>percent</literal>. The exact meaning of these is locale |
| (nationality) specific, and is controlled by the Java platform |
| installation, not by FreeMarker, except for <literal>c</literal>, |
| which uses the same formatting as <link linkend="ref_builtin_c">the |
| <literal>c</literal> built-in</link> (assuming <link |
| linkend="pgui_config_incompatible_improvements">incompatible |
| improvements</link> set to 2.3.31, or higher, or else infinity and |
| NaN isn't formatted like that). There can also be programmer-defined |
| formats, whose name starts with <literal>@</literal> (programmers |
| <link linkend="pgui_config_custom_formats">see more here...</link>). |
| You can use these predefined formats like this:</para> |
| |
| <programlisting role="template"><#assign x=4200000> |
| ${x} |
| ${x?string} <#-- the same as ${x} --> |
| ${x?string.number} |
| ${x?string.currency} |
| ${x?string.percent} |
| ${x?string.c} <#-- But you should write ${x?c} --></programlisting> |
| |
| <para>If your locale is US English, this will print:</para> |
| |
| <programlisting role="output">4,200,000 |
| 4,200,000 |
| 4,200,000 |
| $4,200,000.00 |
| 420,000,000% |
| 4200000</programlisting> |
| |
| <para>The output of first three expressions is identical because the |
| first two expressions use the default format, which is |
| <quote>number</quote> here. You can change this default using a |
| setting:</para> |
| |
| <programlisting role="template"><#setting number_format="currency"> |
| <#assign x=4200000> |
| ${x} |
| ${x?string} <#-- the same as ${x} --> |
| ${x?string.number} |
| ${x?string.currency} |
| ${x?string.percent}</programlisting> |
| |
| <para>Will now output:</para> |
| |
| <programlisting role="output">$4,200,000.00 |
| $4,200,000.00 |
| 4,200,000 |
| $4,200,000.00 |
| 420,000,000%</programlisting> |
| |
| <para>since the default number format was set to |
| <quote>currency</quote>.</para> |
| |
| <para>You can also refer to named custom formats that were defined |
| when configuring FreeMarker (programmers <link |
| linkend="pgui_config_custom_formats">see more here</link>), |
| like:</para> |
| |
| <programlisting role="template">${x?string.@price} |
| ${x?string.@weight}</programlisting> |
| |
| <para>where the custom format names were <quote>price</quote> and |
| <quote>weight</quote>. This way the templates can just refer to the |
| application-domain meaning, and the exact format can be specified |
| outside the templates, on a single central place. (Programmers can |
| read about <link linkend="pgui_config_custom_formats">defining such |
| named formats here...</link>)</para> |
| |
| <para>Beside named formats, you can specify number format patterns |
| directly, using the <link |
| xlink:href="http://docs.oracle.com/javase/7/docs/api/java/text/DecimalFormat.html">Java |
| decimal number format syntax</link> (with some FreeMarker-specific |
| extensions; <link linkend="topic.extendedJavaDecimalFormat">see |
| later</link>):</para> |
| |
| <programlisting role="template"><#assign x = 1.234> |
| ${x?string["0"]} |
| ${x?string["0.#"]} |
| ${x?string["0.##"]} |
| ${x?string["0.###"]} |
| ${x?string["0.####"]} |
| |
| ${1?string["000.00"]} |
| ${12.1?string["000.00"]} |
| ${123.456?string["000.00"]} |
| |
| ${1.2?string["0"]} |
| ${1.8?string["0"]} |
| ${1.5?string["0"]} <-- 1.5, rounded towards even neighbor |
| ${2.5?string["0"]} <-- 2.5, rounded towards even neighbor |
| |
| ${12345?string["0.##E0"]}</programlisting> |
| |
| <programlisting role="output">1 |
| 1.2 |
| 1.23 |
| 1.234 |
| 1.234 |
| |
| 001.00 |
| 012.10 |
| 123.46 |
| |
| 1 |
| 2 |
| 2 <-- 1.5, rounded towards even neighbor |
| 2 <-- 2.5, rounded towards even neighbor |
| |
| 1.23E4</programlisting> |
| |
| <para>Note that as in FreeMarker <literal>foo.bar</literal> is |
| equivalent with <literal>foo["bar"]</literal>, you could also write |
| <literal>x?string.currency</literal> as |
| <literal>x?string["currency"]</literal>, but of course that wouldn't |
| be practical. But in the above examples we have to use the square |
| bracket syntax, because the characters involved (numbers, dot, |
| <literal>#</literal>) aren't allowed syntactically after the dot |
| operator.</para> |
| |
| <para>For historical reasons, you could also write things like |
| <literal>x?string("0.#")</literal>, which does exactly the same as |
| <literal>x?string["0.#"]</literal>.</para> |
| |
| <para>Following the financial and statistics practice, by default |
| the rounding goes according the so called half-even rule, which |
| means rounding towards the nearest <quote>neighbor</quote>, unless |
| both neighbors are equidistant, in which case, it rounds towards the |
| even neighbor. This was visible in the above example if you look at |
| the rounding of 1.5 and of 2.5, as both were rounded to 2, since 2 |
| is even, but 1 and 3 are odds. The other popular rounding rule, |
| where we always round up when the neighbors are equidistant (and so |
| 2.5 is rounded to 3) is called the half-up rule, and it can be |
| activated as <link |
| linkend="topic.extendedJavaDecimalFormat">described |
| later</link>.</para> |
| |
| <para>As it was shown for the predefined formats earlier, the |
| default formatting of the numbers can be set in the template:</para> |
| |
| <programlisting role="template"><#setting number_format="0.##"> |
| ${1.234}</programlisting> |
| |
| <programlisting role="output">1.23</programlisting> |
| |
| <para>The default number format also can be specified outside the |
| templates with the FreeMarker API (like with |
| <literal>Configuration.setNumberFormat(String)</literal>).</para> |
| |
| <para>Note that as number formatting is locale sensitive, the locale |
| setting also plays role in the formatting:</para> |
| |
| <programlisting role="template"><#setting number_format=",##0.00"> |
| <#setting locale="en_US"> |
| US people write: ${12345678} |
| <#setting locale="de_DE"> |
| German people write: ${12345678}</programlisting> |
| |
| <programlisting role="output">US people write: 12,345,678.00 |
| German people write: 12.345.678,00</programlisting> |
| |
| <simplesect xml:id="topic.extendedJavaDecimalFormat"> |
| <title>Extended Java decimal format</title> |
| |
| <indexterm> |
| <primary>extended Java decimal format</primary> |
| </indexterm> |
| |
| <note> |
| <para>You need at least FreeMarker 2.3.24 for these to work. |
| Before that, extended Java decimal format parts are just |
| silently ignored by |
| <literal>java.text.DecimalFormat</literal>.</para> |
| </note> |
| |
| <para>FreeMarker extends the Java decimal format patterns with |
| extra options. These options are name-value pairs, specified after |
| two semicolons (<literal>;;</literal>) at the end of the format |
| string, or if you had a negative pattern (which is separated from |
| the normal patter with a semicolon, like in <literal>"0.0;minus |
| 0.0"</literal>), the after only one semicolon. For example:</para> |
| |
| <programlisting role="template">Standard decimal format: ${10002.5?string[",000"]} |
| Extended decimal format: ${10002.5?string[",000<emphasis>;; roundingMode=halfUp groupingSeparator=_</emphasis>"]}</programlisting> |
| |
| <programlisting role="output">Standard decimal format: 10,002 |
| Extended decimal format: 10<emphasis>_</emphasis>00<emphasis>3</emphasis></programlisting> |
| |
| <warning> |
| <para>A very easy mistake to make is just using a single |
| semicolon instead of two. It won't even result in an error, as |
| <literal>java.text.DecimalFormat</literal> thinks you have just |
| specified some weird format for negative numbers. So remember to |
| use two semicolons.</para> |
| </warning> |
| |
| <para>Above, in the extended decimal format, we have specified |
| half-up rounding mode and group separator <literal>"_"</literal>. |
| The table of all options follows (note that these are defined by |
| <literal>java.text.DecimalFormat</literal> and |
| <literal>java.text.DecimalFormatSymbols</literal>, not by |
| FreeMarker):</para> |
| |
| <informaltable border="1"> |
| <thead> |
| <tr> |
| <th>Name</th> |
| |
| <th>Meaning / value</th> |
| </tr> |
| </thead> |
| |
| <tbody> |
| <tr> |
| <td><literal>roundingMode</literal></td> |
| |
| <td>The value is one of <literal>up</literal>, |
| <literal>down</literal>, <literal>ceiling</literal>, |
| <literal>floor</literal>, <literal>halfUp</literal>, |
| <literal>halfDown</literal>, <literal>halfEven</literal>, |
| and <literal>unnecessary</literal>. The behavior that most |
| people learns in school is <literal>halfUp</literal>, but |
| the Java default is <literal>halfEven</literal> (also called |
| bankers' rounding). (See <link |
| xlink:href="http://docs.oracle.com/javase/7/docs/api/java/math/RoundingMode.html">the |
| <literal>java.math.RoundingMode</literal> API</link> for |
| explanations.)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>multiplier</literal> since 2.3.29; |
| <literal>multipier</literal> since 2.3.24</td> |
| |
| <td>The number will be shown after multiplied with this |
| integer number.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>decimalSeparator</literal></td> |
| |
| <td>The character separating the integer part from the |
| fraction part (like <literal>"."</literal> in |
| <literal>3.14</literal>).</td> |
| </tr> |
| |
| <tr> |
| <td><literal>monetaryDecimalSeparator</literal></td> |
| |
| <td>This is used instead of |
| <literal>decimalSeparator</literal> when the pattern |
| contains parts that make it a monetary format. (See the |
| <link |
| xlink:href="http://docs.oracle.com/javase/7/docs/api/java/text/DecimalFormat.html">Java |
| decimal number format documentation</link> for more.)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>groupingSeparator</literal></td> |
| |
| <td>The single character used for grouping the integer part |
| (like <literal>","</literal> in |
| <literal>1,000,000</literal>) Note that grouping is turned |
| on by using <literal>","</literal> in the pattern, as shown |
| in the earlier example. If it's not turned on, this option |
| won't have visible effect.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>exponentSeparator</literal></td> |
| |
| <td>This string (of arbitrary length) is used to separate |
| the exponent from the part before it. (like |
| <literal>"E"</literal> in <literal>1.23E6</literal>). Only |
| has visible effect if the pattern specifies exponential |
| (also known as scientific) format, like |
| <literal>"0.##E0"</literal>.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>minusSign</literal></td> |
| |
| <td>The single character used as minus sign (like |
| <literal>"-"</literal> in <literal>-1</literal>).</td> |
| </tr> |
| |
| <tr> |
| <td><literal>infinity</literal></td> |
| |
| <td>The string (of arbitrary length) used to show |
| infinity.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>nan</literal></td> |
| |
| <td>The string (of arbitrary length) used to show |
| not-a-number (NaN).</td> |
| </tr> |
| |
| <tr> |
| <td><literal>percent</literal></td> |
| |
| <td>The single character used as the percent symbol (like |
| <literal>"%"</literal> in <literal>50%</literal>). Only has |
| visible effect if the pattern contains |
| <literal>%</literal>.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>perMill</literal></td> |
| |
| <td>The single character used as the per-mill symbol (like |
| <literal>"‰"</literal> in <literal>50021‰</literal>). Only |
| has visible effect if the pattern contains |
| <literal>‰</literal>.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>zeroDigit</literal></td> |
| |
| <td>The first character in the 10 character range (of |
| character codes) that contains the digits to be used. For |
| example, if this is <literal>A</literal>, then 1 will |
| <literal>B</literal>, 2 will be <literal>C</literal>, and so |
| on.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>currencyCode</literal></td> |
| |
| <td>Currency ISO 4217 code. Only has effect when the pattern |
| contains parts that make it a monetary format. It's an error |
| to specify a code that's not a known ISO 4217 code in the |
| Java installation.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>currencySymbol</literal></td> |
| |
| <td>Currency symbol; shown where the localized currency name |
| is present in the pattern. Overrides the symbol determined |
| based on the <literal>currencyCode</literal>.</td> |
| </tr> |
| </tbody> |
| </informaltable> |
| |
| <para>Regarding the syntax of the options:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The option name and value are separated by equals |
| character (<literal>=</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Options are separated by whitespace and/or optional |
| comma (<literal>,</literal>)</para> |
| </listitem> |
| |
| <listitem> |
| <para>The option value can be quoted with apostrophe |
| (<literal>'</literal>) or normal quotation mark |
| (<literal>"</literal>) , like |
| <literal>exponentSeparator='*10^'</literal> or |
| <literal>exponentSeparator="*10^"</literal>. If the value |
| itself has to contain the character used for quotation, then |
| it has to be entered twice (like <literal>infinity='It''s |
| infinite'</literal>, but you could also write |
| <literal>infinity="It's infinite"</literal>). Backslash has no |
| special meaning.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Non-string values must not be quoted. Strings only has |
| to be quoted if they contain punctuation or whitespace, or any |
| other non-letter non-digit non-<literal>"_"</literal> |
| non-<literal>"$"</literal> characters. Thus, for example, both |
| <literal>roundingMode=down</literal> and |
| <literal>roundingMode="down"</literal> are legal.</para> |
| </listitem> |
| </itemizedlist> |
| </simplesect> |
| </section> |
| |
| <section xml:id="ref_builtin_upper_abc"> |
| <title>upper_abc</title> |
| |
| <indexterm> |
| <primary>upper_abc built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>ABC</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>alphabetical ordinals</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in exists since FreeMarker 2.3.22.</para> |
| </note> |
| |
| <para>Same as <link |
| linkend="ref_builtin_lower_abc"><literal>lower_abc</literal></link>, |
| but converts to upper case letters, like <literal>"A"</literal>, |
| <literal>"B"</literal>, <literal>"C"</literal>, …, |
| <literal>"AA"</literal>, <literal>"AB"</literal>, etc.</para> |
| </section> |
| </section> |
| |
| <section xml:id="ref_builtins_date"> |
| <title>Built-ins for date/time/date-time values</title> |
| |
| <indexterm> |
| <primary>date</primary> |
| |
| <secondary>built-ins</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>time</primary> |
| |
| <secondary>built-ins</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>datetime</primary> |
| |
| <secondary>built-ins</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>timestamp</primary> |
| |
| <secondary>built-ins</secondary> |
| </indexterm> |
| |
| <section xml:id="ref_builtin_date_datetype"> |
| <title>date, time, datetime (when used with a date/time/date-time |
| value)</title> |
| |
| <indexterm> |
| <primary>type-casting</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting between types</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>date built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>time built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>datetime built-in</primary> |
| </indexterm> |
| |
| <para>These built-ins can be used to specify which parts of the |
| date-like variable are in use:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>date</literal>: Date only, no time of the |
| day.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>time</literal>: Only the time of the day, no date |
| part</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>datetime</literal>: Both date and time</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Ideally, you do not need to use these built-ins. |
| Unfortunately, because of the technical limitations of the Java |
| platform, FreeMarker sometimes can't find out which parts of a |
| date-like value is a date, a time or a date-time; ask the |
| programmers which variables has this problem. If FreeMarker has to |
| execute an operation where this information is needed -- such as |
| displaying the value as text -- but it does not know which parts are |
| in use, it will stop with error. This is when you have to use these |
| built-ins. For example, assume <literal>openingTime</literal> is a |
| such problematic variable:</para> |
| |
| <programlisting role="template"><#assign x = openingTime> <#-- no problem can occur here --> |
| ${openingTime?time} <#-- without ?time it would fail --> |
| <#-- For the sake of better understanding, consider this: --> |
| <#assign openingTime = openingTime?time> |
| ${openingTime} <#-- this will work now --></programlisting> |
| |
| <para>These built-ins can also be used to convert date-time values |
| to date or time. For example:</para> |
| |
| <programlisting role="template">Last updated: ${lastUpdated} <#-- assume that lastUpdated is a date-time value --> |
| Last updated date: ${lastUpdated?date} |
| Last updated time: ${lastUpdated?time}</programlisting> |
| |
| <para>will output something like:</para> |
| |
| <programlisting role="output">Last updated: 04/25/2003 08:00:54 PM |
| Last updated date: 04/25/2003 |
| Last updated time: 08:00:54 PM</programlisting> |
| |
| <para>If the left side of the <literal>?</literal> is string, then |
| these built-ins <link linkend="ref_builtin_string_date">convert |
| strings to date/time/date-time</link>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_date_if_unknown"> |
| <title>date_if_unknown, time_if_unknown, datetime_if_unknown</title> |
| |
| <note> |
| <para>This built-in exists since FreeMarker 2.3.21.</para> |
| </note> |
| |
| <para>The <literal>date_if_unknown</literal>, |
| <literal>time_if_unknown</literal>, |
| <literal>datetime_if_unknown</literal> built-ins mark a date-like |
| value with some of the sub-types: date without time, time, or |
| date-time, respectively. However, if the value already holds this |
| information, the built-in has no effect. That is, it will never |
| convert the sub-type of a value, it only adds the sub-type if it was |
| unknown.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_date_iso"> |
| <title>iso_...</title> |
| |
| <indexterm> |
| <primary>iso built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>iso_... built-ins</primary> |
| </indexterm> |
| |
| <note> |
| <para><emphasis>These built-ins are deprecated</emphasis> since |
| FreeMarker 2.3.21, where the <literal>date_format</literal>, |
| <literal>time_format</literal> and |
| <literal>datetime_format</literal> settings understand |
| <literal>"iso"</literal> (for ISO 8601:2004 format) and |
| <literal>"xs"</literal> (for XML Schema format) in additionally to |
| the Java <literal>SimpleDateFormat</literal> patterns. Thus the |
| default format can be set to ISO 8601, or for one time ISO |
| formatting you can use <literal>myDate?string.iso</literal>. <link |
| linkend="topic.dateTimeFormatSettings">See more |
| here...</link></para> |
| </note> |
| |
| <para>These built-ins convert a date, time or date-time value to |
| string that follows ISO 8601:2004 "extended" format.</para> |
| |
| <para>This built-in has several variations: |
| <literal>iso_utc</literal>, <literal>iso_local</literal>, |
| <literal>iso_utc_nz</literal>, <literal>iso_local_nz</literal>, |
| <literal>iso_utc_m</literal>, <literal>iso_utc_m_nz</literal>, etc. |
| The name is constructed from the following words in this order, each |
| separated with a <literal>_</literal> from the next:</para> |
| |
| <orderedlist> |
| <listitem> |
| <para><literal>iso</literal> (required)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Either <literal>utc</literal> or <literal>local</literal> |
| (required (except when it's given with a parameter, but see that |
| later)): Specifies whether you want to print the |
| date/time/date-time according to UTC or according the current |
| time zone. The current time zone is decided by the |
| <literal>time_zone</literal> FreeMarker setting and is normally |
| configured by the programmers outside the templates (but it can |
| also be set in a template, like <literal><#setting |
| time_zone="America/New_York"></literal> for example). Note |
| that if the <literal>sql_date_and_time_time_zone</literal> |
| FreeMarker setting is set and non-<literal>null</literal>, then |
| for <literal>java.sql.Date</literal> and |
| <literal>java.sql.Time</literal> values (i.e., for date-only and |
| time-only values that are coming from database via SQL) |
| <literal>local</literal> will mean that time zone instead of the |
| value of the <literal>time_zone</literal> setting.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Either <literal>h</literal> or <literal>m</literal> or |
| <literal>ms</literal> (optional): The accuracy of the time part. |
| When omitted, it defaults to seconds accuracy (like |
| <literal>12:30:18</literal>). <literal>h</literal> means hours |
| accuracy (like <literal>12</literal>), <literal>m</literal> |
| means minutes accuracy (<literal>12:30</literal>), and |
| <literal>ms</literal> means milliseconds accuracy |
| (<literal>12:30:18.25</literal>, where we have 250 ms). Note |
| that when using <literal>ms</literal>, the milliseconds are |
| displayed as fraction seconds (following the standard) and will |
| not have trailing <literal>0</literal>-s. Thus, if the the |
| millisecond part happens to be <literal>0</literal>, the whole |
| fraction second part will be omitted. Also note that the |
| fraction seconds are always separated with a dot , not with |
| comma (to follow the Web conventions and XML Schema |
| time/dateTime canonical format).</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>nz</literal> (optional): <literal>nz</literal> |
| (like in <literal>${foo?utc_local_nz}</literal>) stands for |
| <quote>no zone</quote>, which means that the time zone offset |
| (like <literal>+02:00</literal> or or <literal>-04:30</literal> |
| or <literal>Z</literal>) will not be displayed. If this part is |
| omitted (like in <literal>${foo?utc_local}</literal>) the zone |
| will be displayed, except in two cases:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>If the value is a date (no time part) value (again, |
| ISO 8901 doesn't allow it then)</para> |
| </listitem> |
| |
| <listitem> |
| <para>If the value is a <literal>java.sql.Time</literal> and |
| the <literal>incompatible_improvements</literal> (often set |
| via the Java <literal>Configuration</literal> constructor |
| parameter) FreeMarker configuration setting is at least |
| 2.3.21 (or 2.3.24 when you are inside a string literal). |
| This is because most databases store time values that aren't |
| in any time zone, but just store hour, minute, second, and |
| decimal second field values, so showing the time zone |
| doesn't make sense.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Note that since FreeMarker 2.3.19, the offset always |
| contains the minutes for XML Schema date/time/dateTime format |
| compliance. (However, if you primarily generate for the XML |
| Schema format, use the xs format.)</para> |
| </listitem> |
| </orderedlist> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template"><#assign aDateTime = .now> |
| <#assign aDate = aDateTime?date> |
| <#assign aTime = aDateTime?time> |
| |
| Basic formats: |
| ${aDate?iso_utc} |
| ${aTime?iso_utc} |
| ${aDateTime?iso_utc} |
| |
| Different accuracies: |
| ${aTime?iso_utc_ms} |
| ${aDateTime?iso_utc_m} |
| |
| Local time zone: |
| ${aDateTime?iso_local}</programlisting> |
| |
| <para>A possible output (depends on current time and time |
| zone):</para> |
| |
| <programlisting role="output">Basic formats: |
| 2011-05-16 |
| 21:32:13Z |
| 2011-05-16T21:32:13Z |
| |
| Different accuracies: |
| 21:32:13.868Z |
| 2011-05-16T21:32Z |
| |
| Local time zone: |
| 2011-05-16T23:32:13+02:00</programlisting> |
| |
| <para>There is yet another group of <literal>iso_...</literal> |
| built-in variants, where you omit the <literal>local</literal> or |
| <literal>utc</literal> word from the name and instead specify the |
| time zone as a parameter to the built-in. Example:</para> |
| |
| <programlisting role="template"><#assign aDateTime = .now> |
| ${aDateTime?iso("UTC")} |
| ${aDateTime?iso("GMT-02:30")} |
| ${aDateTime?iso("Europe/Rome")} |
| |
| The usual variations are supported: |
| ${aDateTime?iso_m("GMT+02")} |
| ${aDateTime?iso_m_nz("GMT+02")} |
| ${aDateTime?iso_nz("GMT+02")}</programlisting> |
| |
| <para>A possible output (depends on current time and time |
| zone):</para> |
| |
| <programlisting role="output">2011-05-16T21:43:58Z |
| 2011-05-16T19:13:58-02:30 |
| 2011-05-16T23:43:58+02:00 |
| |
| The usual variations are supported: |
| 2011-05-16T23:43+02:00 |
| 2011-05-16T23:43 |
| 2011-05-16T23:43:58</programlisting> |
| |
| <para>If the time zone parameter can't be interpreted, the template |
| processing will be terminated with error.</para> |
| |
| <para role="forProgrammers">The parameter can be a |
| <literal>java.util.TimeZone</literal> object too (which is possibly |
| the return value of a Java method, or it's in the data-model), not |
| just a string.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_string_for_date"> |
| <title>string (when used with a date/time/date-time value)</title> |
| |
| <indexterm> |
| <primary>type-casting</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting between types</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>string built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>format</primary> |
| |
| <secondary>date</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>format</primary> |
| |
| <secondary>time</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>format</primary> |
| |
| <secondary>date-time</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>format</primary> |
| |
| <secondary>timestamp</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting date to string</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting time to string</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>time to string</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>date to string</primary> |
| </indexterm> |
| |
| <para>This built-in converts a date to a string, with the specified |
| formatting.</para> |
| |
| <note> |
| <para>You should need this built-in rarely, as the default format |
| of date/time/date-time values can be specified globally <link |
| linkend="topic.dateTimeFormatSettings">with the |
| <literal>date_format</literal>, <literal>time_format</literal> and |
| <literal>datetime_format</literal> settings</link> of FreeMarker. |
| Use this built-in only at the places where the desired format |
| differs from the one normally used. For the other places the |
| default format should be set properly by the programmers, outside |
| the templates.</para> |
| </note> |
| |
| <para>The desired format can be specified like |
| <literal>?string.<replaceable>format</replaceable></literal> or |
| <literal>?string["<replaceable>format</replaceable>"]</literal>(or |
| the historical equivalent, |
| <literal>?string("<replaceable>format</replaceable>")</literal>). |
| These are equivalent, except that with the quoted formats you can |
| include any characters in the |
| <literal><replaceable>format</replaceable></literal>, like spaces. |
| The syntax of <literal><replaceable>format</replaceable></literal> |
| is exactly the same as of the <literal>date_format</literal>, |
| <literal>time_format</literal> and |
| <literal>datetime_format</literal> configuration settings; <link |
| linkend="topic.dateTimeFormatSettings">see the documentation of the |
| possible values there</link>.</para> |
| |
| <para>Example: If the locale of the output is U.S. English, and the |
| time zone is the U.S. Pacific Time zone, and |
| <literal>openingTime</literal> is a |
| <literal>java.sql.Time</literal>, <literal>nextDiscountDay</literal> |
| is <literal>java.sql.Date</literal> and |
| <literal>lastUpdated</literal> is |
| <literal>java.sql.Timestamp</literal> or |
| <literal>java.util.Date</literal> then this:</para> |
| |
| <programlisting role="template"><#-- Predefined format names: --> |
| |
| ${openingTime?string.short} |
| ${openingTime?string.medium} |
| ${openingTime?string.long} |
| ${openingTime?string.full} |
| ${openingTime?string.xs} <#-- XSD xs:time --> |
| ${openingTime?string.iso} <#-- ISO 8601 time --> |
| |
| ${nextDiscountDay?string.short} |
| ${nextDiscountDay?string.medium} |
| ${nextDiscountDay?string.long} |
| ${nextDiscountDay?string.full} |
| ${nextDiscountDay?string.xs} <#-- XSD xs:date --> |
| ${nextDiscountDay?string.iso} <#-- ISO 8601 date --> |
| |
| ${lastUpdated?string.short} |
| ${lastUpdated?string.medium} |
| ${lastUpdated?string.long} |
| ${lastUpdated?string.full} |
| ${lastUpdated?string.medium_short} <#-- medium date, short time --> |
| ${lastUpdated?string.xs} <#-- XSD xs:dateTime --> |
| ${lastUpdated?string.iso} <#-- ISO 8601 combined date and time --> |
| |
| <#-- <link linkend="pgui_config_custom_formats">Programmer-defined named format</link> (@ + name): --> |
| ${lastUpdated?string.@fileDate} |
| |
| <#-- Advanced ISO 8601 and XSD formatting: --> |
| ${lastUpdated?string.iso_m_u} |
| ${lastUpdated?string.xs_ms_nz} |
| |
| <#-- SimpleDateFormat patterns: --> |
| ${lastUpdated?string["dd.MM.yyyy, HH:mm"]} |
| ${lastUpdated?string["EEEE, MMMM dd, yyyy, hh:mm a '('zzz')'"]} |
| ${lastUpdated?string["EEE, MMM d, ''yy"]} |
| ${lastUpdated?string.yyyy} <#-- Same as ${lastUpdated?string["yyyy"]} --> |
| </programlisting> |
| |
| <para>will print something like this:</para> |
| |
| <programlisting role="output">01:45 PM |
| 01:45:09 PM |
| 01:45:09 PM PST |
| 01:45:09 PM PST |
| 13:45:09-08:00 |
| 13:45:09-08:00 |
| |
| 2/20/07 |
| Apr 20, 2007 |
| April 20, 2007 |
| Friday, April 20, 2007 |
| 2007-02-20-08:00 |
| 2007-02-20 |
| |
| 2/20/07 01:45 PM |
| Feb 20, 2007 01:45:09 PM |
| February 20, 2007 01:45:09 PM PST |
| Friday, February 20, 2007 01:45:09 PM PST |
| Feb 8, 2003 9:24 PM |
| 2007-02-20T13:45:09-08:00 |
| 2007-02-20T13:45:09-08:00 |
| |
| Apr/20/2007 13:45 |
| |
| 2007-02-20T21:45Z |
| 2007-02-20T13:45:09.000 |
| |
| 08.04.2003 21:24 |
| Tuesday, April 08, 2003, 09:24 PM (PDT) |
| Tue, Apr 8, '03 |
| 2003</programlisting> |
| |
| <para>Note that with custom formats like in |
| <literal>lastUpdated?string.@fileDate</literal> above, templates can |
| just refer to the application-domain meaning, and the exact format |
| can be specified outside the templates, on a central place. |
| (Programmers can read about <link |
| linkend="pgui_config_custom_formats">defining such named formats |
| here...</link>)</para> |
| |
| <warning> |
| <para>Unfortunately, because of the limitations of the Java |
| platform, it can happen that you have date-like variables in the |
| data-model, where FreeMarker can't decide if the variable is a |
| date (year, month, day), or a time (hour, minute, second, |
| millisecond) or a date-time. In this case, FreeMarker doesn't know |
| how to display the value when you write something like |
| <literal>${lastUpdated?string.short}</literal> or |
| <literal>${lastUpdated?string.xs}</literal>, i.e., a format that |
| doesn't specify the exact fields to display, or if you simply use |
| <literal>${lastUpdated}</literal>. Then it will have to stop with |
| error. To prevent this, you can help FreeMarker with the <link |
| linkend="ref_builtin_date_datetype"><literal>?date</literal>, |
| <literal>?time</literal> and <literal>?datetime</literal> |
| built-ins</link>. For example: |
| <literal>${lastUpdated?datetime?string.short}</literal>. Ask the |
| programmers if certain variables of the data-model have this |
| problem, or always use <literal>?date</literal>, |
| <literal>?time</literal> and <literal>?datetime</literal> |
| built-ins to be on the safe side.</para> |
| </warning> |
| |
| <note> |
| <para>You never need to use <literal>?date</literal>, |
| <literal>?time</literal> or <literal>?datetime</literal> with |
| format patterns like <literal>"yyyy.MM.dd HH:mm"</literal>, since |
| with the pattern you tell FreeMarker what parts of the date to |
| show. However, FreeMarker will trust you blindly, so you can show |
| "noise" if you display parts that are actually not stored in the |
| variable. For example, <literal>${openingTime?string["yyyy-MM-dd |
| hh:mm:ss a"]}</literal>, where <literal>openingTime</literal> |
| stores only time, will display <literal>1970-01-01 09:24:44 |
| PM</literal>.</para> |
| </note> |
| |
| <para>To prevent misunderstandings, the format need not be a string |
| literal, it can be a variable or any other expression as far as it |
| evaluates to a string. For example, it can be like |
| <literal>"<replaceable>...</replaceable>"?string[myFormat]</literal>.</para> |
| |
| <para>See also: <link |
| linkend="dgui_template_valueinserion_universal_date">the |
| interpolation of dates</link></para> |
| </section> |
| </section> |
| |
| <section xml:id="ref_builtins_boolean"> |
| <title>Built-ins for booleans</title> |
| |
| <indexterm> |
| <primary>boolean</primary> |
| |
| <secondary>built-ins</secondary> |
| </indexterm> |
| |
| <section xml:id="ref_builtin_c_boolean"> |
| <title>c (for boolean value)</title> |
| |
| <indexterm> |
| <primary>c built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>type-casting</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting between types</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>format</primary> |
| |
| <secondary>boolean</secondary> |
| </indexterm> |
| |
| <note> |
| <para>The <literal>c</literal> built-in also works <link |
| linkend="ref_builtin_c_boolean"> <link linkend="ref_builtin_c">on |
| numbers</link></link>, and <link linkend="ref_builtin_c_string">on |
| strings</link>!</para> |
| </note> |
| |
| <note> |
| <para>To provide a background, see <xref |
| linkend="dgui_misc_computer_vs_human_format"/></para> |
| </note> |
| |
| <note> |
| <para>The <literal>c</literal> built-in supports booleans since |
| FreeMarker 2.3.20.</para> |
| </note> |
| |
| <para>This built-in converts a boolean to a <quote>computer |
| language</quote> literal, as opposed to format it for human reading. |
| This formats is independent of the <literal>boolean_format</literal> |
| configuration setting, as that setting is meant to specify the |
| format for human readers. Instead, it depends on the <link |
| linkend="gloss.c_format"><literal>c_format</literal> setting</link>. |
| However, currently all <literal>c_format</literal> that's built into |
| FreeMarker result will give <literal>true</literal> or |
| <literal>false</literal>.</para> |
| |
| <para>When outputting boolean literals for JavaScript, JSON, Java, |
| and many other languages, always use this built-in, instead of |
| relying on <literal>boolean_format</literal>.</para> |
| |
| <para>If you only generate output that's computer language and isn't |
| read by end-users, you may prefer to set the |
| <literal>boolean_format</literal> configuration setting to |
| <literal>c</literal> (since FreeMarker 2.3.29), in which case |
| <literal>${<replaceable>aBoolean</replaceable>}</literal> will have |
| the same output as |
| <literal>${<replaceable>aBoolean</replaceable>?c}</literal>.</para> |
| |
| <para>If the value the <literal>c</literal> built-in is applied on |
| is <literal>null</literal>/missing, it will stop the template |
| processing with error, just like most other built-ins. If instead |
| you want to output a <literal>null</literal> literal, see the <link |
| linkend="ref_builtin_cn_string"><literal>cn</literal> |
| built-in</link>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_cn_boolean"> |
| <title>cn (for boolean value)</title> |
| |
| <indexterm> |
| <primary>cn built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>format</primary> |
| |
| <secondary>boolean</secondary> |
| </indexterm> |
| |
| <para>This does the same as the <link |
| linkend="ref_builtin_c_boolean"><literal>c</literal> |
| built-in</link>, but when applied on a |
| <literal>null</literal>/missing value, it will output a |
| <literal>null</literal> value according the <link |
| linkend="gloss.c_format"><literal>c_format</literal> setting</link>. |
| See more details about formatting a <literal>null</literal> <link |
| linkend="ref_builtin_cn">here</link>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_string_for_boolean"> |
| <title>string (when used with a boolean value)</title> |
| |
| <indexterm> |
| <primary>boolean</primary> |
| |
| <secondary>printing</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>type-casting</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting between types</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>string built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>format</primary> |
| |
| <secondary>boolean</secondary> |
| </indexterm> |
| |
| <para>Converts a boolean to a string. You can use it in two |
| ways:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>As <literal>foo?string("yes", "no")</literal>: Formats the |
| boolean value to the first parameter (here: |
| <literal>"yes"</literal>) if the boolean is true, and to the |
| second parameter (here: <literal>"no"</literal>) if it's false. |
| Unless you only meant to format a boolean with simple literals, |
| use <link |
| linkend="ref_builtin_then"><literal>?then(<replaceable>whenTrue</replaceable>, |
| <replaceable>whenFalse</replaceable>)</literal></link> instead, |
| as that has less type limitations, and it evaluate its |
| parameters lazily! The return value of |
| <literal>?string</literal> is always a string (unlike for |
| <literal>?then</literal>), because if the parameters aren't |
| strings, they will be converted to strings. Also note that both |
| parameters are evaluated (unlike for <literal>?then</literal>), |
| despite that only one of them will be used; this might has |
| negative impact if the parameters aren't just literals.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>foo?string</literal>: <emphasis>Deprecated |
| starting from FreeMarker 2.3.20: use <link |
| linkend="ref_builtin_c_boolean"><literal>?c</literal></link> |
| instead, or set the <literal>boolean_format</literal> <link |
| linkend="ref_directive_setting">setting</link> to something like |
| <literal>"yes,no"</literal> and then the conversion can happen |
| automatically</emphasis>. If you still need to know about this, |
| this will convert the boolean to string using the default |
| strings for representing true and false values. By default, true |
| is rendered as <literal>"true"</literal> and false is rendered |
| as <literal>"false"</literal>. This is mostly only useful if you |
| generate source code with FreeMarker <emphasis>(but use |
| <literal>?c</literal> for that starting from 2.3.20)</emphasis>. |
| To change these default strings, you can use the |
| <literal>boolean_format</literal> <link |
| linkend="ref_directive_setting">setting</link>.</para> |
| |
| <para role="forProgrammers">Note that in the very rare case when |
| a value is multi-typed and is both a boolean and a string, then |
| the string value of the variable will be returned, and so the |
| <literal>boolean_format</literal> setting will have no |
| effect.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section xml:id="ref_builtin_then"> |
| <title>then</title> |
| |
| <indexterm> |
| <primary>then built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>ternary operator</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>format; boolean</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in exists since FreeMarker 2.3.23.</para> |
| </note> |
| |
| <para>Used like |
| <literal><replaceable>booleanExp</replaceable>?then(<replaceable>whenTrue</replaceable>, |
| <replaceable>whenFalse</replaceable>)</literal>, fills the same role |
| as the ternary operator in C-like languages (i.e., |
| <literal><replaceable>booleanExp</replaceable> ? |
| <replaceable>whenTrue</replaceable> : |
| <replaceable>whenFalse</replaceable></literal>). If |
| <literal><replaceable>booleanExp</replaceable></literal> evaluates |
| to boolean true then it evaluates and returns its first argument, or |
| else if <literal><replaceable>booleanExp</replaceable></literal> |
| evaluates to boolean false then it evaluates and return its second |
| argument. Off course, all three expression can be arbitrary complex. |
| The argument expressions can have any type, even different |
| types.</para> |
| |
| <para>An important special property of this built-in is that only |
| one of the argument expressions will be evaluated. This is unlike |
| with normal method calls, where all argument expressions are |
| evaluated, regardless if the method will need them. This also means |
| that the argument that's not needed can even refer to missing |
| variables without causing error. (It still can't be syntactically |
| invalid of course.)</para> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template"><#assign foo = true> |
| ${foo?then('Y', 'N')} |
| |
| <#assign foo = false> |
| ${foo?then('Y', 'N')} |
| |
| <#assign x = 10> |
| <#assign y = 20> |
| <#-- Prints 100 plus the maximum of x and y: --> |
| ${100 + (x > y)?then(x, y)}</programlisting> |
| |
| <programlisting role="output">Y |
| |
| N |
| |
| 120</programlisting> |
| |
| <note> |
| <para>If you need to choose based on a non-boolean value, you |
| should use the <link |
| linkend="ref_builtin_switch"><literal>switch</literal> |
| built-in</link> instead of nesting multiple |
| <literal>then</literal>-s into each other, like |
| <literal>priority?switch(1, "low", 2, "medium", 3, |
| "high")</literal>, or even <literal>true?switch(priority <= 1, |
| "low", priority == 2, "medium", priority >= 3, |
| "high")</literal>.</para> |
| </note> |
| </section> |
| </section> |
| |
| <section xml:id="ref_builtins_sequence"> |
| <title>Built-ins for sequences</title> |
| |
| <indexterm> |
| <primary>sequence</primary> |
| |
| <secondary>built-ins</secondary> |
| </indexterm> |
| |
| <section xml:id="ref_builtin_chunk"> |
| <title>chunk</title> |
| |
| <indexterm> |
| <primary>chunk built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>tabular printing of sequences</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>columnar printing of sequences</primary> |
| </indexterm> |
| |
| <para>This built-in splits a sequence into multiple sequences of the |
| size given with the 1st parameter to the built-in (like |
| <literal>mySeq?chunk(3)</literal>). The result is the sequence of |
| these sequences. The last sequence is possibly shorter than the |
| given size, unless the 2nd parameter is given (like |
| <literal>mySeq?chunk(3, '-')</literal>), that is the item used to |
| make up the size of the last sequence to the given size. |
| Example:</para> |
| |
| <programlisting role="template"><#assign seq = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']> |
| |
| <#list seq?chunk(4) as row> |
| <#list row as cell>${cell} </#list> |
| </#list> |
| |
| <#list seq?chunk(4, '-') as row> |
| <#list row as cell>${cell} </#list> |
| </#list></programlisting> |
| |
| <para>The output will be:</para> |
| |
| <programlisting role="output"> |
| a b c d |
| e f g h |
| i j |
| |
| a b c d |
| e f g h |
| i j - - |
| </programlisting> |
| |
| <para>This built in is mostly for outputting sequnces in |
| tabular/columnar format. When used with HTML tables, the 2nd |
| parameter is often <literal>"\xA0"</literal> (that is the code of |
| the no-break space character, also known as <quote>nbsp</quote>), so |
| the border of the empty TD-s will not be missing.</para> |
| |
| <para>The 1st parameter must be a number that is at least 1. If the |
| number is not integer, it will be silently rounded down to integer |
| (i.e. both 3.1 and 3.9 will be rounded to 3). The 2nd parameter can |
| be of any type and value.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_drop_while"> |
| <title>drop_while</title> |
| |
| <indexterm> |
| <primary>drop_while built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>sequence</primary> |
| |
| <secondary>drop while</secondary> |
| </indexterm> |
| |
| <para>Returns a new sequence that contains the elements from the |
| input sequence starting with from the first element that does |
| <emphasis>not</emphasis> match the parameter predicate (condition). |
| After that, all elements are included, regardless if they match the |
| predicate or not. See the <link |
| linkend="ref_builtin_filter"><literal>filter</literal> |
| built-in</link> for more details about parameters, and other |
| details, but note that the condition in <literal>filter</literal> |
| has opposite meaning (what to keep, instead of what to drop).</para> |
| |
| <para>Example and comparison with <literal>filter</literal>:</para> |
| |
| <programlisting role="template"><#assign xs = [1, 2, -3, 4, -5, 6]> |
| |
| Drop while positive: |
| <#list xs?drop_while(x -> x > 0) as x>${x} </#list> |
| |
| Filer for positives: |
| <#list xs?filter(x -> x > 0) as x>${x} </#list></programlisting> |
| |
| <programlisting role="output">Drop while positive: |
| -3 4 -5 6 |
| |
| Filer for positives: |
| 1 2 4 6 </programlisting> |
| |
| <para>As you can see, <literal>drop_while</literal> has stopped |
| dropping the elements once it ran into the first element that didn't |
| match the predicate (<literal>x > 0</literal>). On the other |
| hand, <literal>filter</literal> keeps the elements that match the |
| same predicate, and it doesn't stop.</para> |
| |
| <para>See also: <link |
| linkend="ref_builtin_take_while"><literal>take_while</literal> |
| built-in</link></para> |
| </section> |
| |
| <section xml:id="ref_builtin_filter"> |
| <title>filter</title> |
| |
| <indexterm> |
| <primary>filter built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>sequence</primary> |
| |
| <secondary>filter</secondary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since 2.3.29</para> |
| </note> |
| |
| <para>Returns a new sequence that only contains the elements for |
| which the parameter condition (the predicate) returns |
| <literal>true</literal>. For example:</para> |
| |
| <programlisting role="template"><#assign xs = [1, -2, 3, 4, -5]> |
| Positives: |
| <#list xs?<emphasis>filter(x -> x > 0)</emphasis> as x>${x} </#list> |
| Negatives: |
| <#list xs?<emphasis>filter(x -> x < 0)</emphasis> as x>${x} </#list></programlisting> |
| |
| <programlisting role="output">Positives: |
| 1 3 4 |
| Negatives: |
| -2 -5 </programlisting> |
| |
| <para>This built-in has a single required parameter, the predicate |
| (filter condition, what to keep). The predicate can be specified in |
| 3 ways:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>As a single argument <link |
| linkend="dgui_template_exp_lambda">lambda expression</link>: |
| <literal><replaceable>element</replaceable> -> |
| <replaceable>predicate</replaceable></literal>. In that, |
| <literal><replaceable>element</replaceable></literal> is the |
| variable name with which you can refer to the current element in |
| the <literal><replaceable>predicate</replaceable></literal>, and |
| the <literal><replaceable>predicate</replaceable></literal> is |
| an arbitrarily complex <link |
| linkend="dgui_template_exp">expression</link> that must return a |
| boolean value (<literal>true</literal> or |
| <literal>false</literal>). An example this was shown above. Note |
| again the predicates can be arbitrarily complex, like the |
| predicate in <literal>products?filter(product -> |
| product.discounted && |
| !user.hasBought(product))</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>As a <link |
| linkend="ref_directive_function">function</link> or method that |
| has a single argument, and returns boolean. For example, the |
| <quote>Negatives</quote> example above could be implemented like |
| this:</para> |
| |
| <programlisting role="template"><#function negative(x)> |
| <#return x < 0> |
| </#function> |
| |
| <replaceable>...</replaceable> |
| |
| Negatives: |
| <#list xs<emphasis>?filter(negative)</emphasis> as x>${x} </#list></programlisting> |
| |
| <para>Note how we just referred to the function by name, and did |
| not call it. Similarly, if you have a Java object called |
| <literal>utils</literal> in the data-model, and it has a |
| <literal>boolean isNegative(Number n)</literal> method, then you |
| could use that like |
| <literal>xs?filter(utils.isNegative)</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <note> |
| <para>Remember, the condition (predicate) that you specify tells |
| <emphasis>what to keep</emphasis>, not what to filter out! That |
| is, the element will be in the result sequence when you return |
| <literal>true</literal>, not when you return |
| <literal>false</literal>. (It's like the <literal>WHERE</literal> |
| condition in SQL, if you know that.)</para> |
| </note> |
| |
| <para>While <literal>filter</literal> is most often used in the |
| <link linkend="ref.directive.list"><literal>list</literal> |
| directive</link>, naturally it can be used anywhere where a filtered |
| sequence is needed, and so this works as well:</para> |
| |
| <programlisting role="template"><#assign negatives = xs?filter(x -> x < 0)> |
| Negatives: |
| <#list negatives as x>${x} </#list></programlisting> |
| |
| <para>Note however, that for a very long sequences, the above |
| solution can consume significantly more memory. That's because |
| <literal><list |
| <replaceable>seq</replaceable>?filter(<replaceable>pred</replaceable>) |
| <replaceable>...</replaceable>></literal> is optimized to do |
| filtering without building an intermediate filtered sequence, while |
| the n above example, <literal>assign</literal> will first build the |
| whole filtered sequence in memory, and we pass that filtered |
| sequence later to <literal>list</literal>. But again, this only |
| matters for very long sequences.</para> |
| |
| <para>See also: <link |
| linkend="ref_builtin_take_while"><literal>take_while</literal> |
| built-in</link>, <link |
| linkend="ref_builtin_drop_while"><literal>drop_while</literal> |
| built-in</link></para> |
| |
| <simplesect xml:id="topic.filterLazyEval"> |
| <title>Lazy evaluation and its consequences</title> |
| |
| <note> |
| <para>Identical rules apply to these built-ins as well: <link |
| linkend="ref_builtin_map"><literal>map(<replaceable>mapper</replaceable>)</literal></link>, |
| <link |
| linkend="ref_builtin_take_while"><literal>take_while(<replaceable>predicate</replaceable>)</literal></link>, |
| <link |
| linkend="ref_builtin_drop_while"><literal>drop_while(<replaceable>predicate</replaceable>)</literal></link>.</para> |
| </note> |
| |
| <para>To optimize processing, <literal>filter</literal> might |
| delays fetching the elements of the input sequence, and applying |
| the predicate on them. But it's guaranteed that those operations |
| are not delayed past the point where the execution of the |
| directive or interpolation, whose parameter contains the |
| <literal><replaceable>seq</replaceable>?filter(<replaceable>predicate</replaceable>)</literal>, |
| is finished. Some examples:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>In the case of <literal><list |
| <replaceable>seq</replaceable>?filter(<replaceable>predicate</replaceable>) |
| <replaceable>...</replaceable>><replaceable>nested |
| content</replaceable></#list></literal>, when the |
| execution enters the <literal><replaceable>nested |
| content</replaceable></literal>, it's not true that all |
| elements of <literal><replaceable>seq</replaceable></literal> |
| was already consumed and filtered. Consuming and filtering |
| <literal><replaceable>seq</replaceable></literal> is instead |
| done bit by bit as <literal>list</literal> repeats the nested |
| content. But it's guaranteed that past the |
| <literal></#list></literal> tag (the end of the |
| execution of the <literal>list</literal> directive), there are |
| no delayed readings of |
| <literal><replaceable>seq</replaceable></literal>, or delayed |
| evaluation of the |
| <literal><replaceable>predicate</replaceable></literal>. So |
| avoid changing a such variable (or other system state) in the |
| nested content of <literal>list</literal>, which influences |
| the result of the |
| <literal><replaceable>predicate</replaceable></literal>. Doing |
| so could change the filtering for the rest of the |
| <literal><replaceable>seq</replaceable></literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>In the case of <literal><#assign |
| <replaceable>filteredSeq</replaceable> = |
| <replaceable>seq</replaceable>?filter(<replaceable>predicate</replaceable>)></literal> |
| it's guaranteed that all elements of |
| <literal><replaceable>seq</replaceable></literal> were |
| processed, and thus |
| <literal><replaceable>predicate</replaceable></literal> won't |
| be evaluated after the <literal>assign</literal> |
| directive.</para> |
| </listitem> |
| |
| <listitem> |
| <para>In the case of |
| <literal>${<replaceable>seq</replaceable>?filter(<replaceable>predicate</replaceable>)?join(', |
| ')}</literal> it's guaranteed that all elements of |
| <literal><replaceable>seq</replaceable></literal> were |
| processed, and thus |
| <literal><replaceable>predicate</replaceable></literal> won't |
| be evaluated after the <literal>assign</literal> |
| directive.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Inside <link linkend="dgui_template_exp">expressions</link> |
| however, there's no promise regarding when the elements are |
| consumed and when the predicate is evaluated. Like in the case of |
| <literal><replaceable>seq</replaceable>?filter(<replaceable>predicate1</replaceable>)?filter(<replaceable>predicate2</replaceable>)</literal>, |
| it's not guaranteed that |
| <literal><replaceable>predicate1</replaceable></literal> will only |
| be evaluated before |
| <literal><replaceable>predicate2</replaceable></literal>. (Most |
| likely they will be called alternately: |
| <literal><replaceable>predicate1</replaceable></literal> for the |
| 1st element, then |
| <literal><replaceable>predicate2</replaceable></literal> for the |
| 1st element, then |
| <literal><replaceable>predicate1</replaceable></literal> for the |
| 2nd element, then |
| <literal><replaceable>predicate2</replaceable></literal> for the |
| 2nd element, and so on.)</para> |
| |
| <para>If you pass a filtered sequence to a |
| <emphasis>custom</emphasis> directive (a macro) or function or |
| method, as in <literal><@<replaceable>myMacro</replaceable> |
| <replaceable>seq</replaceable>?filter(<replaceable>predicate</replaceable>) |
| /></literal> or |
| <literal><replaceable>myFunction</replaceable>(<replaceable>seq</replaceable>?filter(<replaceable>predicate</replaceable>))</literal>, |
| then it's guaranteed that the filtering is not delayed past the |
| point when the custom directive/function/method is invoked. That |
| is, your macro/function/method will aways receive a fully |
| constructed filtered sequence.</para> |
| |
| <para>Also note that in it's <emphasis>not</emphasis> guaranteed |
| that all elements of the input sequence will be read, and |
| therefore that the predicate will be evaluated for all elements. |
| Some examples of such cases:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>You may <link |
| linkend="ref.directive.list.break"><literal>break</literal></link> |
| out from <literal><list |
| <replaceable>seq</replaceable>?filter(<replaceable>predicate</replaceable>) |
| <replaceable>...</replaceable>></literal> before it reaches |
| the last element, in which case the rest of the |
| <literal><replaceable>seq</replaceable></literal> elements |
| won't be fetched and filtered.</para> |
| </listitem> |
| |
| <listitem> |
| <para>In the case of |
| <literal><replaceable>seq</replaceable>?filter(<replaceable>predicate</replaceable>)[2]</literal>, |
| which reads the 3rd element of the filtered sequence, |
| FreeMarker stops fetching and filtering the elements of |
| <literal><replaceable>seq</replaceable></literal> when we have |
| found the 3rd element that matches the |
| <literal><replaceable>predicate</replaceable></literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>In the case of |
| <literal><replaceable>seq</replaceable>?filter(<replaceable>predicate</replaceable>)?size |
| != 0</literal>, which tells whether the filtered sequence is |
| non-empty, we stop fetching and filtering the elements of |
| <literal><replaceable>seq</replaceable></literal> when we have |
| found the 1st element that matches the |
| <literal><replaceable>predicate</replaceable></literal>. |
| (That's certainly surprising as <literal>?size</literal> needs |
| to process the whole sequence to tell the size. But in this |
| case FreeMarker notices that we don't really need the exact |
| size.)</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>If you are a Java programmer, note how the |
| <literal>filter</literal> built-in differs from Java |
| <literal>Stream.filter</literal>. <literal>Stream.filter</literal> |
| is <quote>lazy</quote>, while FreeMarker <literal>filter</literal> |
| is basically <quote>eager</quote>, and is only <quote>lazy</quote> |
| in special cases, and within a limited scope. Thus, unlike in |
| Java, calling <literal>filter</literal> is not always free. In |
| particular, if you assign a filtered sequence to a variable, or |
| pass it to a custom directive/function/method, the filtered |
| sequence will be created eagerly.</para> |
| </simplesect> |
| |
| <simplesect xml:id="topic.filterLongInput"> |
| <title>Filtering very long input that you don't hold in |
| memory</title> |
| |
| <note> |
| <para>Identical rules apply to these built-ins as well: <link |
| linkend="ref_builtin_map"><literal>map(<replaceable>mapper</replaceable>)</literal></link>, |
| <link |
| linkend="ref_builtin_take_while"><literal>take_while(<replaceable>predicate</replaceable>)</literal></link>, |
| <link |
| linkend="ref_builtin_drop_while"><literal>drop_while(<replaceable>predicate</replaceable>)</literal></link>.</para> |
| </note> |
| |
| <para>Some applications, particularly those that render huge |
| tables, use <link linkend="dgui_datamodel_container">sequence-like |
| values</link> in the data-model that are not held in memory at |
| once, instead they are like a stream of elements that you can only |
| read in the order as they are given to you (on the Java side these |
| are <literal>java.util.Iterator</literal>-s, or |
| <literal>java.util.Iterables</literal>, or the like). These will |
| have <quote>collection</quote> type in the template language, |
| which is like a restricted sequence.</para> |
| |
| <para><literal>filter</literal> works with collection input too. |
| As you have seen earlier, <literal>filter</literal> might stores |
| the entire filtered sequence in the memory, which in this case |
| sounds concerning, because if the input was too big to fit into |
| the memory (hence it wasn't exposed as a sequence), then the |
| filtered collection can be too big as well. For that reason, if |
| the input is not a sequence (but a collection), |
| <literal>filter</literal> never collects its result into the |
| memory, and never fetches and processes the input elements until |
| they are really needed (<quote>lazy</quote> behavior). Furthermore |
| the result of <literal>filter</literal> is then a collection, not |
| a sequence, therefor sequence operations (like |
| <literal><replaceable>seq</replaceable>[<replaceable>index</replaceable>]</literal>) |
| will not work on it.</para> |
| |
| <para>Unlike with sequence input, any operation that would cause |
| collecting the whole filtered result into the memory will now |
| fail. Let's see that through examples. Let's say we have |
| <literal>hugeTable</literal> in the data-model, which is not a |
| sequence, but still a collection (probably an |
| <literal>Iterator</literal> in Java). Then, consider:</para> |
| |
| <programlisting role="template"><#-- Works: --> |
| <#list hugeTable?filter(<replaceable>predicate</replaceable>) as row><replaceable>nested content</replaceable></#list></programlisting> |
| |
| <para>This works fine, since <literal>list</literal> doesn't |
| require collecting the result into the memory</para> |
| |
| <para>Consider this:</para> |
| |
| <programlisting role="template"><#-- Fails if hugeTable is not a sequence, just a collection: --> |
| <#assign filteredHugeTable = hugeTable?filter(<replaceable>predicate</replaceable>)></programlisting> |
| |
| <para>This fails, as filtering can't be postponed beyond the |
| containing directive (<literal>assign</literal>), so FreeMareker |
| had to put the entire filtered result into |
| <literal>filteredHugeTable</literal>. If, however, you know that |
| <literal>filteredHugeTable</literal> won't be too big, you can |
| explicitly collect the result into a sequence via the <link |
| linkend="ref_builtin_sequence"><literal>sequence</literal> |
| built-in</link>:</para> |
| |
| <programlisting role="template"><#-- Works, but be sure filtredHugeTable fits into the memory: --> |
| <#assign filteredHugeTable = hugeTable?filter(predicate)<emphasis>?sequence</emphasis>></programlisting> |
| |
| <para>Naturally, applying the <literal>sequence</literal> built-in |
| allows all sequence operations, such as |
| <literal><replaceable>seq</replaceable>[<replaceable>index</replaceable>]</literal>, |
| <literal><replaceable>seq</replaceable>[<replaceable>range</replaceable>]</literal>, |
| or |
| <literal><replaceable>seq</replaceable>?<replaceable>size</replaceable></literal>. |
| If these operations are directly applied on a sequence that was |
| converted from a collection, then FreeMarker optimizes out |
| actually creating the sequence in memory. So these won't consume |
| much memory regardless of the size of the filtered |
| <literal>hugeTable</literal>:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>hugeTable?filter(<replaceable>predicate</replaceable>)?sequence[index]</literal>: |
| FreeMarker will just fetch and drop the elements till it |
| reaches the element at the desired position.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>hugeTable?filter(<replaceable>predicate</replaceable>)?sequence[0..9]</literal>: |
| FreeMarker will just collect the first 10 elements.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>hugeTable?filter(<replaceable>predicate</replaceable>)?sequence?size</literal>: |
| In this case the whole <literal>hugeTable</literal> will be |
| fetched, which is possibly slow, but the fetched elements are |
| still not collected into the memory, as they only need to be |
| counted.</para> |
| </listitem> |
| </itemizedlist> |
| </simplesect> |
| |
| <simplesect xml:id="topic.filterMissing"> |
| <title>Filtering missing (null) values</title> |
| |
| <para>The argument to a lambda expression can hold the missing |
| (Java <literal>null</literal>) value, and reading such value will |
| not fall back to a higher scope. Thus, something like |
| <literal>seq?filter(it -> it??)</literal>, which filters out |
| missing element from the sequence, will work reliably.</para> |
| </simplesect> |
| </section> |
| |
| <section xml:id="ref_builtin_first"> |
| <title>first</title> |
| |
| <indexterm> |
| <primary>first built-in</primary> |
| </indexterm> |
| |
| <para>Returns the first item of the sequence. Thus |
| <literal><replaceable>value</replaceable>?first</literal> is the |
| same as <literal><replaceable>value</replaceable>[0]</literal>, |
| except that, since FreeMarker 2.3.26, |
| <literal><replaceable>value</replaceable>?first</literal> also works |
| if <literal><replaceable>value</replaceable></literal> doesn't |
| support getting items with numerical index, but still supports to be |
| listed (i.e., with FTL collection values).</para> |
| |
| <para>If the sequence or collection is empty, the result will be a |
| missing value (as in |
| <literal><replaceable>empty</replaceable>?first!'No item was |
| found'</literal>).</para> |
| </section> |
| |
| <section xml:id="ref_builtin_join"> |
| <title>join</title> |
| |
| <indexterm> |
| <primary>join built-in</primary> |
| </indexterm> |
| |
| <para>Concatenates the items of a sequence to a single string, with |
| the given separator. For example:</para> |
| |
| <programlisting role="template"><#assign colors = ["red", "green", "blue"]> |
| ${colors?join(", ")}</programlisting> |
| |
| <para>will output:</para> |
| |
| <programlisting role="output">red, green, blue</programlisting> |
| |
| <para>Sequence items that are not strings will be converted to |
| string with the same conversion rules as of |
| <literal>${<replaceable>...</replaceable>}</literal> (except, of |
| course, no automatic escaping is applied at this stage).</para> |
| |
| <para><literal>?join(<replaceable>...</replaceable>)</literal> can |
| have up to 3 parameters:</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>Separator, required: The string that is inserted between |
| items</para> |
| </listitem> |
| |
| <listitem> |
| <para>Empty value, defaults to <literal>""</literal> (empty |
| string): The value used if the sequence contains no |
| items.</para> |
| </listitem> |
| |
| <listitem> |
| <para>List ending, defaults to <literal>""</literal> (empty |
| string): The value printed after the last value, if the list |
| sequence wasn't empty.</para> |
| </listitem> |
| </orderedlist> |
| |
| <para>So this (where <literal>[]</literal> means an empty |
| sequence):</para> |
| |
| <programlisting role="template">${colors?join(", ", "-")} |
| ${[]?join(", ", "-")} |
| |
| ${colors?join(", ", "-", ".")} |
| ${[]?join(", ", "-", ".")}</programlisting> |
| |
| <para>will output:</para> |
| |
| <programlisting role="output">red, green, blue |
| - |
| |
| red, green, blue. |
| -</programlisting> |
| |
| <para role="forProgrammers">Sequences coming from Java might contain |
| <literal>null</literal> values. Those values will be ignored by this |
| built-in, exactly like if they were removed from the list.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_last"> |
| <title>last</title> |
| |
| <indexterm> |
| <primary>last built-in</primary> |
| </indexterm> |
| |
| <para>The last subvariable of the sequence. Template processing will |
| die with error if the sequence is empty.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_map"> |
| <title>map</title> |
| |
| <indexterm> |
| <primary>map built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>sequence</primary> |
| |
| <secondary>filter</secondary> |
| </indexterm> |
| |
| <para>Returns an new sequence where all elements are replaced with |
| the result of the parameter lambda, function, or method. For |
| example, you have a list of user objects in |
| <literal>users</literal>, but instead you need a list of user names |
| in variable, then you could do this:</para> |
| |
| <programlisting role="template"><#assign userNames = users?map(user -> user.name)></programlisting> |
| |
| <para>The parameter work like the parameter of the with <link |
| linkend="ref_builtin_filter"><literal>filter</literal> |
| built-in</link> (so see there), except that the |
| lambda/function/method you specify can return values of any |
| type.</para> |
| |
| <para>Regarding lazy evaluation, and handling of very long inputs, |
| it also <link linkend="topic.filterLazyEval">works on the same |
| way</link> as the <link |
| linkend="ref_builtin_filter"><literal>filter</literal> |
| built-in</link>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_min_max"> |
| <title>min, max</title> |
| |
| <indexterm> |
| <primary>min built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>max built-in</primary> |
| </indexterm> |
| |
| <para>Returns the smaller (<literal>min</literal>) or greatest |
| (<literal>max</literal>) item of the sequence (or collection). The |
| items must be either all numbers, or all date/time values of the |
| same kind (date-only, time-only, date-time), or else a comparison |
| error will occur. These are the same restrictions as for the <link |
| linkend="dgui_template_exp_comparison"><literal><</literal> and |
| <literal>></literal> operators</link>.</para> |
| |
| <para>Missing items (i.e., Java <literal>null</literal>-s) will be |
| silently ignored. If the sequence is empty or it only contains |
| missing (Java <literal>null</literal>) items, the result itself will |
| be missing.</para> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template">${[1, 2, 3]?min} |
| ${[1, 2, 3]?max} |
| ${[]?min!'-'}</programlisting> |
| |
| <programlisting role="output">1 |
| 3 |
| -</programlisting> |
| </section> |
| |
| <section xml:id="ref_builtin_reverse"> |
| <title>reverse</title> |
| |
| <indexterm> |
| <primary>reverse built-in</primary> |
| </indexterm> |
| |
| <para>The sequence with reversed order.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_seq_contains"> |
| <title>seq_contains</title> |
| |
| <indexterm> |
| <primary>seq_contains built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>The <literal>seq_</literal> prefix is required in the |
| built-in name to differentiate it from the <link |
| linkend="ref_builtin_contains"><literal>contains</literal> |
| built-in</link> that searches a substring in a string (since a |
| variable can be both string and sequence on the same time).</para> |
| </note> |
| |
| <para>Tells if the sequence contains the specified value (according |
| the <link |
| linkend="dgui_template_exp_comparison"><literal>==</literal> |
| operator</link> of the template language, not according Java's |
| <literal>Object.equals</literal>). It has 1 parameter, the value to |
| find. Example:</para> |
| |
| <programlisting role="template"><#assign x = ["red", 16, "blue", "cyan"]> |
| "blue": ${x?seq_contains("blue")?string("yes", "no")} |
| "yellow": ${x?seq_contains("yellow")?string("yes", "no")} |
| 16: ${x?seq_contains(16)?string("yes", "no")} |
| "16": ${x?seq_contains("16")?string("yes", "no")}</programlisting> |
| |
| <para>The output will be:</para> |
| |
| <programlisting role="output">"blue": yes |
| "yellow": no |
| 16: yes |
| "16": no</programlisting> |
| |
| <para>To find the value the built-in uses FreeMarker's comparison |
| rules (as if you was using <link |
| linkend="dgui_template_exp_comparison"><literal>==</literal> |
| operator</link>), except that comparing two values of different |
| types or of types for which FreeMarker doesn't support comparison |
| will not cause error, just will be evaluated as the two values are |
| not equal. Thus, you can use it only to find scalar values (i.e. |
| string, number, boolean or date/time values). For other types the |
| result will be always <literal>false</literal>.</para> |
| |
| <para>For fault tolerance, this built-in also works with |
| collections.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_seq_index_of"> |
| <title>seq_index_of</title> |
| |
| <indexterm> |
| <primary>seq_index_of built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.1. It |
| doesn't exist in 2.3.</para> |
| </note> |
| |
| <note> |
| <para>The <literal>seq_</literal> prefix is required in the |
| built-in name to differentiate it from the <link |
| linkend="ref_builtin_index_of"><literal>index_of</literal> |
| built-in</link> that searches a substring in a string (since a |
| variable can be both string and sequence on the same time).</para> |
| </note> |
| |
| <para>Returns the index of the first occurrence of a value in the |
| sequence, or <literal>-1</literal> if the sequence doesn't contain |
| the specified value. The value to find is specified as the first |
| parameter. For example this template:</para> |
| |
| <programlisting role="template"><#assign colors = ["red", "green", "blue"]> |
| ${colors?seq_index_of("blue")} |
| ${colors?seq_index_of("red")} |
| ${colors?seq_index_of("purple")}</programlisting> |
| |
| <para>will output this:</para> |
| |
| <programlisting role="output">2 |
| 0 |
| -1</programlisting> |
| |
| <para>To find the value the built-in uses FreeMarker's comparison |
| rules (as if you was using <link |
| linkend="dgui_template_exp_comparison"><literal>==</literal> |
| operator</link>), except that comparing two values of different |
| types or of types for which FreeMarker doesn't support comparison |
| will not cause error, just will be evaluated as the two values are |
| not equal. Thus, you can use it only to find scalar values (i.e. |
| string, number, boolean or date/time values). For other types the |
| result will be always <literal>-1</literal>.</para> |
| |
| <para>The index where the searching is started can be optionally |
| given as the 2nd parameter. This may be useful if the same item can |
| occur for multiple times in the same sequence. There is no |
| restriction on the numerical value of the second parameter: if it is |
| negative, it has the same effect as if it were zero, and if it is |
| greater than the length of the sequence, it has the same effect as |
| if it were equal to the length of the sequence. Decimal values will |
| be truncated to integers. For example:</para> |
| |
| <programlisting role="template"><#assign names = ["Joe", "Fred", "Joe", "Susan"]> |
| No 2nd param: ${names?seq_index_of("Joe")} |
| -2: ${names?seq_index_of("Joe", -2)} |
| -1: ${names?seq_index_of("Joe", -1)} |
| 0: ${names?seq_index_of("Joe", 0)} |
| 1: ${names?seq_index_of("Joe", 1)} |
| 2: ${names?seq_index_of("Joe", 2)} |
| 3: ${names?seq_index_of("Joe", 3)} |
| 4: ${names?seq_index_of("Joe", 4)}</programlisting> |
| |
| <para>will output this:</para> |
| |
| <programlisting role="output">No 2nd param: 0 |
| -2: 0 |
| -1: 0 |
| 0: 0 |
| 1: 2 |
| 2: 2 |
| 3: -1 |
| 4: -1</programlisting> |
| </section> |
| |
| <section xml:id="ref_builtin_seq_last_index_of"> |
| <title>seq_last_index_of</title> |
| |
| <indexterm> |
| <primary>seq_last_index_of built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.1. It |
| doesn't exist in 2.3.</para> |
| </note> |
| |
| <note> |
| <para>The <literal>seq_</literal> prefix is required in the |
| built-in name to differentiate it from the <link |
| linkend="ref_builtin_last_index_of"><literal>last_index_of</literal> |
| built-in</link> that searches a substring in a string (since a |
| variable can be both string and sequence on the same time).</para> |
| </note> |
| |
| <para>Returns the index of the last occurrence of a value in the |
| sequence, or <literal>-1</literal> if the sequence doesn't contain |
| the specified value. That is, it is the same as <link |
| linkend="ref_builtin_seq_index_of"><literal>seq_index_of</literal></link>, |
| just it searches backward starting from the last item of the |
| sequence. It also supports the optional 2nd parameter that specifies |
| the index where the searching is started. For example:</para> |
| |
| <programlisting role="template"><#assign names = ["Joe", "Fred", "Joe", "Susan"]> |
| No 2nd param: ${names?seq_last_index_of("Joe")} |
| -2: ${names?seq_last_index_of("Joe", -2)} |
| -1: ${names?seq_last_index_of("Joe", -1)} |
| 0: ${names?seq_last_index_of("Joe", 0)} |
| 1: ${names?seq_last_index_of("Joe", 1)} |
| 2: ${names?seq_last_index_of("Joe", 2)} |
| 3: ${names?seq_last_index_of("Joe", 3)} |
| 4: ${names?seq_last_index_of("Joe", 4)}</programlisting> |
| |
| <para>will output this:</para> |
| |
| <programlisting role="output">No 2nd param: 2 |
| -2: -1 |
| -1: -1 |
| 0: 0 |
| 1: 0 |
| 2: 2 |
| 3: 2 |
| 4: 2</programlisting> |
| </section> |
| |
| <section xml:id="ref_builtin_size"> |
| <title>size</title> |
| |
| <indexterm> |
| <primary>size built-in</primary> |
| </indexterm> |
| |
| <para>The number of sub variables in sequence (as a numerical |
| value). The highest possible index in sequence <literal>s</literal> |
| is <literal>s?size - 1</literal> (since the index of the first |
| subvariable is 0) assuming that the sequence has at least one |
| subvariable.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_sort"> |
| <title>sort</title> |
| |
| <indexterm> |
| <primary>sort built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>sequence</primary> |
| |
| <secondary>sorting</secondary> |
| </indexterm> |
| |
| <para>Returns the sequence sorted in ascending order. (For |
| descending order use this and then the <link |
| linkend="ref_builtin_reverse"><literal>reverse</literal> built |
| in</link>.) This will work only if all sub variables are strings, or |
| if all sub variables are numbers, or if all sub variables are date |
| values (date, time, or date+time), or if all sub variables are |
| booleans (since 2.3.17). If the sub variables are strings, it uses |
| locale (language) specific lexical sorting (which is usually not |
| case sensitive). For example:</para> |
| |
| <programlisting role="template"><#assign ls = ["whale", "Barbara", "zeppelin", "aardvark", "beetroot"]?sort> |
| <#list ls as i>${i} </#list></programlisting> |
| |
| <para>will print (with US locale at least):</para> |
| |
| <programlisting role="output">aardvark Barbara beetroot whale zeppelin</programlisting> |
| </section> |
| |
| <section xml:id="ref_builtin_sort_by"> |
| <title>sort_by</title> |
| |
| <indexterm> |
| <primary>sort_by built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>sequence</primary> |
| |
| <secondary>sorting</secondary> |
| </indexterm> |
| |
| <para>Returns the sequence of hashes sorted by the given hash |
| subvariable in ascending order. (For descending order use this and |
| then the <link |
| linkend="ref_builtin_reverse"><literal>reverse</literal> built |
| in</link>.) The rules are the same as with the <link |
| linkend="ref_builtin_sort"><literal>sort</literal> built-in</link>, |
| except that the sub variables of the sequence must be hashes, and |
| you have to give the name of a hash subvariable that will decide the |
| order. For example:</para> |
| |
| <programlisting role="template"><#assign ls = [ |
| {"name":"whale", "weight":2000}, |
| {"name":"Barbara", "weight":53}, |
| {"name":"zeppelin", "weight":-200}, |
| {"name":"aardvark", "weight":30}, |
| {"name":"beetroot", "weight":0.3} |
| ]> |
| Order by name: |
| <#list ls?sort_by("name") as i> |
| - ${i.name}: ${i.weight} |
| </#list> |
| |
| Order by weight: |
| <#list ls?sort_by("weight") as i> |
| - ${i.name}: ${i.weight} |
| </#list></programlisting> |
| |
| <para>will print (with US locale at least):</para> |
| |
| <programlisting role="output">Order by name: |
| - aardvark: 30 |
| - Barbara: 53 |
| - beetroot: 0.3 |
| - whale: 2000 |
| - zeppelin: -200 |
| |
| Order by weight: |
| - zeppelin: -200 |
| - beetroot: 0.3 |
| - aardvark: 30 |
| - Barbara: 53 |
| - whale: 2000</programlisting> |
| |
| <para>If the subvariable that you want to use for the sorting is on |
| a deeper level (that is, if it is a subvariable of a subvariable and |
| so on), then you can use a sequence as parameter, that specifies the |
| names of the sub variables that lead down to the desired |
| subvariable. For example:</para> |
| |
| <programlisting role="template"><#assign members = [ |
| {"name": {"first": "Joe", "last": "Smith"}, "age": 40}, |
| {"name": {"first": "Fred", "last": "Crooger"}, "age": 35}, |
| {"name": {"first": "Amanda", "last": "Fox"}, "age": 25}]> |
| Sorted by name.last: |
| <#list members?sort_by(['name', 'last']) as m> |
| - ${m.name.last}, ${m.name.first}: ${m.age} years old |
| </#list></programlisting> |
| |
| <para>will print (with US locale at least):</para> |
| |
| <programlisting role="output">Sorted by name.last: |
| - Crooger, Fred: 35 years old |
| - Fox, Amanda: 25 years old |
| - Smith, Joe: 40 years old</programlisting> |
| </section> |
| |
| <section xml:id="ref_builtin_take_while"> |
| <title>take_while</title> |
| |
| <indexterm> |
| <primary>take_while built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>sequence</primary> |
| |
| <secondary>take while</secondary> |
| </indexterm> |
| |
| <para>Returns a sequence that only contains the elements of the |
| input sequence which are before the first element that doesn't match |
| the parameter predicate (filter condition). This is very similar to |
| the <link linkend="ref_builtin_filter"><literal>filter</literal> |
| built-in</link>, so see further details there.</para> |
| |
| <para>Example and comparison with <literal>filter</literal>:</para> |
| |
| <programlisting role="template"><#assign xs = [1, 2, -3, 4, -5, 6]> |
| |
| Take while positive: |
| <#list xs<emphasis>?take_while</emphasis>(x -> x > 0) as x>${x} </#list> |
| |
| Filer for positives: |
| <#list xs?filter(x -> x > 0) as x>${x} </#list></programlisting> |
| |
| <programlisting role="output">Take while positive: |
| 1 2 |
| |
| Filer for positives: |
| 1 2 4 6 </programlisting> |
| |
| <para>As you can see, <literal>take_while</literal> has stopped at |
| the first number that didn't match the predicate (<literal>x > |
| 0</literal>), while <literal>filter</literal> has continued finding |
| further matches.</para> |
| |
| <para>See also: <link |
| linkend="ref_builtin_drop_while"><literal>drop_while</literal> |
| built-in</link></para> |
| </section> |
| </section> |
| |
| <section xml:id="ref_builtins_hash"> |
| <title>Built-ins for hashes</title> |
| |
| <indexterm> |
| <primary>hash</primary> |
| |
| <secondary>built-ins</secondary> |
| </indexterm> |
| |
| <section xml:id="ref_builtin_keys"> |
| <title>keys</title> |
| |
| <indexterm> |
| <primary>keys built-in</primary> |
| </indexterm> |
| |
| <para>A sequence that contains all the lookup keys in the |
| hash.</para> |
| |
| <programlisting role="template"><#assign myHash = { "name": "mouse", "price": 50 }> |
| <#list myHash?keys as k> |
| ${k} |
| </#list></programlisting> |
| |
| <programlisting role="output"> name |
| price</programlisting> |
| |
| <para>Note that not all hashes support this (ask the programmer if a |
| certain hash allows this or not).</para> |
| |
| <para>Since hashes do not define an order for their sub variables in |
| general, the order in which key names are returned can be arbitrary. |
| However, some hashes maintain a meaningful order (ask the programmer |
| if a certain hash does that or not). For example, hashes created |
| with the above <literal>{<replaceable>...</replaceable>}</literal> |
| syntax preserve the same order as you have specified the sub |
| variables.</para> |
| |
| <note> |
| <para>To list both the keys and the values, you can use |
| <literal><#list attrs as key, |
| value>...<#list></literal>; see the <link |
| linkend="ref.directive.list"><literal>list</literal> |
| directive</link>.</para> |
| </note> |
| </section> |
| |
| <section xml:id="ref_builtin_values"> |
| <title>values</title> |
| |
| <indexterm> |
| <primary>values built-in</primary> |
| </indexterm> |
| |
| <para>A sequence that contains all the variables (the values in the |
| key-value pairs) in the hash.</para> |
| |
| <programlisting role="template"><#assign myHash = { "name": "mouse", "price": 50 }> |
| <#list myHash?values as v> |
| ${v} |
| </#list></programlisting> |
| |
| <programlisting role="output"> mouse |
| 50</programlisting> |
| |
| <para>Note that not all hashes support this (ask the programmer if a |
| certain hash allows this or not).</para> |
| |
| <para>As of the order in which the values are returned, the same |
| applies as with the <literal>keys</literal> built-in; see there. |
| Furthermore, it's not guaranteed that the order of the values |
| corresponds to the order of the keys returned by the |
| <literal>keys</literal> build-in.</para> |
| |
| <note> |
| <para>To list both the keys and the values, you can use |
| <literal><#list attrs as key, |
| value>...<#list></literal>; see the <link |
| linkend="ref.directive.list"><literal>list</literal> |
| directive</link>.</para> |
| </note> |
| </section> |
| </section> |
| |
| <section xml:id="ref_builtins_node"> |
| <title>Built-ins for nodes (for XML)</title> |
| |
| <indexterm> |
| <primary>node</primary> |
| |
| <secondary>built-ins</secondary> |
| </indexterm> |
| |
| <para>Note that the variables returned by these built-ins are |
| generated by the node variable implementation it is used with. This |
| means that the returned variables can have extra features in |
| additional to what it stated here, for example, with the <link |
| linkend="xgui_expose_dom">XML DOM nodes</link> the sequence retuned by |
| the <literal>children</literal> built-in also can be used as hash and |
| maybe as string, as it is described in the <link linkend="xgui">part |
| about XML processing</link>.</para> |
| |
| <section xml:id="ref_builtin_ancestors"> |
| <title>ancestors</title> |
| |
| <indexterm> |
| <primary>ancestors built-in</primary> |
| </indexterm> |
| |
| <para>A sequence that contains all the node's ancestors, starting |
| with the immediate parent and ending with the root node. The result |
| of this built-in is also a method, by which you can filter the |
| result with the <link |
| linkend="gloss.fullQualifiedName">full-qualified name</link> of the |
| node. For example as <literal>node?ancestors("section")</literal> to |
| get the sequence of all ancestors with name |
| <literal>section</literal>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_children"> |
| <title>children</title> |
| |
| <indexterm> |
| <primary>children built-in</primary> |
| </indexterm> |
| |
| <para>A sequence that contains all of this node's child nodes (i.e. |
| immediate descendant nodes).</para> |
| |
| <para>XML: This is almost the same as special hash key |
| <literal>*</literal>, except that it returns all nodes, not only |
| elements. So the possible children are element nodes, text nodes, |
| comment nodes, processing instruction nodes, etc. but |
| <emphasis>not</emphasis> attribute nodes. Attribute nodes are |
| excluded from the sequence.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_node_name"> |
| <title>node_name</title> |
| |
| <indexterm> |
| <primary>node_name built-in</primary> |
| </indexterm> |
| |
| <para>Returns the string that is used to determine what user-defined |
| directive to invoke to handle this node when it is |
| <quote>visited</quote>. See: the <link |
| linkend="ref.directive.visit">visit</link> and <link |
| linkend="ref.directive.recurse">recurse</link> directives.</para> |
| |
| <para>XML: If the node is an element or attribute, then the string |
| will be the local (prefix free) name of the element or attribute. |
| Otherwise the name usually starts with <literal>@</literal> followed |
| by the node type. See <link linkend="misc.xguiTable">this |
| table</link>. Note that this node name is not the same as the node |
| name returned in the DOM API; the goal of FreeMarker node names is |
| to give the name of the used-defined directive that will process the |
| node.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_next_sibling"> |
| <title>next_sibling</title> |
| |
| <indexterm> |
| <primary>next_sibling built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is only available since 2.3.26</para> |
| </note> |
| |
| <para>Returns the following sibling node of the node. (Two nodes in |
| a tree are said to be siblings if they are on the same level and are |
| directly next to each other.) If there's no such node, the |
| expression |
| <literal><replaceable>node</replaceable>?next_sibling??</literal> |
| evaluates to <literal>false</literal>.</para> |
| |
| <para>XML: Note that the value returned by this built-in is also a |
| sequence of length 1 (same as the result of some XPath expressions), |
| however if there's no next sibling, the result is a missing value |
| (null) instead of an empty sequence. Also note that for XML element |
| nodes you can also use |
| <literal><replaceable>node</replaceable>.@@next_sibling_element</literal>, |
| which is practical if you want to ignore the whitespace that |
| separates two apparently sibling elements; see more <link |
| linkend="xgui_imperative_formal">here...</link></para> |
| |
| <note> |
| <para>For custom node implementations this built-in is only |
| supported if that implements the |
| <literal>freemarker.template.TemplateNodeModelEx</literal> |
| interface.</para> |
| </note> |
| </section> |
| |
| <section xml:id="ref_builtin_node_namespace"> |
| <title>node_namespace</title> |
| |
| <indexterm> |
| <primary>node_namespace built-in</primary> |
| </indexterm> |
| |
| <para>Returns the namespace string of the node. FreeMarker does not |
| define the exact meaning of node namespace; it depends on what your |
| node variables are modeling. It's possible that a node doesn't have |
| any node namespace defined. In this case, the built-in should |
| evaluate to undefined variable (i.e. |
| <literal>node?<replaceable>node_namespace</replaceable>??</literal> |
| is <literal>false</literal>), so you can't use the returned |
| value.</para> |
| |
| <para>XML: In the case of XML, it's the XML namespace URI (such as |
| <literal>"http://www.w3.org/1999/xhtml"</literal>). If an element or |
| attribute node does not use XML namespace, then this built-in |
| evaluates to an empty string. For other XML nodes this built-in |
| always return undefined variable.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_node_type"> |
| <title>node_type</title> |
| |
| <indexterm> |
| <primary>node_type built-in</primary> |
| </indexterm> |
| |
| <para>A string that describes the type of the node. FreeMarker does |
| not define the exact meaning of node type; it depends on what your |
| variables are modeling. It's possible that a node doesn't support |
| node type at all. In this case, the built-in evaluates to an |
| undefined value, so you can't use the returned value. (You can still |
| check if a node supports the type property with |
| <literal><replaceable>node</replaceable>?node_type??</literal>.)</para> |
| |
| <para>XML: The possible values are: <literal>"attribute"</literal>, |
| <literal>"text"</literal>, <literal>"comment"</literal>, |
| <literal>"document_fragment"</literal>, |
| <literal>"document"</literal>, <literal>"document_type"</literal>, |
| <literal>"element"</literal>, <literal>"entity"</literal>, |
| <literal>"entity_reference"</literal>, |
| <literal>"notation"</literal>, <literal>"pi"</literal>. Note that a |
| there is no <literal>"cdata"</literal> type, because CDATA is |
| considered as plain text node.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_parent"> |
| <title>parent</title> |
| |
| <indexterm> |
| <primary>parent built-in</primary> |
| </indexterm> |
| |
| <para>Returns the node that is this node's immediate parent in the |
| node tree. The root node has no parent node, so for the root node, |
| the expression |
| <literal><replaceable>node</replaceable>?parent??</literal> |
| evaluates to <literal>false</literal>.</para> |
| |
| <para>XML: Note that the value returned by this built-in is also a |
| sequence (same as the result of XPath expression |
| <literal>..</literal>, when you write |
| <literal>someNode[".."]</literal>), however if there's no parent, |
| the result is a missing value (null) instead of an empty sequence. |
| Also note that for attribute nodes, it returns the element the |
| attribute belongs to, despite that attribute nodes are not counted |
| as children of the element.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_previous_sibling"> |
| <title>previous_sibling</title> |
| |
| <indexterm> |
| <primary>previous_sibling built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is only available since 2.3.26</para> |
| </note> |
| |
| <para>Returns the previous sibling node of the node. Apart from the |
| direction, this is the same as <literal>next_sibling</literal>, so |
| see more details <link |
| linkend="ref_builtin_next_sibling">there...</link></para> |
| |
| <note> |
| <para>For custom node implementations this built-in is only |
| supported if that implements the |
| <literal>freemarker.template.TemplateNodeModelEx</literal> |
| interface.</para> |
| </note> |
| </section> |
| |
| <section xml:id="ref_builtin_root"> |
| <title>root</title> |
| |
| <indexterm> |
| <primary>root built-in</primary> |
| </indexterm> |
| |
| <para>The node that is the root of the tree of nodes to which this |
| node belongs.</para> |
| |
| <para>XML: According to W3C, the root of an XML document is not the |
| topmost element node, but the document itself, which is the parent |
| of the topmost element. For example, if you want to get the topmost |
| <emphasis>element</emphasis> of the XML (the so called |
| <quote>document element</quote>; do not mix it with the |
| <quote>document</quote>), which is called <literal>foo</literal>, |
| then you have to write <literal>someNode?root.foo</literal>. If you |
| write just <literal>someNode?root</literal>, then you get the |
| document itself, and not the document element.</para> |
| </section> |
| </section> |
| |
| <section xml:id="ref_builtins_loop_var"> |
| <title>Loop variable built-ins</title> |
| |
| <note> |
| <para>Loop variable built-ins only exists since FreeMarker |
| 2.3.23.</para> |
| </note> |
| |
| <para>These built-ins you can only use with the loop variable of the |
| <link linkend="ref_directive_list"><literal>list</literal> and |
| <literal>items</literal> directives</link> (and of the deprecated |
| <literal>foreach</literal> directive). Some explanation of that |
| follows (<literal><replaceable>loopVar</replaceable>?index</literal> |
| returns the 0-based index in the listable value we iterate |
| through):</para> |
| |
| <programlisting role="template"><#-- Note: x is a loop variable --> |
| <#list ['a', 'b', 'c'] as x> |
| ${x?index} |
| </#list></programlisting> |
| |
| <programlisting role="output">0 |
| 1 |
| 2</programlisting> |
| |
| <para>When the <literal>list</literal> directive doesn't specify the |
| loop variable, these built-ins are used with the loop variable of the |
| <literal>items</literal> directive:</para> |
| |
| <programlisting role="template"><#list ['a', 'b', 'c']> |
| <ul> |
| <#items as x> |
| <li>${x?index}</li> |
| </#items> |
| </ul> |
| </#list></programlisting> |
| |
| <para>Loop variable built-ins only use the <emphasis>name</emphasis> |
| of loop variable, so that they can identify the related ongoing |
| iteration. They don't read the <emphasis>value</emphasis> of the loop |
| variable. Hence, this is a parsing error:</para> |
| |
| <programlisting role="template"><#list ['a', 'b', 'c'] as x> |
| <#assign y = x> |
| ${y?index} <#-- ERROR: y isn't a loop variable --> |
| </#list></programlisting> |
| |
| <section xml:id="ref_builtin_counter"> |
| <title>counter</title> |
| |
| <indexterm> |
| <primary>counter built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.23.</para> |
| </note> |
| |
| <para>Returns the 1-based index where the iteration (which is |
| identified by the loop variable name) currently stands.</para> |
| |
| <programlisting role="template"><#list ['a', 'b', 'c'] as i> |
| ${i?counter}: ${i} |
| </#list></programlisting> |
| |
| <programlisting role="output"> 1: a |
| 2: b |
| 3: c</programlisting> |
| |
| <note> |
| <para>For the 0-based index, use the <link |
| linkend="ref_builtin_index"><literal>index</literal> |
| built-in</link>.</para> |
| </note> |
| </section> |
| |
| <section xml:id="ref_builtin_has_next"> |
| <title>has_next</title> |
| |
| <indexterm> |
| <primary>has_next built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.23.</para> |
| </note> |
| |
| <para>Tells if the item where the iteration (which is identified by |
| the loop variable name) currently stands is not the last |
| item.</para> |
| |
| <programlisting role="template"><#list ['a', 'b', 'c'] as i>${i?has_next?c} </#list></programlisting> |
| |
| <programlisting role="output">true true false </programlisting> |
| |
| <note> |
| <para>For separating items with commas and such, use |
| <literal><#sep><replaceable>separator</replaceable></#sep></literal> |
| instead of <literal><#if |
| <replaceable>var</replaceable>?has_next><replaceable>separator</replaceable></#if></literal>, |
| as it's more readable. (Furthermore the |
| <literal></#sep></literal> can be often omitted, like in |
| <literal><#list <replaceable>...</replaceable> as |
| <replaceable>var</replaceable>><replaceable>...</replaceable>${<replaceable>var</replaceable>}<replaceable>...</replaceable><#sep><replaceable>separator</replaceable></#list></literal>)</para> |
| </note> |
| |
| <note> |
| <para>If you need the inverse of this built-in, use |
| <literal><replaceable>var</replaceable>?is_last</literal> instead |
| of <literal>!<replaceable>var</replaceable>?has_next</literal>, |
| because it's more readable.</para> |
| </note> |
| </section> |
| |
| <section xml:id="ref_builtin_index"> |
| <title>index</title> |
| |
| <indexterm> |
| <primary>index built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.23.</para> |
| </note> |
| |
| <para>Returns the 0-based index where the iteration (which is |
| identified by the loop variable name) currently stands.</para> |
| |
| <programlisting role="template"><#list ['a', 'b', 'c'] as i> |
| ${i?index}: ${i} |
| </#list></programlisting> |
| |
| <programlisting role="output"> 0: a |
| 1: b |
| 2: c</programlisting> |
| |
| <note> |
| <para>For the 1-based index, use the <link |
| linkend="ref_builtin_counter"><literal>counter</literal> |
| built-in</link>.</para> |
| </note> |
| </section> |
| |
| <section xml:id="ref_builtin_is_even_item"> |
| <title>is_even_item</title> |
| |
| <indexterm> |
| <primary>is_even_item built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.23.</para> |
| </note> |
| |
| <para>Tells if the item where the iteration (which is identified by |
| the loop variable name) currently stands has an even 1-based |
| index.</para> |
| |
| <programlisting role="template"><#list ['a', 'b', 'c', 'd'] as i>${i?is_even_item?c} </#list></programlisting> |
| |
| <programlisting role="output">false true false true</programlisting> |
| |
| <note> |
| <para>To make tables with alternating row colors and such, use |
| <link |
| linkend="ref_builtin_item_parity"><literal><replaceable>var</replaceable>?item_parity</literal></link> |
| or <link |
| linkend="ref_builtin_item_cycle"><literal><replaceable>var</replaceable>?item_cycle(...)</literal></link> |
| instead.</para> |
| </note> |
| </section> |
| |
| <section xml:id="ref_builtin_is_first"> |
| <title>is_first</title> |
| |
| <indexterm> |
| <primary>is_first built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.23.</para> |
| </note> |
| |
| <para>Tells if the item where the iteration (which is identified by |
| the loop variable name) currently stands is the first item.</para> |
| |
| <programlisting role="template"><#list ['a', 'b', 'c'] as i>${i?is_first?c} </#list></programlisting> |
| |
| <programlisting role="output">true false false </programlisting> |
| </section> |
| |
| <section xml:id="ref_builtin_is_last"> |
| <title>is_last</title> |
| |
| <indexterm> |
| <primary>is_last built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.23.</para> |
| </note> |
| |
| <para>Tells if the item where the iteration (which is identified by |
| the loop variable name) currently stands is the last item.</para> |
| |
| <programlisting role="template"><#list ['a', 'b', 'c'] as i>${i?is_last?c} </#list></programlisting> |
| |
| <programlisting role="output">false false true</programlisting> |
| |
| <note> |
| <para>If you need the inverse of this built-in, use |
| <literal><replaceable>var</replaceable>?has_next</literal> instead |
| of <literal>!<replaceable>var</replaceable>?is_last</literal>, |
| because it's more readable.</para> |
| </note> |
| |
| <note> |
| <para>For separating items with commas and such, use |
| <literal><#sep><replaceable>separator</replaceable></#sep></literal> |
| instead of <literal><#if |
| <replaceable>var</replaceable>?has_next><replaceable>separator</replaceable></#if></literal>, |
| as it's more readable. (Furthermore the |
| <literal></#sep></literal> can be often omitted, like in |
| <literal><#list <replaceable>...</replaceable> as |
| <replaceable>var</replaceable>><replaceable>...</replaceable>${<replaceable>var</replaceable>}<replaceable>...</replaceable><#sep><replaceable>separator</replaceable></#list></literal>)</para> |
| </note> |
| </section> |
| |
| <section xml:id="ref_builtin_is_odd_item"> |
| <title>is_odd_item</title> |
| |
| <indexterm> |
| <primary>is_odd_item built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.23.</para> |
| </note> |
| |
| <para>Tells if the item where the iteration (which is identified by |
| the loop variable name) currently stands has an odd 1-based |
| index.</para> |
| |
| <programlisting role="template"><#list ['a', 'b', 'c', 'd'] as i>${i?is_odd_item?c} </#list></programlisting> |
| |
| <programlisting role="output">true false true false </programlisting> |
| |
| <note> |
| <para>To make tables with alternating row colors and such, use |
| <link |
| linkend="ref_builtin_item_parity"><literal><replaceable>var</replaceable>?item_parity</literal></link> |
| or <link |
| linkend="ref_builtin_item_cycle"><literal><replaceable>var</replaceable>?item_cycle(...)</literal></link> |
| instead.</para> |
| </note> |
| </section> |
| |
| <section xml:id="ref_builtin_item_cycle"> |
| <title>item_cycle</title> |
| |
| <indexterm> |
| <primary>item_cycle built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.23.</para> |
| </note> |
| |
| <para>This is a more generic version of the <link |
| linkend="ref_builtin_item_parity"><literal>item_parity</literal> |
| built-in</link>, where you can specify what value to use instead of |
| <literal>"odd"</literal> and <literal>"even"</literal>. It also |
| allows more than 2 values that it will cycle through.</para> |
| |
| <programlisting role="template"><#list ['a', 'b', 'c', 'd', 'e', 'f', 'g'] as i> |
| <tr class="${i?item_cycle('row1', 'row2', 'row3')}">${i}</tr> |
| </#list></programlisting> |
| |
| <programlisting role="output"> <tr class="row1">a</tr> |
| <tr class="row2">b</tr> |
| <tr class="row3">c</tr> |
| <tr class="row1">d</tr> |
| <tr class="row2">e</tr> |
| <tr class="row3">f</tr> |
| <tr class="row1">g</tr></programlisting> |
| |
| <para>Some details:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The number of arguments must be at least 1, and has no |
| upper limit.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The type of the arguments can be anything, they doesn't |
| have to be strings.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <note> |
| <para>Use the <link |
| linkend="ref_builtin_item_parity"><literal>item_parity</literal> |
| built-in</link> instead if the values you need are |
| <literal>"odd"</literal> and <literal>"even"</literal>.</para> |
| </note> |
| </section> |
| |
| <section xml:id="ref_builtin_item_parity"> |
| <title>item_parity</title> |
| |
| <indexterm> |
| <primary>item_parity built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.23.</para> |
| </note> |
| |
| <para>Returns <literal>"odd"</literal> or <literal>"even"</literal> |
| string value, depending on the parity of the 1-based index where the |
| iteration (which is identified by the loop variable name) currently |
| stands. This is commonly used for alternating color for table |
| rows:</para> |
| |
| <programlisting role="template"><#list ['a', 'b', 'c', 'd'] as i> |
| <tr class="${i?item_parity}Row">${i}</tr> |
| </#list></programlisting> |
| |
| <programlisting role="output"> <tr class="oddRow">a</tr> |
| <tr class="evenRow">b</tr> |
| <tr class="oddRow">c</tr> |
| <tr class="evenRow">d</tr></programlisting> |
| |
| <note> |
| <para>Use the <link |
| linkend="ref_builtin_item_parity"><literal>item_parity_cap</literal> |
| built-in</link> for capitalized <literal>"Odd"</literal> and |
| <literal>"Even"</literal>. Use the <link |
| linkend="ref_builtin_item_cycle"><literal>item_cycle</literal> |
| built-in</link> to specify custom values, or more then two |
| values.</para> |
| </note> |
| </section> |
| |
| <section xml:id="ref_builtin_item_parity_cap"> |
| <title>item_parity_cap</title> |
| |
| <indexterm> |
| <primary>item_parity_cap built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.23.</para> |
| </note> |
| |
| <para>Returns <literal>"Odd"</literal> or <literal>"Even"</literal> |
| string value (note the capitalization), depending on the parity of |
| the 1-based index where the iteration (which is identified by the |
| loop variable name) currently stands.</para> |
| |
| <programlisting role="template"><#list ['a', 'b', 'c', 'd'] as i> |
| <tr class="row${i?item_parity_cap}">${i}</tr> |
| </#list></programlisting> |
| |
| <programlisting role="output"> <tr class="rowOdd">a</tr> |
| <tr class="rowEven">b</tr> |
| <tr class="rowOdd">c</tr> |
| <tr class="rowEven">d</tr></programlisting> |
| |
| <note> |
| <para>Use the <link |
| linkend="ref_builtin_item_parity"><literal>item_parity</literal> |
| built-in</link> for lower case <literal>"odd"</literal> and |
| <literal>"even"</literal>.</para> |
| </note> |
| </section> |
| </section> |
| |
| <section xml:id="ref_builtins_type_independent"> |
| <title>Type independent built-ins</title> |
| |
| <para>These are the built-ins that don't care (much) about the type of |
| their left hand argument.</para> |
| |
| <section xml:id="ref_builtin_switch"> |
| <title>switch</title> |
| |
| <indexterm> |
| <primary>switch built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>switch expression</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in exists since FreeMarker 2.3.23.</para> |
| </note> |
| |
| <para>This is basically the in-line (expression) version of the |
| <link |
| linkend="ref_directive_switch"><literal>switch</literal>-<literal>case</literal>-<literal>default</literal> |
| directives</link>. Its generic format is like |
| <literal><replaceable>matchedValue</replaceable>?switch(<replaceable>case1</replaceable>, |
| <replaceable>result1</replaceable>, |
| <replaceable>case2</replaceable>, |
| <replaceable>result2</replaceable>, ... |
| <replaceable>caseN</replaceable>, |
| <replaceable>resultN</replaceable>, |
| <replaceable>defaultResult</replaceable>)</literal>, where |
| <literal><replaceable>defaultResult</replaceable></literal> can be |
| omitted. Example:</para> |
| |
| <programlisting role="template"><#list ['r', 'w', 'x', 's'] as flag> |
| ${flag<emphasis>?switch('r', 'readable', 'w' 'writable', 'x', 'executable', 'unknown flag: ' + flag)</emphasis>} |
| </#list></programlisting> |
| |
| <programlisting role="output"> readable |
| writable |
| executable |
| unknown flag: s |
| </programlisting> |
| |
| <para>That is, <literal>switch</literal> will find the first |
| <literal><replaceable>case</replaceable></literal> parameter (left |
| to right) whose value equals to |
| <literal><replaceable>matchedValue</replaceable></literal>, then it |
| returns the value of the |
| <literal><replaceable>result</replaceable></literal> parameter |
| that's directly after that |
| <literal><replaceable>case</replaceable></literal> parameter. If it |
| doesn't find an equal |
| <literal><replaceable>case</replaceable></literal>, then it will |
| return the value of the |
| <literal><replaceable>defaultResult</replaceable></literal>, or if |
| there's no |
| <literal><replaceable>defaultResult</replaceable></literal> |
| parameter (i.e., if the number of parameters is even) then it stops |
| the template processing with error.</para> |
| |
| <para>Further details:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The comparison of |
| <literal><replaceable>matchedValue</replaceable></literal> to |
| the <literal><replaceable>case</replaceable></literal> parameter |
| value behaves exactly like <link |
| linkend="dgui_template_exp_comparison">the <literal>==</literal> |
| operator</link>. Hence it only compares scalars and only |
| same-type values. Thus, something like <literal>x?switch(1, |
| "r1", "c2", "r2")</literal> doesn't make sense, as if |
| <literal>x</literal> is non-numerical then the first case will |
| cause error, and if <literal>x</literal> is numerical then the |
| second case will cause error (unless <literal>x</literal> is |
| <literal>1</literal>, as then we won't do further comparisons |
| after the first one).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Unlike with normal method calls, only those parameters of |
| <literal>switch(<replaceable>...</replaceable>)</literal> are |
| evaluated that are indeed needed. For example, in |
| <literal>two()?switch(c1(), r1(), c2(), r2(), c3(), |
| r3())</literal>, if <literal>two()</literal> returns |
| <literal>2</literal>, <literal>c1()</literal> returns |
| <literal>1</literal>, and <literal>c2()</literal> returns |
| <literal>2</literal>, then only the following functions will be |
| called, and in this order: <literal>m()</literal>, |
| <literal>c1()</literal>, <literal>c2()</literal>, |
| <literal>r2()</literal>. (Naturally, arguments that aren't |
| evaluated can refer to missing variables without causing error.) |
| It's guaranteed that the |
| <literal><replaceable>case</replaceable></literal> parameter |
| expressions are evaluated left to right, and only until the |
| first match was found. It's also guaranteed that only the |
| <literal><replaceable>result</replaceable></literal> expression |
| that belongs to the first matching |
| <literal><replaceable>case</replaceable></literal> will be |
| evaluated. It's also guaranteed that the |
| <literal><replaceable>defaultResult</replaceable></literal> |
| expression will only be evaluated if there was no matching |
| <literal><replaceable>case</replaceable></literal> |
| parameter.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal><replaceable>case</replaceable></literal> |
| parameter expressions need not be constant values, they can be |
| arbitrary complex expressions. Of course, the same goes for and |
| the <literal><replaceable>result</replaceable></literal>, |
| <literal><replaceable>defaultResult</replaceable></literal>, and |
| <literal><replaceable>matchedValue</replaceable></literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>There's no restriction regarding the type of the |
| <literal><replaceable>case</replaceable></literal> parameter |
| values, like they can be strings, or numbers, or dates, etc. |
| However, because of how the <literal>==</literal> operator |
| works, it doesn't make sense to use |
| <literal><replaceable>case</replaceable></literal> parameters of |
| different types inside the <replaceable>same</replaceable> |
| <literal>switch</literal> (see earlier why).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Unlike with the <link |
| linkend="ref_directive_switch"><literal>case</literal> |
| directive</link>, there's no fall-through behavior there, that |
| is, there's no need for an equivalent of the |
| <literal>break</literal> directive.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <note> |
| <para>If you need to switch by a boolean value, you should use the |
| <link linkend="ref_builtin_then"><literal>then</literal> |
| built-in</link> instead, like |
| <literal><replaceable>matchedBoolean</replaceable>?then(<replaceable>whenTrue</replaceable>, |
| <replaceable>whenFalse</replaceable>)</literal>.</para> |
| </note> |
| |
| <note> |
| <para>If you need to do arbitrary logical tests instead of simple |
| equality comparisons at the |
| <literal><replaceable>case</replaceable></literal> parameters, you |
| can do something like this (here we tests for ranges): |
| <literal>true?switch(priority <= 1, "low", priority == 2, |
| "medium", priority >= 3, "high")</literal></para> |
| </note> |
| </section> |
| </section> |
| |
| <section xml:id="ref_builtins_expert"> |
| <title>Seldom used and expert built-ins</title> |
| |
| <para>These are the built-ins that normally you should not use, but in |
| exceptional situations (debugging, advanced macros) they can be |
| useful. If you need to use these in your normal page templates, you |
| may revisit the data-model so you don't need to use these.</para> |
| |
| <section xml:id="ref_builtin_absolute_template_name"> |
| <title>absolute_template_name</title> |
| |
| <indexterm> |
| <primary>absolute_template_name built-in</primary> |
| </indexterm> |
| |
| <para>Converts a template name to an absolute name, which can be |
| safely passed to <literal><#include |
| <replaceable>name</replaceable>></literal> or |
| <literal><#import <replaceable>name</replaceable> as |
| <replaceable>ns</replaceable>></literal> or |
| <literal>.get_optional_template(<replaceable>name</replaceable>)</literal> |
| and such in <emphasis>another</emphasis> template, as it won't be |
| misinterpreted to be relative to the directory of the template that |
| contains the <literal>include</literal>, <literal>import</literal>, |
| etc. For example, if you are in template |
| <literal>"dir/here.ftl"</literal>, then |
| <literal>"target.ftl"</literal> is converted to |
| <literal>"/dir/target.ftl"</literal> (note the initial |
| <literal>/</literal>). If now you pass this value to a template in |
| <literal>"other-dir/there.ftl"</literal>, where it's passed to the |
| <literal>include</literal> directive, then it won't be |
| misinterpreted as <literal>"other-dir/target.ftl"</literal>, like |
| <literal>"target.ftl"</literal> would have been.</para> |
| |
| <para>Optionally, you can specify a root based name (a name that's |
| either relative to the template root directory, or is absolute) that |
| will be used instead of the name of the current template, like |
| <literal><replaceable>pathToConver</replaceable>?absolute_template_name(<replaceable>otherTemplateName</replaceable>)</literal>.</para> |
| |
| <para>Example of an application (also uses <link |
| linkend="ref_specvar_caller_template_name"><literal>.caller_template_name</literal></link> |
| and <link |
| linkend="ref_specvar_get_optional_template"><literal>.get_optional_template</literal></link>):</para> |
| |
| <programlisting role="template"><#-- |
| <@smileyInclude name /> behaves like <#include name>, but prints a "(:" before the |
| template, or prints "):" instead if the template is missing. |
| |
| Note that just like with #include, if name is relative, it's resolved based on the |
| directory of the caller template, not of the template that defines this macro. As |
| .get_optional_template resolves relative names based on the current template, we |
| had to convert the name to an absolute name based on the caller template before |
| passing it to it. |
| --> |
| <#macro smileyInclude name> |
| <#local t = .get_optional_template( |
| name<emphasis>?absolute_template_name</emphasis>(.caller_template_name))> |
| <#if t.exists> |
| (: |
| <@t.include /> |
| <#else> |
| ): |
| </#if> |
| </#macro></programlisting> |
| </section> |
| |
| <section xml:id="ref_buitin_api_and_has_api"> |
| <title>api, has_api</title> |
| |
| <indexterm> |
| <primary>api built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>has_api built-in</primary> |
| </indexterm> |
| |
| <note> |
| <para>These built-ins exists since FreeMarker 2.3.22</para> |
| </note> |
| |
| <para><literal><replaceable>value</replaceable>?api</literal> |
| provides access to the API (usually, the Java API) of |
| <literal><replaceable>value</replaceable></literal>, like |
| <literal><replaceable>value</replaceable>?api.<replaceable>someJavaMethod()</replaceable></literal> |
| or |
| <literal><replaceable>value</replaceable>?api.<replaceable>someBeanProperty</replaceable></literal>, |
| if the value itself supports exposing its API. This meant to be used |
| rarely, when you need to call a Java method of an object, but the |
| by-design simplistic view of the value that FreeMarker exposes to |
| the templates hides that, and there's no equivalent built-in either. |
| For example, when you put a <literal>Map</literal> into the |
| data-model (and you are using the default object wrapper), |
| <literal>myMap.myMethod()</literal> in a template basically |
| translates to <literal>((Method) |
| myMap.get("myMethod")).invoke(...)</literal> in Java, thus you can't |
| call <literal>myMethod</literal>. If, however, you write |
| <literal>myMap?api.myMethod()</literal> instead, that means |
| <literal>myMap.myMethod()</literal> in Java. Similarly, |
| <literal>myMap?api.myProperty</literal> translates to |
| <literal>myMap.getMyProperty()</literal> in Java, instead of to |
| <literal>myMap.get("myProperty")</literal>.</para> |
| |
| <para><emphasis>You should avoid using <literal>api</literal>, and |
| rely on the capabilities of the FTL types and the related built-ins |
| as far as possible.</emphasis> For example, don't use |
| <literal>users?api.size()</literal>, but |
| <literal>users?size</literal>. The variation that uses |
| <literal>?api</literal> is more verbose, slower, more easily breaks |
| when FreeMarker configuration settings are changed, and most |
| importantly, more prone to break as the technical details of the |
| data-model change. For example, if <literal>users</literal> is |
| changed from a <literal>List</literal> to an array, |
| <literal>users?size</literal> will keep working, while |
| <literal>users?api.size()</literal> will break.</para> |
| |
| <para>Avoid calling methods that <emphasis>modify</emphasis> an |
| object (especially <literal>Map</literal>-s and |
| <literal>Collection</literal>-s) or that aren't thread safe from |
| other reasons. Templates usually aren't expected to modify the |
| objects exposed to them, just to display them. Thus the application |
| may passes some objects to multiple (possibly concurrent) template |
| processings.</para> |
| |
| <para>The <literal>api</literal> built-in is not everywhere |
| available, some requirements has to be met:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The <literal>api_builtin_enabled</literal> configuration |
| setting must be set to <literal>true</literal>. Its default is |
| <literal>false</literal> (at least as of 2.3.22) for not |
| lowering the security of existing applications.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The value itself has to support it. We are talking about |
| the value as the template sees it, which is created from the |
| original object (that's coming from the data-model or from a |
| Java method return value) value via <link |
| linkend="pgui_datamodel_objectWrapper">object wrapping</link>. |
| Hence, this depends on the <literal>object_wrapper</literal> |
| FreeMarker configuration setting, and on the class of the |
| wrapped (the original) object:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>When the object wrapper is a |
| <literal>DefaultObjectWrapper</literal> with its |
| <literal>incompatibleImprovements</literal> set to 2.3.22 or |
| higher (<link linkend="topic.defaultObjectWrapperIcI">see |
| how to set it here</link>), FTL values made from |
| <literal>Map</literal>-s and <literal>List</literal>-s |
| support <literal>?api</literal>. (Actually, what matters is |
| that its <literal>useAdaptersForContainer</literal> property |
| is set to <literal>true</literal>, but that's the default |
| with said <literal>incompatibleImprovements</literal>.) |
| Other <literal>java.util.Collections</literal> (such as |
| <literal>Set</literal>-s) only support |
| <literal>?api</literal> if |
| <literal>DefaultObjectWrapper</literal>'s |
| <literal>forceLegacyNonListCollections</literal> property is |
| set to <literal>false</literal> (the default is |
| <literal>true</literal> for better out-of-the-box backward |
| compatibility).</para> |
| </listitem> |
| |
| <listitem> |
| <para>When wrapped with pure |
| <literal>BeansWrapper</literal>, all values support |
| <literal>?api</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Custom <literal>TemplateModel</literal>-s can support |
| <literal>?api</literal> by implementing the |
| <literal>freemarker.template.TemplateModelWithAPISupport</literal> |
| interface.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Using <literal>?api</literal> when it's not allowed in the |
| configuration or when the value doesn't support it will abort |
| template processing with error.</para> |
| |
| <para>Whether a value supports <literal>?api</literal> can be |
| checked like |
| <literal><replaceable>value</replaceable>?has_api</literal>, which |
| returns a boolean value. Note that the result of |
| <literal>?has_api</literal> isn't influenced by the |
| <literal>api_builtin_enabled</literal> setting.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_numType"> |
| <title>byte, double, float, int, long, short</title> |
| |
| <indexterm> |
| <primary>type-casting</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting between types</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>byte built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>double built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>float built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>int built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>long built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>short built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting date to long</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>date to long</primary> |
| </indexterm> |
| |
| <para>Returns a <literal>SimpleNumber</literal> which contains the |
| same value as the original variable, but uses |
| <literal>java.lang.<replaceable>Type</replaceable></literal> for the |
| internal representation of the value. This is useful if a method is |
| overloaded, or if a <literal>TemplateModel</literal> unwrapper has |
| problem with automatically choosing the suitable |
| <literal>java.lang.*</literal> type. Note that since version 2.3.9 |
| the unwrapper has been improved substantially, so you will hardly |
| ever need to use these built-ins to convert between numerical types, |
| except for resolving ambiguity in overloaded method |
| invocation.</para> |
| |
| <para>The <literal>long</literal> built-in can also be used with |
| date, time and date-time values to get the value as |
| <literal>java.util.Date.getTime()</literal> would return. This is |
| useful if you have to call a Java methods that expect a timestamp as |
| a <literal>long</literal>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_eval"> |
| <title>eval</title> |
| |
| <indexterm> |
| <primary>eval</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>evaluate string</primary> |
| </indexterm> |
| |
| <para>This built-in evaluates a string as an FTL |
| <emphasis>expression</emphasis>. For example |
| <literal>"1+2"?eval</literal> returns the number 3. (To render a |
| template that's stored in a string, use the <link |
| linkend="ref_builtin_interpret"><literal>interpret</literal> |
| built-in</link> instead.)</para> |
| |
| <warning> |
| <para>Do not use this to evaluate JSON! For that use the <link |
| linkend="ref_builtin_eval_json"><literal>eval_json</literal> |
| built-in</link> instead. While FTL expression language looks |
| similar to JSON, not all JSON is valid FTL expression. Also, FTL |
| expressions can access variables, and call Java methods on them, |
| so if you <literal>?eval</literal> strings coming from untrusted |
| source, it can become an attack vector.</para> |
| </warning> |
| |
| <para>The evaluated expression sees the same variables (such as |
| locals) that are visible at the place of the invocation of |
| <literal>eval</literal>. That is, it behaves similarly as if in |
| place of <literal><replaceable>s</replaceable>?eval</literal> you |
| had the <emphasis>value of</emphasis> |
| <literal><replaceable>s</replaceable></literal> there. Except, it |
| can't use <link linkend="ref_builtins_loop_var">loop variable |
| built-ins</link> that refer to a loop variable that was created |
| outside <literal><replaceable>s</replaceable></literal>.</para> |
| |
| <para>Regarding the configuration settings that affect the parsing |
| (like syntax) and evaluation the rules are the same as with the |
| <link linkend="ref_builtin_interpret"><literal>interpret</literal> |
| built-in</link>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_eval_json"> |
| <title>eval_json</title> |
| |
| <indexterm> |
| <primary>eval_json</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>evaluate string</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>JSON</primary> |
| </indexterm> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.31.</para> |
| </note> |
| |
| <para>This built-in evaluates a string as a JSON |
| <emphasis>expression</emphasis>, so that you can extract data from |
| inside it. For example, if you receive data in the |
| <literal>dataJson</literal> variable, but it's unfortunately just a |
| flat string that contains <literal>{"name": "foo", "ids": [11, |
| 22]}</literal>, then you can extract data from it like this:</para> |
| |
| <programlisting role="template"><#assign data = dataJson<emphasis>?eval_json</emphasis>> |
| <p>Name: ${data.name} |
| <p>Ids: |
| <ul> |
| <#list data.ids as id> |
| <li>${id} |
| </#list> |
| </ul></programlisting> |
| |
| <para>Ideally, you shouldn't need <literal>eval_json</literal>, |
| since the template should receive data already parsed (to |
| <literal>List</literal>-s, <literal>Map</literal>-s, Java beans, |
| etc.). This built-in is there as a workaround, if you can't improve |
| the data-model.</para> |
| |
| <para>The evaluated JSON expression doesn't have to be a JSON object |
| (key-value pairs), it can be any kind of JSON value, like JSON |
| array, JSON number, etc.</para> |
| |
| <para>The syntax understood by this built-in is a superset of |
| JSON:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Java-style comments are supported |
| (<literal>/*<replaceable>...</replaceable>*/</literal> and |
| <literal>//<replaceable>...</replaceable></literal>)</para> |
| </listitem> |
| |
| <listitem> |
| <para>BOM (byte order mark) and non-breaking space |
| (<quote>nbsp</quote>) are treated as whitespace (in a stricter |
| JSON parser they are errors of occurring around tokens).</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>No other non-JSON extras are implemented, notably, it's |
| impossible to refer to variables (unlike in the <link |
| linkend="ref_builtin_eval"><literal>eval</literal> built-in</link>). |
| This is important for safety, when receiving JSON from untrusted |
| sources.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_has_content"> |
| <title>has_content</title> |
| |
| <indexterm> |
| <primary>has_content built-in</primary> |
| </indexterm> |
| |
| <para>It is <literal>true</literal> if the variable exists (and |
| isn't Java <literal>null</literal>) and is not <quote>empty</quote>, |
| otherwise it is <literal>false</literal>. The meaning of |
| <quote>empty</quote> depends on the concrete case. This follows |
| intuitive common-sense ideas. The following are empty: a string with |
| 0 length, a <link linkend="dgui_misc_autoescaping_movalues">markup |
| output value</link> with 0 length markup, a sequence or hash with no |
| sub variables, a collection which has passed the last element. If |
| the value is not of any of these types, then it counts as non-empty |
| if it's a number or a date or a boolean (e.g. <literal>0</literal> |
| and <literal>false</literal> are not empty), otherwise it counts as |
| empty. Note that when your data-model implements multiple template |
| model interfaces you may get unexpected results. However, when in |
| doubt you can use always use <literal>expr!?size > 0</literal> or |
| <literal>expr!?length > 0</literal> instead of |
| <literal>expr?has_content</literal>.</para> |
| |
| <para>This buit-in is exceptional in that you can use the |
| parentheses trick like with the <link |
| linkend="dgui_template_exp_missing_default">default value |
| operator</link>. That is, you can write both |
| <literal>product.color?has_content</literal> and |
| <literal>(product.color)?has_content</literal>. The first doesn't |
| handle the case when <literal>product</literal> is missing, the last |
| does.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_interpret"> |
| <title>interpret</title> |
| |
| <indexterm> |
| <primary>interpret built-in</primary> |
| </indexterm> |
| |
| <para>This built-in parses a string as an FTL template, and returns |
| an user-defined directive that executes that template, just as if a |
| template with that content were <link |
| linkend="ref_directive_include"><literal>include</literal>-d</link> |
| at that point. Example:</para> |
| |
| <programlisting role="template"><#assign x=["a", "b", "c"]> |
| <#assign templateSource = r"<#list x as y>${y}</#list>"> |
| <#-- Note: That r was needed so that the ${y} is not interpreted above --> |
| <#assign inlineTemplate = templateSource?interpret> |
| <@inlineTemplate /></programlisting> |
| |
| <para>The output:</para> |
| |
| <programlisting role="output">abc</programlisting> |
| |
| <para>As you can see, <literal>inlineTemplate</literal> is a |
| user-defined directive that, when executed, runs the template whose |
| content is the value of <literal>templateSource</literal>.</para> |
| |
| <para>The name of the template created by |
| <literal>interpret</literal> is the name of the template that calls |
| <literal>interpret</literal>, plus |
| <literal>"->anonymous_interpreted"</literal>. For example, if the |
| template that calls the built-in is |
| <literal>"foo/bar.ftl"</literal>, then the name of the resulting |
| template is |
| <literal>"foo/bar.ftl->anonymous_interpreted"</literal>. Thus, |
| relative paths inside the interpreted template are relative to this |
| path (i.e., the base directory will be <literal>"foo"</literal>), |
| and errors inside the interpreted template will point to this |
| generated template name.</para> |
| |
| <para>For more helpful error messages, you can override the template |
| name part after the <literal>"->"</literal>. For example, let's |
| say <literal>mailTemplateSource</literal> comes from the |
| <literal>mail_template</literal> database table, and in the case of |
| error, you want the error log to contain the database ID of the |
| failing template:</para> |
| |
| <programlisting role="template"><#assign inlineTemplate = [mailTemplateSource, "mail_templates id=${mailTemplateId}"]?interpret></programlisting> |
| |
| <para>As you can see, <literal>interpret</literal> can be applied on |
| a sequence of two items, in which case the first item is the FTL |
| string to interpret, and the second items is the template name used |
| after the <literal>"->"</literal>.</para> |
| |
| <para>The configuration settings that affect the interpreted |
| template are the same as of the surrounding template, except that |
| parser settings specified in the <link |
| linkend="ref.directive.ftl"><literal>ftl</literal> directive</link> |
| or was established via tag syntax or naming convention |
| auto-detection are instead coming from the |
| <literal>Configuration</literal> object (or naturally, from the |
| <link |
| linkend="pgui_config_templateconfigurations"><literal>TemplateConfiguration</literal></link>, |
| if there's any). Thus the tag syntax, naming convention, whitespace |
| handling, etc. of the interpreted template is independent of that |
| established <emphasis>inside</emphasis> the surrounding template. An |
| important exception from this rule is that the <link |
| linkend="dgui_misc_autoescaping_outputformat">output format</link> |
| and auto-escaping policy is inherited from the lexical context where |
| <literal>interpret</literal> is called from. For example in a |
| template that has <literal><#ftl |
| output_format="XML"></literal> header (or if you are inside a |
| <literal><#output_format |
| "XML"><replaceable>...</replaceable></#output_format></literal> |
| block), <literal>interpret</literal> calls in it will produce |
| directives with XML output format.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_isType"> |
| <title>is_...</title> |
| |
| <indexterm> |
| <primary>is_... built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>type checking</primary> |
| </indexterm> |
| |
| <para>These built-ins check the type of a variable, and returns |
| <literal>true</literal> or <literal>false</literal> depending on the |
| type. The list of |
| <literal>is_<replaceable>...</replaceable></literal> |
| built-ins:</para> |
| |
| <informaltable border="1"> |
| <thead> |
| <tr> |
| <th>Built-in</th> |
| |
| <th>Returns <literal>true</literal> if the value is a ...</th> |
| </tr> |
| </thead> |
| |
| <tbody> |
| <tr> |
| <td><literal>is_string</literal></td> |
| |
| <td>string</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_number</literal></td> |
| |
| <td>number</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_boolean</literal></td> |
| |
| <td>boolean</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_date</literal></td> |
| |
| <td>Don't use it! Same as <literal>is_date_like</literal>, use |
| that instead. Later may changes meaning to |
| <literal>date_only</literal>.</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_date_like</literal></td> |
| |
| <td>date-like, means either date, time or date-time, or |
| date-like with unknown precise type (since FreeMarker |
| 2.3.21)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_date_only</literal></td> |
| |
| <td>date (no time of the day part) (since FreeMarker |
| 2.3.21)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_time</literal></td> |
| |
| <td>time (no year-month-day part) (since FreeMarker |
| 2.3.21)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_datetime</literal></td> |
| |
| <td>date-time (contains both year-month-day and time of the |
| day)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_unknown_date_like</literal></td> |
| |
| <td>date-like where we don't know if it's a date or a time or |
| a date-time</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_method</literal></td> |
| |
| <td>method</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_transform</literal></td> |
| |
| <td>transform</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_macro</literal></td> |
| |
| <td>macro or function (yes, also for function; a historical |
| glitch)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_hash</literal></td> |
| |
| <td>hash (including extended hash)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_hash_ex</literal></td> |
| |
| <td>extended hash (supports <literal>?keys</literal> and |
| <literal>?values</literal>)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_sequence</literal></td> |
| |
| <td>sequence (Historical quirk: Before <link |
| linkend="pgui_config_incompatible_improvements_how_to_set"><literal>incompatible_improvements</literal></link> |
| 2.3.24 it returns <literal>true</literal> for Java methods as |
| they implement the |
| <literal>[<replaceable>index</replaceable>]</literal> |
| operator, however, they fail on |
| <literal>?size</literal>.)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_collection</literal></td> |
| |
| <td>collection (including extended collection)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_collection_ex</literal></td> |
| |
| <td>extended collection (supports |
| <literal>?size</literal>)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_enumerable</literal></td> |
| |
| <td>sequence or collection</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_indexable</literal></td> |
| |
| <td>sequence (Historical quirk: it returns |
| <literal>true</literal> for Java methods as they implement the |
| <literal>[<replaceable>index</replaceable>]</literal> |
| operator.)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_directive</literal></td> |
| |
| <td>Whatever kind of directive (for example a macro, <phrase |
| role="forProgrammers">or |
| <literal>TemplateDirectiveModel</literal>, |
| <literal>TemplateTransformModel</literal>, etc.</phrase>), or |
| function (a historical glitch)</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_node</literal></td> |
| |
| <td>node</td> |
| </tr> |
| |
| <tr> |
| <td><literal>is_markup_output</literal></td> |
| |
| <td>markup output (a value that won't be <link |
| linkend="dgui_misc_autoescaping">auto-escaped</link>)</td> |
| </tr> |
| </tbody> |
| </informaltable> |
| </section> |
| |
| <section xml:id="ref_builtin_markup_string"> |
| <title>markup_string</title> |
| |
| <para><indexterm> |
| <primary>markup_string built-in</primary> |
| </indexterm></para> |
| |
| <note> |
| <para>This built-in is available since FreeMarker 2.3.24.</para> |
| </note> |
| |
| <para>Returns the markup stored inside a <link |
| linkend="dgui_misc_autoescaping_movalues">markup output value</link> |
| as string. This is useful if the value has to be passed to a Java |
| method for a <literal>String</literal> parameter, or if we want to |
| manipulate the markup directly in the template. Note that the |
| resulting string can be converted back to markup output value with |
| <link |
| linkend="ref_builtin_no_esc"><literal>?no_esc</literal></link>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_namespace"> |
| <title>namespace</title> |
| |
| <indexterm> |
| <primary>namespace built-in</primary> |
| </indexterm> |
| |
| <para>This built-in returns the namespace (i.e. the |
| <quote>gate</quote> hash to the namespace) associated with a macro |
| or function variable. You can use it with macros and functions |
| only.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_new"> |
| <title>new</title> |
| |
| <indexterm> |
| <primary>instantiating variable</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>new built-in</primary> |
| </indexterm> |
| |
| <para>This is to create a variable of a certain |
| <literal>TemplateModel</literal> implementation.</para> |
| |
| <para>On the left side of <literal>?</literal> you specify a string, |
| the full-qualified class name of a <literal>TemplateModel</literal> |
| implementation. The result is a method variable that calls the |
| constructor, and returns the new variable.</para> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template"><#-- Creates an user-defined directive be calling the parameterless constructor of the class --> |
| <#assign word_wrapp = "com.acmee.freemarker.WordWrapperDirective"?new()> |
| <#-- Creates an user-defined directive be calling the constructor with one numerical argument --> |
| <#assign word_wrapp_narrow = "com.acmee.freemarker.WordWrapperDirective"?new(40)></programlisting> |
| |
| <para>For more information about how the constructor parameters are |
| unwrapped and how overloaded constructor is chosen, read: <xref |
| linkend="pgui_misc_beanwrapper"/></para> |
| |
| <para>This built-in can be a security concern because the template |
| author can create arbitrary Java objects and then use them, as far |
| as they implement <literal>TemplateModel</literal>. Also the |
| template author can trigger static initialization for classes that |
| don't even implement <literal>TemplateModel</literal>. You can |
| (since 2.3.17) restrict the classes accessible with this built-in |
| using |
| <literal>Configuration.setNewBuiltinClassResolver(TemplateClassResolver)</literal> |
| or the <literal>new_builtin_class_resolver</literal> setting. See |
| the Java API docs for more information. If you are allowing |
| not-so-much-trusted users to upload templates then you should |
| definitely look into this topic.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_numToDate"> |
| <title>number_to_date, number_to_time, number_to_datetime</title> |
| |
| <indexterm> |
| <primary>type-casting</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting between types</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>number_to_date built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>number_to_datetime built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>number_to_time built-in</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>converting long to date</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>long to date</primary> |
| </indexterm> |
| |
| <para>These are used to convert a number (usually a Java |
| <literal>long</literal>) to a date, time or date-time, respectively. |
| This does them same as <literal>new java.util.Date(long)</literal> |
| in Java, that is, the number is interpreted as the milliseconds |
| passed since the epoch. The number can be anything and of any type |
| as far as its value fits into a <literal>long</literal>. If the |
| number isn't a whole number, it will be rounded to whole with |
| half-up rule.</para> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template">${1305575275540?number_to_datetime} |
| ${1305575275540?number_to_date} |
| ${1305575275540?number_to_time}</programlisting> |
| |
| <para>The output will be something like this (depending on the |
| current locale and time zone):</para> |
| |
| <programlisting role="output">May 16, 2011 3:47:55 PM |
| May 16, 2011 |
| 3:47:55 PM</programlisting> |
| </section> |
| |
| <section xml:id="ref_builtin_sequence"> |
| <title>sequence</title> |
| |
| <indexterm> |
| <primary>seq_sequence built-in</primary> |
| </indexterm> |
| |
| <para>This built-in is used to convert a listable value (one that |
| you can iterate through with the <link |
| linkend="ref.directive.list"><literal>list</literal> |
| directive</link>) to a more capable <link |
| linkend="dgui_datamodel_container">sequence</link> value. Sequences |
| support operations like <literal>xs[index]</literal> and |
| <literal>xs?size</literal>. Also, the resulting value is listable |
| for multiple times, even if the original value was backed by a |
| <literal>java.util.Iterator</literal> (which gives error when you |
| try to list it for the 2nd time). This built-in is typically used to |
| work around data-model problems, in case you can't fix the |
| data-model itself. If you can, always fix the data-model instead |
| (give a <literal>java.util.List</literal> or array to the template |
| instead of a more restricted object, like a |
| non-<literal>List</literal> <literal>java.util.Collection</literal>, |
| or a <literal>java.util.Iterator</literal>).</para> |
| |
| <para>If the value is already a sequence, then this built-in just |
| returns that as is. If the value is not something that the <link |
| linkend="ref.directive.list"><literal>list</literal> |
| directive</link> could list, then template processing will be |
| aborted with error. Otherwise, it usually fetches all the values, |
| and stores them into a sequence. Be careful if you can have a huge |
| number of items, as all of them will be held in memory on the same |
| time. However, in some special cases fetching and/or storing all |
| elements is avoided; see about the <link |
| linkend="ref_builtin_sequence_optimizations">optimizations</link> |
| later.</para> |
| |
| <para>You should convert a value with <literal>sequence</literal> |
| only once. If you need the resulting sequence at multiple places, |
| always assign the result to a variable, because if the value you |
| convert is only listable once, converting it for the second time |
| will result in error or an empty sequence. Also the conversion is |
| somewhat costly for big collections, so it's better to do it only |
| once.</para> |
| |
| <para>Example: Let's say you find that <literal>users</literal> is |
| only listable once (because it's a |
| <literal>java.util.Iterator</literal>), but you need to list it for |
| multiple times in the template, and you can't fix the data-model. |
| Then you could do this:</para> |
| |
| <programlisting role="template"><#-- Collect all the users into a sequence: --> |
| <#assign usersSeq = users?sequence> |
| |
| <#list usersSeq as user>...</#list> |
| Again: |
| <#list usersSeq as user>...</#list> |
| </programlisting> |
| |
| <simplesect xml:id="ref_builtin_sequence_optimizations"> |
| <title>Optimizations</title> |
| |
| <para>Since version 2.3.29, if the result of the |
| <literal>sequence</literal> built-in is directly the input of to |
| the <link |
| linkend="dgui_template_exp_var_sequence"><literal>[<replaceable>index</replaceable>]</literal></link> |
| or <link |
| linkend="dgui_template_exp_seqenceop_slice"><literal>[<replaceable>range</replaceable>]</literal></link> |
| operator, or of <literal>?size</literal>, or of |
| <literal>?first</literal>, or a chain of these operations, then |
| the elements will not be collected into the memory, and only as |
| many elements as strictly necessary will be fetched. For example |
| <literal>anIterator?sequence[1]</literal> will just fetch the |
| first 2 items (instead of building a sequence that contains all |
| the elements, and then getting the 2nd element from that). Or, if |
| you write <literal>anIterator?sequence?size</literal>, it will |
| just skip through all elements to count them, but won't store them |
| in memory.</para> |
| |
| <para>The optimizations will only work within the same chain of |
| built-in calls, so for example in <literal><#assign seq = |
| anIterator?sequence>${seq[1]}</literal> the |
| <literal>?sequence</literal> step will collect all the elements |
| into the memory, as <literal>anIterator?sequence</literal> and |
| <literal>seq[1]</literal> are separated. On the other hand, the |
| optimizations will work in |
| <literal>anIterator?sequence[10..]?size</literal>, as both |
| <literal>[<replaceable>range</replaceable>]</literal> and |
| <literal>?size</literal> supports it, and they are directly |
| chained together.</para> |
| </simplesect> |
| </section> |
| |
| <section xml:id="ref_builtin_with_args"> |
| <title>with_args</title> |
| |
| <note> |
| <para>This built-in is available since 2.3.30</para> |
| </note> |
| |
| <para>The goal of this built-in is to add parameters |
| <emphasis>dynamically</emphasis> to the call of a directive (like a |
| macro), function or method. Dynamically means that parameters are |
| added based on a hash value (like <literal>{'a': 1, 'b': 2, 'c': |
| 3}</literal> or a Java <literal>Map</literal>), or a sequence value |
| (like <literal>[1, 2, 3]</literal> or a Java |
| <literal>List</literal>), whose actual content is might only known |
| at the moment when the call happens.</para> |
| |
| <para>For example, we have this macro <literal>m</literal>:</para> |
| |
| <programlisting role="template"><#macro m a b c>a=${a}, b=${b}, c=${c}</#macro></programlisting> |
| |
| <para>Normally you call it like:</para> |
| |
| <programlisting role="template"><@m a=1 b=2 c=3 /></programlisting> |
| |
| <para>Below call does the same, assuming <literal>dynArgs</literal> |
| is the hash <literal>{'a': 1, 'b': 2, 'c': 3}</literal>:</para> |
| |
| <programlisting role="template"><@m?with_args(dynArgs) /></programlisting> |
| |
| <programlisting role="output">a=1, b=1, c=1</programlisting> |
| |
| <para>Below call also does the same, but combines dynamic arguments |
| from <literal>dynArgsAB</literal>, assumed to be <literal>{'a': 1, |
| 'b': 2}</literal>, and argument <literal>c</literal> specified |
| directly:</para> |
| |
| <programlisting role="template"><@m?with_args(dynArgsAB) c=3 /></programlisting> |
| |
| <programlisting role="output">a=1, b=1, c=1</programlisting> |
| |
| <para>To understand why this works, you need to realize that macros, |
| custom directives, functions, and methods in FreeMarker are just |
| values, just like numbers, strings, etc. <literal><#macro m |
| <replaceable>...</replaceable>></literal> just creates a value |
| that's a macro (as opposed to a number, or string, etc.), and then |
| assigns it to variable <literal>m</literal>. Thus, |
| <literal>m</literal> in itself is a valid expression, which |
| evaluates to the macro (but it doesn't <emphasis>call</emphasis> the |
| macro). <literal><@m <replaceable>...</replaceable> |
| /></literal> evaluates the expression <literal>m</literal> (and |
| you can use arbitrarily complex expressions there too, like |
| <literal>m?with_args(<replaceable>...</replaceable>)</literal>), and |
| then <emphasis>calls</emphasis> the resulting macro. |
| <literal>m?with_args(<replaceable>dynArgs</replaceable>)</literal> |
| returns a macro that's very similar to the original macro (that's |
| stored in <literal>m</literal>), but its arguments |
| <emphasis>default</emphasis> to the values specified in |
| <literal><replaceable>dynArgs</replaceable></literal>. So the result |
| of <literal>m?with_args({'b': 22, 'c': 33})</literal> is similar to |
| a modified macro that was created as <literal><#macro |
| <replaceable>unspefiedName</replaceable> a b=22 c=33></literal>. |
| With an example:</para> |
| |
| <programlisting role="template"><#assign mWithDefs = m?with_args({'b': 22, 'c': 33})> |
| <@myWithDefs a=1 c='overridden'/></programlisting> |
| |
| <programlisting role="output">a=1, b=22, c=overridden</programlisting> |
| |
| <para>Above we have created a new macro based on the value of |
| <literal>m</literal>, stored it in variable |
| <literal>mWithDefs</literal>, and then later we called it with |
| <literal><@myWithDefs <replaceable>...</replaceable> |
| /></literal>.</para> |
| |
| <para><literal>with_args</literal> can also be applied on functions |
| (crated with <literal><#function |
| <replaceable>...</replaceable>></literal>) and Java methods |
| (usually get from the data-model, like |
| <literal>myObject.myMethod</literal>). But because functions and |
| methods can only be called with positional arguments (like |
| <literal>f(1, 2, 3)</literal>, and <emphasis>not</emphasis> as |
| <literal>f(a=1, b=2, c=3)</literal>), the argument to |
| <literal>with_args</literal> must be a sequence instead of a hash. |
| Other than that, the same tricks work as with macros:</para> |
| |
| <programlisting role="template"><#function f(a, b, c)><#return "a=${a}, b=${b}, c=${c}"></#function> |
| <#assign dynArgs=[1, 2, 3]> |
| |
| ${f(1, 2, 3)} |
| Same as: |
| ${f?with_args(dynArgs)()} |
| or as: |
| ${f?with_args([1, 2])(3)} |
| or as: |
| ${f?with_args([1])(2, 3)} |
| |
| <#assign fWithOneAsFirstArg = f?with_args([1])> |
| ${fWithOneAsFirstArg(2, 3)} <#-- same as f(1, 2, 3) --></programlisting> |
| |
| <para>Note the double application of |
| <literal>(<replaceable>...</replaceable>)</literal> above, like in |
| <literal>f?with_args(<replaceable>dynArgs</replaceable>)()</literal>. |
| That's because |
| <literal>f?with_args(<replaceable>dynArgs</replaceable>)</literal> |
| just returns a new function (which is just a value), but doesn't |
| call it. So if you want to call that new function immediately (as |
| opposed to assigning it to a variable for example), you need the |
| second <literal>()</literal>.</para> |
| |
| <para>Because macro calls support both named and positional |
| arguments, the <literal>with_args</literal> argument can be a |
| sequence for macros as well (though using a hash is usually a better |
| practice):</para> |
| |
| <programlisting role="template"><#macro m a b c>a=${a}, b=${b}, c=${c}</#macro> |
| |
| <#-- Called with named parameters: --> |
| <@m a=1 b=2 c=3 /> |
| Same as: |
| <#-- Called with positional parameters: --> |
| <@m 1 2 3 /> |
| Same as: |
| <@m?with_args([1, 2, 3]) /> |
| Same as: |
| <#-- Sequence with_args with positional c parameter: --> |
| <@m?with_args([1, 2]) 3 /> |
| Same as: |
| <#-- Sequence with_args with named c parameter: --> |
| <@m?with_args([1, 2]) c=3 /></programlisting> |
| |
| <para>To summarize, depending on the type of the value |
| <literal>with_args</literal> is applied on, the type of argument to |
| <literal>with_args</literal> can be:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Function or method: sequence. Note that WRONG |
| <literal>f?with_args(1, 2)</literal> is WRONG, the correct form |
| is <literal>f?with_args([1, 2])</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Macro: hash or sequence</para> |
| </listitem> |
| |
| <listitem> |
| <para>Directive (user defined): hash</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>The return type of <literal>with_args</literal> is the same as |
| the type of value it was applied on, like if it's applied on a |
| method (like <literal>myObj.myMethod?with_args(dynArgs)</literal>), |
| then it returns a method.</para> |
| |
| <para>Note that it's not possible to apply |
| <literal>with_args</literal> on built-in directives, like |
| <literal><#if <replaceable>...</replaceable>></literal>, |
| <literal><#list <replaceable>...</replaceable>></literal>, |
| etc., because they aren't available as values.</para> |
| |
| <para>This built-in is often used together with the <link |
| linkend="specvar.args"><literal>.args</literal> special |
| variable</link>. For example:</para> |
| |
| <programlisting role="template"><#macro m1 a b c> |
| m1 does things with ${a}, ${b}, ${c} |
| </#macro> |
| |
| <#macro m2 a b c> |
| m2 does things with ${a}, ${b}, ${c} |
| Delegate to m1: |
| <@m1?with_args(.args) /> |
| </#macro> |
| |
| <@m2 a=1 b=2 c=3 /></programlisting> |
| |
| <programlisting role="output"> m2 does things with 1, 2, 3 |
| Delegate to m1: |
| m1 does things with 1, 2, 3</programlisting> |
| |
| <para>FreeMarker syntax allows using the name before the |
| <literal>?with_args(<replaceable>...</replaceable>)</literal> in the |
| end-tag, just as if the |
| <literal>?with_args(<replaceable>...</replaceable>)</literal> wasn't |
| there:</para> |
| |
| <programlisting role="template"><@myMacro?with_args({'a': 1})>...</<emphasis>@myMacro</emphasis>></programlisting> |
| |
| <para>Note that as far as the order of arguments is concerned, |
| arguments coming from |
| <literal>with_args(<replaceable>...</replaceable>)</literal> are |
| added before the arguments specified in the call to the returned |
| directive/function/method. In some use cases it's more desirable to |
| add them at the end instead, in which case use the <link |
| linkend="ref_builtin_with_args_last"><literal>with_args_last</literal> |
| built-in</link>.</para> |
| </section> |
| |
| <section xml:id="ref_builtin_with_args_last"> |
| <title>with_args_last</title> |
| |
| <note> |
| <para>This built-in is available since 2.3.30</para> |
| </note> |
| |
| <para>Same as <link |
| linkend="ref_builtin_with_args"><literal>with_args</literal></link>, |
| but if the order of the arguments in resulting final argument list |
| may differs (but not the values in it). This only matters if you |
| pass parameters by position (typically, when calling functions or |
| methods), or when there's catch-all argument.</para> |
| |
| <para>A typical example with positional arguments is when you want |
| to add the dynamic argument to the end of the parameter list:</para> |
| |
| <programlisting role="template"><#function f a b c d> |
| <#return "a=${a}, b=${b}, c=${c}, d=${d}"> |
| </#function> |
| |
| <#assign dynamicArgs=[3, 4]> |
| |
| with_args: |
| ${f?with_args(dynamicArgs)(1, 2)} |
| |
| with_args_last: |
| ${f?with_args_last(dynamicArgs)(1, 2)}</programlisting> |
| |
| <programlisting role="output">with_args: |
| a=3, b=4, c=1, d=2 |
| |
| with_args_last: |
| a=1, b=2, c=3, d=4</programlisting> |
| |
| <para>In the case of name arguments, while the primary mean of |
| identifying an argument is the its name, catch-all arguments |
| (<literal>others...</literal> below) still have an order:</para> |
| |
| <programlisting role="template"><#macro m a b others...> |
| a=${a} |
| b=${b} |
| others: |
| <#list others as k, v> |
| ${k} = ${v} |
| </#list> |
| </#macro> |
| |
| <#assign dynamicArgs={'e': 5, 'f': 6}> |
| |
| with_args: |
| <@m?with_args(dynamicArgs) a=1 b=2 c=3 d=4 /> |
| |
| with_args_last: |
| <@m?with_args_last(dynamicArgs) a=1 b=2 c=3 d=4 /></programlisting> |
| |
| <programlisting role="output">with_args: |
| a=1 |
| b=2 |
| others: |
| e = 5 |
| f = 6 |
| c = 3 |
| d = 4 |
| |
| with_args_last: |
| a=1 |
| b=2 |
| others: |
| c = 3 |
| d = 4 |
| e = 5 |
| f = 6</programlisting> |
| |
| <para>If you specify a named parameter that are not catch-all, so |
| they are declared in the <literal>macro</literal> tag (as |
| <literal>a</literal> and <literal>b</literal> below), then |
| <literal>with_args</literal> and <literal>with_args_last</literal> |
| are no different, since the argument order is specified by the macro |
| definition, not the macro call:</para> |
| |
| <programlisting role="template"><#macro m a=0 b=0> |
| <#-- We use .args to demonstrate the ordering of a and b: --> |
| <#list .args as k, v> |
| ${k} = ${v} |
| </#list> |
| </#macro> |
| |
| <#assign dynamicArgs={'b': 1}> |
| |
| with_args: |
| <@m?with_args(dynamicArgs) a=1 /> |
| |
| with_args_last: |
| <@m?with_args_last(dynamicArgs) a=1 /></programlisting> |
| |
| <programlisting role="output">with_args: |
| a = 1 |
| b = 1 |
| |
| with_args_last: |
| a = 1 |
| b = 1</programlisting> |
| |
| <para>If both the macro or directive call, and the |
| <literal>with_args_last</literal> argument specifies named catch-all |
| argument with the same name (like <literal>b</literal> below), then |
| the placement of those parameters is decide by the macro/directive |
| call:</para> |
| |
| <programlisting role="template"><#macro m others...> |
| <#list others as k, v> |
| ${k} = ${v} |
| </#list> |
| </#macro> |
| |
| <#assign dynamicArgs={'b': 0, 'd': 4}> |
| |
| with_args: |
| <@m?with_args(dynamicArgs) a=1 b=2 c=3 /> |
| |
| with_args_last: |
| <@m?with_args_last(dynamicArgs) a=1 b=2 c=3 /></programlisting> |
| |
| <programlisting role="output">with_args: |
| <emphasis> b = 2 |
| d = 4 |
| </emphasis> a = 1 |
| c = 3 |
| |
| with_args_last: |
| a = 1 |
| <emphasis> b = 2 |
| </emphasis> c = 3 |
| <emphasis> d = 4</emphasis></programlisting> |
| </section> |
| </section> |
| </chapter> |
| |
| <chapter xml:id="ref_directives"> |
| <title>Directive Reference</title> |
| |
| <indexterm> |
| <primary>directive</primary> |
| </indexterm> |
| |
| <section xml:id="ref_directive_alphaidx"> |
| <title>Alphabetical index</title> |
| |
| <note> |
| <para>As of FreeMarker 2.3.23, you can use camel case instead of |
| all-lower-case for directive names, like <literal>noParse</literal> |
| instead of <literal>noparse</literal>. But know that then within the |
| same template, FreeMarker will enforce the usage of camel case for |
| all identifiers that are part of the template language (user defined |
| names are not affected).</para> |
| </note> |
| |
| <indexterm> |
| <primary>directive</primary> |
| </indexterm> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><link linkend="ref.directive.assign">assign</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.attempt">attempt</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_directive_autoesc">autoesc</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>break: <link linkend="ref.directive.switch.break">in |
| switch</link>, <link linkend="ref.directive.list.break">in |
| list</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.case">case</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref.directive.compress">compress</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref.directive.list.continue">continue</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.default">default</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>else: <link linkend="ref.directive.else">in if</link>, <link |
| linkend="ref.directive.list.else">in list</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.elseif">elseif</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.escape">escape</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref.directive.fallback">fallback</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref.directive.function">function</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.flush">flush</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.ftl">ftl</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.global">global</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.if">if</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.import">import</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.include">include</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.items">items</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.list">list</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.local">local</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.lt">lt</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.macro">macro</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.nested">nested</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_directive_noautoesc">noautoesc</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref.directive.noescape">noescape</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_directive_noparse">noparse</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.nt">nt</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_directive_outputformat">outputformat</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.attempt">recover</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.recurse">recurse</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>return: <link linkend="ref.directive.macro.return">in |
| macro</link>, <link linkend="ref.directive.function.return">in |
| function</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.rt">rt</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.sep">sep</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.setting">setting</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.stop">stop</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.switch">switch</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.t">t</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.userDefined">User-defined |
| directive (<@...>)</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.visit">visit</link></para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>If you don't find a directive here that you have seen in a |
| working template, probably you will find it in: <xref |
| linkend="ref_deprecated"/></para> |
| </section> |
| |
| <section xml:id="ref_directive_assign"> |
| <title>assign</title> |
| |
| <anchor xml:id="ref.directive.assign"/> |
| |
| <indexterm> |
| <primary>assign directive</primary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"><literal><#assign <replaceable>name1</replaceable>=<replaceable>value1</replaceable> <replaceable>name2</replaceable>=<replaceable>value2</replaceable> <replaceable>... nameN</replaceable>=<replaceable>valueN</replaceable>></literal> |
| or |
| <literal><#assign <replaceable>same as above...</replaceable> in <replaceable>namespacehash</replaceable>></literal> |
| or |
| <literal><#assign <replaceable>name</replaceable>> |
| <replaceable>capture this</replaceable> |
| </#assign></literal> |
| or |
| <literal><#assign <replaceable>name</replaceable> in <replaceable>namespacehash</replaceable>> |
| <replaceable>capture this</replaceable> |
| </#assign></literal></programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>name</replaceable></literal>: name |
| of the variable. It is not expression. However, it can be |
| written as a string literal, which is useful if the variable |
| name contains reserved characters, for example |
| <literal><#assign "foo-bar" = 1></literal>. Note that this |
| string literal does not expand interpolations (as |
| <literal>"${foo}"</literal>); if you need to assign to a |
| dynamically constructed name, the you have to use <link |
| linkend="faq_assign_to_dynamic_variable_name">a different |
| trick</link>. Note that because the FreeMarker template language |
| assumes that sequences (lists, arrays, etc.) and hashes (maps, |
| beans, etc.) are immutable, you can <emphasis>not</emphasis> |
| write something like <literal><#assign myObj.someProperty = |
| 'will NOT work'></literal> or <literal><#assign myList[0] |
| = 'will NOT work'></literal>. However, adding sequences or |
| hashes with the <literal>+</literal> operator to form another |
| value is supported; see in the <link |
| linkend="exp_cheatsheet">chapter about expressions</link>, and |
| please note the performance consequences.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>=</literal>: Assignment operator. It can also be |
| one of the assignment shorthand operators (since FreeMarker |
| 2.3.23): <literal>++</literal>, <literal>--</literal>, |
| <literal>+=</literal>, <literal>-=</literal>, |
| <literal>*=</literal>, <literal>/=</literal> or |
| <literal>%=</literal>. Like <literal><#assign |
| x++></literal> is similar to <literal><#assign x = x + |
| 1></literal>, and <literal><#assign x += 2></literal> |
| is the same as <literal><#assign x = x + 2></literal>. |
| Note that <literal>++</literal> always means arithmetical |
| addition (an so it will fail on non-numbers), unlike |
| <literal>+</literal> or <literal>+=</literal> that are |
| overloaded to do string concatenation and such.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>value</replaceable></literal>: the |
| value to store. Expression.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>namespacehash</replaceable></literal>: |
| a hash that was created for a <link |
| linkend="dgui_misc_namespace">namespace</link> (by <link |
| linkend="ref.directive.import"><literal>import</literal></link>). |
| Expression. If not specified, it defaults to the namespace that |
| belongs to the containing template.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>With this you can create a new variable, or replace an |
| existing variable. Note that only top-level variables can be |
| created/replaced (i.e. you can't create/replace |
| <literal>some_hash.subvar</literal>, but |
| <literal>some_hash</literal>).</para> |
| |
| <para>For more information about variables, read this: <xref |
| linkend="dgui_misc_var"/></para> |
| |
| <note> |
| <para>A frequent mistake is trying to use |
| <literal>assign</literal> to change a local variable like: |
| <literal><#macro m><#local x = 1>${x}<#assign x = |
| 2>${x}</#macro></literal>. This prints |
| <literal>11</literal>, not <literal>12</literal>, because |
| <literal>assign</literal> creates/replaces the |
| <literal>x</literal> of the namespace that the template belongs |
| to, and doesn't change the <literal>x</literal> local variable. |
| Local variables should be always set with the <link |
| linkend="ref.directive.local"><literal>local</literal> |
| directive</link>, not just for the fist time.</para> |
| </note> |
| |
| <para>Example: variable <literal>seq</literal> will store a |
| sequence:</para> |
| |
| <programlisting role="template"><#assign seq = ["foo", "bar", "baz"]></programlisting> |
| |
| <para>Example: Increments the numerical value stored in variable |
| <literal>x</literal>:</para> |
| |
| <programlisting role="template"><#assign x++></programlisting> |
| |
| <para>As a convenience feature, you can do more assignments with one |
| <literal>assign</literal> tag. For example this will do the same as |
| the two previous examples:</para> |
| |
| <programlisting role="template"><#assign |
| seq = ["foo", "bar", "baz"] |
| x++ |
| ></programlisting> |
| |
| <para>If you know what namespaces are: <literal>assign</literal> |
| directive creates variables in a namespace. Normally it creates the |
| variable in the current namespace (i.e. in the namespace associated |
| with the template where the tag is). However, if you use <literal>in |
| <replaceable>namespacehash</replaceable></literal> then you can |
| create/replace a variable of another <link |
| linkend="dgui_misc_namespace">namespace</link> than the current |
| namespace. For example, here you create/replace variable |
| <literal>bgColor</literal> of the namespace used for |
| <literal>/mylib.ftl</literal>:</para> |
| |
| <programlisting role="template"><#import "/mylib.ftl" as my> |
| <#assign bgColor="red" in my></programlisting> |
| |
| <para>An extreme usage of <literal>assign</literal> is when it |
| captures the output generated between its start-tag and end-tag. |
| That is, things that are printed between the tags will not be shown |
| on the page, but will be stored in the variable. For example:</para> |
| |
| <programlisting role="template"><#macro myMacro>foo</#macro> |
| <#assign x> |
| <#list 1..3 as n> |
| ${n} <@myMacro /> |
| </#list> |
| </#assign> |
| Number of words: ${x?word_list?size} |
| ${x}</programlisting> |
| |
| <para>will print:</para> |
| |
| <programlisting role="output">Number of words: 6 |
| 1 foo |
| 2 foo |
| 3 foo |
| </programlisting> |
| |
| <para>Please note that you should not to use this to insert |
| variables into strings:</para> |
| |
| <programlisting role="template"><#assign x>Hello ${user}!</#assign> <#-- BAD PRACTICE! --></programlisting> |
| |
| <para>You should simply write:</para> |
| |
| <programlisting role="template"><#assign x="Hello ${user}!"></programlisting> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_attempt"> |
| <title>attempt, recover</title> |
| |
| <anchor xml:id="ref.directive.attempt"/> |
| |
| <indexterm> |
| <primary>attempt directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>recover directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>error handling</primary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"> |
| <literal><#attempt> |
| <replaceable>attempt block</replaceable> |
| <#recover> |
| <replaceable>recover block</replaceable> |
| </#attempt> |
| </literal> |
| </programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>attempt |
| block</replaceable></literal>: Template block with any content. |
| This will be always executed, but if an error occurs during |
| that, all output from this block is rolled back, and the |
| <literal><replaceable>recover block</replaceable></literal> will |
| be executed.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>recover |
| block</replaceable></literal>: Template block with any content. |
| This will be executed only if there was an error during the |
| execution of the <literal><replaceable>attempt |
| block</replaceable></literal>. You may print an error messages |
| here and such.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>The <literal><replaceable>recover</replaceable></literal> is |
| mandatory. <literal>attempt</literal>/<literal>recover</literal> can |
| be nested freely into other <literal><replaceable>attempt |
| block</replaceable></literal>s or <literal><replaceable>recover |
| block</replaceable></literal>s.</para> |
| |
| <note> |
| <para>The format shown here is supported starting from 2.3.3; |
| earlier it was |
| <literal><#attempt><replaceable>...</replaceable><#recover><replaceable>...</replaceable></#recover></literal>, |
| which is still supported for backward compatibility. Furthermore, |
| these directives were introduced with FreeMarker 2.3.1, so they |
| aren't exist in 2.3.</para> |
| </note> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>These directives are used if you want the page successfully |
| outputted even if the outputting of a certain part of the page |
| fails. If an error occurs during the execution of the |
| <literal><replaceable>attempt block</replaceable></literal>, then |
| the output of the <literal><replaceable>attempt |
| block</replaceable></literal> is rolled back <phrase |
| role="forProgrammers">(and the error is logged, with the default |
| configuration at least)</phrase>, and the |
| <literal><replaceable>recover block</replaceable></literal> is |
| executed instead, then template execution continues normally after |
| the <literal><replaceable>recover block</replaceable></literal>. If |
| no error occurs during the execution of the |
| <literal><replaceable>attempt block</replaceable></literal>, then |
| the <literal><replaceable>recover block</replaceable></literal> is |
| ignored. A simple example:</para> |
| |
| <programlisting role="template">Primary content |
| <#attempt> |
| Optional content: ${thisMayFails} |
| <#recover> |
| Ops! The optional content is not available. |
| </#attempt> |
| Primary content continued</programlisting> |
| |
| <para>If the <literal>thisMayFails</literal> variable doesn't exist |
| (or any other error occurs at that place), then the output |
| is:</para> |
| |
| <programlisting role="output">Primary content |
| Ops! The optional content is not available. |
| Primary content continued</programlisting> |
| |
| <para>If the <literal>thisMayFails</literal> variable exists and |
| it's value is <literal>123</literal>, then the output is:</para> |
| |
| <programlisting role="output">Primary content |
| Optional content: 123 |
| Primary content continued</programlisting> |
| |
| <para>The <literal><replaceable>attempt |
| block</replaceable></literal> has an all-or-none semantic: either |
| the entire content of the <literal><replaceable>attempt |
| block</replaceable></literal> is output (when there was no error), |
| or no output at all results from the execution of the |
| <literal><replaceable>attempt block</replaceable></literal> (when |
| there was an error). For example, above, the failure happens after |
| <quote>Optional content: </quote> was printed, still it is not there |
| in the output before the <quote>Ops!</quote>. (<phrase |
| role="forProgrammers">This is implemented with the aggressive |
| buffering of the output inside the <literal><replaceable>attempt |
| block</replaceable></literal>. Not even the <literal>flush</literal> |
| directive will send the output to the client.</phrase>)</para> |
| |
| <para>To prevent misunderstandings coming from the above example: |
| <literal>attempt</literal>/<literal>recover</literal> is not (only) |
| for handling undefined variables (for that use <link |
| linkend="dgui_template_exp_missing">missing value handler |
| operators</link>). It can handle all kind of errors that occurs when |
| the block is executed (i.e. not syntactical errors, which are |
| detected earlier). It meant to enclose bigger template fragments, |
| where error can occur at various points. For example, you have a |
| part in your template that deals with printing advertisements, but |
| that's not the primary content of the page, so you don't want your |
| whole page be down just because some error occurs with the printing |
| of the advertisements (say, because of a database server outage). So |
| you put the whole advertisement printing into an |
| <literal><replaceable>attempt block</replaceable></literal>.</para> |
| |
| <para>In some environments programmers configure FreeMarker so that |
| it doesn't abort template execution for certain errors, but |
| continues execution, possibly after printing some error indicator to |
| the output (<phrase role="forProgrammers">see more <link |
| linkend="pgui_config_errorhandling">here...</link></phrase>). The |
| <literal>attempt</literal> directive doesn't consider such |
| suppressed errors as errors.</para> |
| |
| <para>Inside a <literal><replaceable>recover |
| block</replaceable></literal> the error message of the error is |
| available with the <literal>error</literal> <link |
| linkend="ref_specvar">special variable</link>. Don't forget that |
| references to special variable are started with dot (for example: |
| <literal>${.error}</literal>).</para> |
| |
| <para><phrase role="forProgrammers">By default errors occurring |
| inside an <literal><replaceable>attempt |
| block</replaceable></literal> are <link |
| linkend="pgui_misc_logging">logged</link> with |
| <literal>ERROR</literal> level, despite that the template recovers |
| from them. This is because <literal>attempt</literal> is not meant |
| to be a general purpose error handler mechanism, like |
| <literal>try</literal> is in Java. It's for decreasing the impact of |
| unexpected errors on the visitors, by making it possible that only |
| part of the page is going down, instead of the whole page. But it's |
| still an error, something that needs the attention of the operators. |
| (The way this error is reported can be customized with the |
| <literal>attempt_exception_reporter</literal> configuration setting, |
| since FreeMarker 2.3.27.)</phrase></para> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_autoesc"> |
| <title>autoesc</title> |
| |
| <anchor xml:id="ref.directive.autoesc"/> |
| |
| <indexterm> |
| <primary>autoesc directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>auto-escaping</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>escaping</primary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"><literal><#autoesc> |
| <replaceable>...</replaceable> |
| </#autoesc></literal> |
| </programlisting> |
| |
| <para>Camel case name variant: <literal>autoEsc</literal></para> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>Turns on <link |
| linkend="dgui_misc_autoescaping">auto-escaping</link> in the nested |
| section. Auto-escaping is usually enabled by default if the current |
| <link linkend="dgui_misc_autoescaping_outputformat">output |
| format</link> has auto-escaping by default, so you rarely need this. |
| Note that to escape just a single |
| <literal>${<replaceable>expression</replaceable>}</literal> where |
| auto-escaping is disabled you should use |
| <literal>${<replaceable>expression</replaceable>?esc}</literal> |
| instead.</para> |
| |
| <para>This directive only has effect on the section that is |
| literally (as in the text editor) inside the nested bock, not on the |
| parts that are called/included from there.</para> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template"><#ftl output_format="XML" auto_esc=false> |
| ${"&"} |
| <#autoesc> |
| ${"&"} |
| ... |
| ${"&"} |
| </#autoesc> |
| ${"&"}</programlisting> |
| |
| <programlisting role="output">& |
| &amp; |
| ... |
| &amp; |
| &</programlisting> |
| |
| <para><literal>autoesc</literal> can't be used where the current |
| <link linkend="dgui_misc_autoescaping_outputformat">output |
| format</link> is a <link |
| linkend="dgui_misc_autoescaping_nonmarkupof">non-markup output |
| format</link> (and hence can't do escaping). Doing so is a <link |
| linkend="gloss.parseTimeError">parse-time error</link>.</para> |
| |
| <para><literal>autoesc</literal> can also be used nested into <link |
| linkend="ref_directive_noautoesc"><literal>noautoesc</literal> |
| directive</link> to re-enable auto-escaping.</para> |
| |
| <para><literal>autoesc</literal> can be used on places where |
| auto-escaping is already enabled, such as even inside another |
| <literal>autoesc</literal> block. Doing so is redundant but |
| allowed.</para> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_compress"> |
| <title>compress</title> |
| |
| <anchor xml:id="ref.directive.compress"/> |
| |
| <indexterm> |
| <primary>compress directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>white-space removal</primary> |
| |
| <secondary>compress</secondary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"> |
| <literal><#compress> |
| <replaceable>...</replaceable> |
| </#compress></literal> |
| </programlisting> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>The compress directive is useful for removing superfluous |
| <link linkend="gloss.whiteSpace">white-space</link> when you use a |
| white-space insensitive format (e.g. HTML or XML). It captures the |
| output generated inside its body (i.e. between its start-tag and |
| end-tag), and reduces all unbroken white-space sequences to a single |
| white-space character. The inserted character will be a <link |
| linkend="gloss.lineBreak">line break</link> if the replaced sequence |
| contains line breaks, or a space otherwise. The very first and very |
| last unbroken white-space sequences will be completely |
| removed.</para> |
| |
| <programlisting role="template"><#assign x = " moo \n\n "> |
| (<#compress> |
| 1 2 3 4 5 |
| ${moo} |
| test only |
| |
| I said, test only |
| |
| </#compress>)</programlisting> |
| |
| <para>will output:</para> |
| |
| <programlisting role="output">(1 2 3 4 5 |
| moo |
| test only |
| I said, test only)</programlisting> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_escape"> |
| <title>escape, noescape (deprecated)</title> |
| |
| <anchor xml:id="ref.directive.escape"/> |
| |
| <anchor xml:id="ref.directive.noescape"/> |
| |
| <indexterm> |
| <primary>escape directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>noescape directive</primary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"> |
| <literal><#escape <replaceable>identifier</replaceable> as <replaceable>expression</replaceable>> |
| <replaceable>...</replaceable> |
| <#noescape><replaceable>...</replaceable></#noescape> |
| <replaceable>...</replaceable> |
| </#escape></literal> |
| </programlisting> |
| |
| <para>Camel case name variant: <literal>noEscape</literal></para> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <note> |
| <para>These directives are <emphasis>deprecated</emphasis> by |
| <link linkend="dgui_misc_autoescaping">output-format-based |
| auto-escaping</link> since 2.3.24. Furthermore, on places that use |
| auto-escaping (with an output format that actually does escaping) |
| you aren't allowed to use the <literal>escape</literal> directive |
| (as you will find out from the parsing error message |
| anyway).</para> |
| </note> |
| |
| <para>When you surround a part of the template with an escape |
| directive, interpolations |
| (<literal>${<replaceable>...</replaceable>}</literal>) that occur |
| inside the block are combined with the escaping expression |
| automatically. This is a convenience method for avoiding writing |
| similar expressions all over. It does not affect interpolations in |
| string literals (as in <literal><#assign x = |
| "Hello ${user}!"></literal>). Also, it does not affect numerical |
| interpolations |
| (<literal>#{<replaceable>...</replaceable>}</literal>).</para> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template"><emphasis><#escape x as x?html></emphasis> |
| First name: ${firstName} |
| Last name: ${lastName} |
| Maiden name: ${maidenName} |
| <emphasis></#escape></emphasis></programlisting> |
| |
| <para>is actually equivalent to:</para> |
| |
| <programlisting role="template"> First name: ${firstName<emphasis>?html</emphasis>} |
| Last name: ${lastName<emphasis>?html</emphasis>} |
| Maiden name: ${maidenName<emphasis>?html</emphasis>}</programlisting> |
| |
| <para>Note that it is irrelevant what identifier you use in the |
| directive - it just serves as a formal parameter to the escaping |
| expression.</para> |
| |
| <para>When you are calling macros or the <literal>include</literal> |
| directive, it is important to understand that escape has effect only |
| on interpolations that occur between the <literal><#escape |
| <replaceable>...</replaceable>></literal> and |
| <literal></#escape></literal> <emphasis>in the template |
| text</emphasis>. That is, it will not escape anything that is before |
| <literal><#escape <replaceable>...</replaceable>></literal> in |
| the text, or after the <literal></#escape></literal> in the |
| text, not even if that part is called from inside the |
| <literal>escape</literal>-d section.</para> |
| |
| <programlisting role="template"><#assign x = "<test>"> |
| <#macro m1> |
| m1: ${x} |
| </#macro> |
| <#escape x as x?html> |
| <#macro m2>m2: ${x}</#macro> |
| ${x} |
| <@m1/> |
| </#escape> |
| ${x} |
| <@m2/></programlisting> |
| |
| <para>the output will be:</para> |
| |
| <programlisting role="output"> &lt;test&gt; |
| m1: <test> |
| <test> |
| m2: &lt;test&gt;</programlisting> |
| |
| <para><phrase role="forProgrammers">More technically, the effects of |
| <literal>escape</literal> directive are applied at template parsing |
| time rather than at template processing time. This means that if you |
| call a macro or include another template from within an escape |
| block, it won't affect the interpolations in the macro/included |
| template, since macro calls and template includes are evaluated at |
| template processing time. On the other hand, if you surround one or |
| more macro declarations (which are evaluated at template parsing |
| time, as opposed to macro calls) with an escape block, the |
| interpolations in those macros will be combined with the escaping |
| expression.</phrase></para> |
| |
| <para>Sometimes there is a need to temporarily turn off escaping for |
| one or two interpolations in an escape block. You can achieve this |
| by closing and later reopening the escape block, but then you have |
| to write the escaping expression twice. You can instead use the |
| noescape directive:</para> |
| |
| <programlisting role="template"><#escape x as x?html> |
| From: ${mailMessage.From} |
| Subject: ${mailMessage.Subject} |
| <emphasis><#noescape></emphasis>Message: ${mailMessage.htmlFormattedBody}<emphasis></#noescape></emphasis> |
| <replaceable>...</replaceable> |
| </#escape></programlisting> |
| |
| <para>is equivalent to:</para> |
| |
| <programlisting role="template"> From: ${mailMessage.From?html} |
| Subject: ${mailMessage.Subject?html} |
| Message: ${mailMessage.htmlFormattedBody} |
| ...</programlisting> |
| |
| <para>Escapes can be nested (although you will do it only in rare |
| circumstances). Therefore, you can write something like the below |
| code (the example is admittedly a bit stretched, as you'd probably |
| place item codes in a sequence and use <literal>list</literal> to |
| iterate over them, but we're now doing it this way just to |
| illustrate the point):</para> |
| |
| <programlisting role="template"><emphasis><#escape x as x?html></emphasis> |
| Customer Name: ${customerName} |
| Items to ship: |
| <emphasis><#escape x as itemCodeToNameMap[x]></emphasis> |
| ${itemCode1} |
| ${itemCode2} |
| ${itemCode3} |
| ${itemCode4} |
| <emphasis></#escape></emphasis> |
| <emphasis></#escape></emphasis></programlisting> |
| |
| <para>is actually equivalent to:</para> |
| |
| <programlisting role="template"> Customer Name: ${customerName?html} |
| Items to ship: |
| ${itemCodeToNameMap[itemCode1]?html} |
| ${itemCodeToNameMap[itemCode2]?html} |
| ${itemCodeToNameMap[itemCode3]?html} |
| ${itemCodeToNameMap[itemCode4]?html}</programlisting> |
| |
| <para>When you use the noescape directive in a nested escape block, |
| it undoes only a single level of escaping. Therefore, to completely |
| turn off escaping in a two-level deep escaped block, you need to use |
| two nested noescape directives as well.</para> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_flush"> |
| <title>flush</title> |
| |
| <anchor xml:id="ref.directive.flush"/> |
| |
| <indexterm> |
| <primary>flush directive</primary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"><literal><#flush></literal></programlisting> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>When FreeMarker generates the output, it's usually not sent |
| immediately to the final receiving party (like a web browser or a |
| destination file), but is accumulated in a buffer, then it's sent |
| out in bigger chunks. The exact rules of the buffering is not |
| decided by FreeMarker, but by the embedding software. Sending out |
| the content accumulated in the buffer is called flushing. Although |
| flushing happens automatically, sometimes you want to force it on |
| certain points of the template processing, and this is what the |
| <literal>flush</literal> directive does. Whether it's needed at |
| certain points should be decided by a programmer, not a |
| designer.</para> |
| |
| <para>Note that while <literal>flush</literal> tells the embedding |
| software that we want to flush, that might as well decides to ignore |
| this request. It's not in the hands of FreeMarker.</para> |
| |
| <para><phrase role="forProgrammers">Flush simply calls the |
| <literal>flush()</literal> method of the currently used |
| <literal>java.io.Writer</literal> instance. The whole buffering and |
| flushing mechanism is implemented in the <literal>Writer</literal> |
| (that you have passed as the parameter of the |
| <literal>Template.process</literal> method); FreeMarker does not |
| deal with it.</phrase></para> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_ftl"> |
| <title>ftl</title> |
| |
| <anchor xml:id="ref.directive.ftl"/> |
| |
| <indexterm> |
| <primary>ftl directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>header</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>charset</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>encoding</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>white-space removal</primary> |
| |
| <secondary>stripping</secondary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"> |
| <literal><#ftl <replaceable>param1</replaceable>=<replaceable>value1</replaceable> <replaceable>param2</replaceable>=<replaceable>value2</replaceable> <replaceable>...</replaceable> <replaceable>paramN</replaceable>=<replaceable>valueN</replaceable>></literal> |
| </programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>param1</replaceable></literal>, |
| <literal><replaceable>param2</replaceable></literal>, ...etc.: |
| Name of the parameter. Not an expression. Allowed parameters |
| are: <literal>encoding</literal>, |
| <literal>strip_whitespace</literal>, |
| <literal>strip_text</literal>, ...etc. See below.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>value1</replaceable></literal>, |
| <literal><replaceable>value2</replaceable></literal>, ...etc.: |
| The value of parameter. This must be a constant expression (as |
| <literal>true</literal>, or <literal>"ISO-8859-5"</literal>, or |
| <literal>{x:1, y:2}</literal>). It can't use variables.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>Tells information about the template for FreeMarker and for |
| other tools, also helps programs to automatically detect if a text |
| file is an FTL file. This directive, if present, must be the very |
| first thing in the template. Any <link |
| linkend="gloss.whiteSpace">white-space</link> before this directive |
| will be ignored. The old-syntax (<literal>#</literal>-less) format |
| of this directive is not supported.</para> |
| |
| <para>The settings (encoding, white-space stripping, etc.) given |
| here has the highest precedence, that is, they will be used for the |
| template regardless of any FreeMarker configuration settings.</para> |
| |
| <para>Possible parameters:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>attributes</literal>: This is a hash that |
| associates arbitrary attributes (name-value pairs) to the |
| template. The values of the attributes can be of any type |
| (string, number, sequence... etc.). FreeMarker doesn't try to |
| understand the meaning of the attributes. It's up to the |
| application that encapsulates FreeMarker (as a Web application |
| framework). Thus, the set of allowed attributes and their |
| semantic is application (Web application framework) dependent. |
| <phrase role="forProgrammers">Programmers: you can get the |
| attributes associated with a <literal>Template</literal> object |
| with its <literal>getCustomAttributeNames</literal> and |
| <literal>getCustomAttribute</literal> methods (inherited from |
| <literal>freemarker.core.Configurable</literal>). As the |
| template attributes are associated with the |
| <literal>Template</literal> object when the template is parsed, |
| the attributes can be read anytime, the template need not be |
| executed. The methods mentioned return the attribute values |
| unwrapped, that is, with FreeMarker independent type as |
| <literal>java.util.List</literal>.</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>auto_esc</literal>: A boolean constant to turn |
| <link linkend="dgui_misc_autoescaping">auto-escaping</link> on |
| or off. It depends on the |
| <literal>auto_escaping_policy</literal> of the FreeMarker |
| configuration, but usually auto-escaping will be by default on, |
| if the current <link |
| linkend="dgui_misc_autoescaping_outputformat">output |
| format</link> uses auto-escaping by default. So you mostly use |
| this to disable auto-escaping (<literal>false</literal> value). |
| An attempt to use <literal>true</literal> value when the current |
| output format is a <link |
| linkend="dgui_misc_autoescaping_nonmarkupof">non-markup output |
| format</link> (which hence can't escape) will cause <link |
| linkend="gloss.parseTimeError">parse-time error</link>. Note |
| that you can turn auto-escaping on/off for only a part of the |
| template with the <link |
| linkend="ref_directive_autoesc"><literal>autoesc</literal></link> |
| and <link |
| linkend="ref_directive_noautoesc"><literal>noautoesc</literal> |
| directives</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>encoding</literal>: With this you can specify the |
| encoding (charset) of the template in the template file itself. |
| <phrase role="forProgrammers">(That is, this will be the |
| <literal>encoding</literal> setting of the newly created |
| <literal>Template</literal>, and not even the |
| <literal>encoding</literal> parameter to |
| <literal>Configuration.getTemplate</literal> can override |
| it)</phrase>. Note however, that FreeMarker will try to find and |
| interpret the <literal>ftl</literal> directive first with the |
| automatically guessed encoding (which depends on the FreeMarker |
| configuration set by the programmers), and only then realizes if |
| the <literal>ftl</literal> directive dictates something |
| different, and re-read the template with the new encoding. Thus, |
| the template must be valid FTL until the end of |
| <literal>ftl</literal> tag with the encoding tried first. The |
| valid values of this parameter are MIME-preferred charset names |
| from the IANA Charset Registry, like ISO-8859-5, UTF-8 or |
| Shift_JIS.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>ns_prefixes</literal>: This is a hash that |
| associates prefixes with node namespaces. For example: |
| <literal>{"e":"http://example.com/ebook", |
| "vg":"http://example.com/vektorGraphics"}</literal>. This is |
| mostly used with XML processing where the prefixes can be used |
| in XML queries, but it also influences the working of <link |
| linkend="ref_directive_visit">directives |
| <literal>visit</literal> and <literal>recurse</literal></link>. |
| Only one prefix can be registered for the same node namespace |
| (otherwise an error will occur), so there is one-to-one relation |
| between prefixes and node namespaces. Prefixes |
| <literal>D</literal> and <literal>N</literal> are reserved. If |
| you register prefix <literal>D</literal>, then other than you |
| associate the node namespace with prefix <literal>D</literal>, |
| you also set the default node namespace. Prefix |
| <literal>N</literal> can't be registered; it is used to denote |
| nodes with no node namespace in certain places, when (and only |
| when) prefix <literal>D</literal> is registered. (To see the |
| usage of default node namespace, <literal>N</literal>, and |
| prefixes in general, see the part about <link linkend="xgui">XML |
| processing</link> and <link |
| linkend="ref_directive_visit"><literal>visit</literal> and |
| <literal>recurse</literal></link> in the reference.) The effect |
| of <literal>ns_prefixes</literal> is limited to a single <link |
| linkend="dgui_misc_namespace">FTL namespace</link>, namely, to |
| the FTL namespace that was created for the template. This also |
| means that <literal>ns_prefixes</literal> has effect only when |
| an FTL namespace is created for the template that contains it, |
| otherwise the <literal>ns_prefixes</literal> parameter has no |
| effect. An FTL namespace is made for a template when: (a) the |
| template is the <quote>main</quote> template, that is, it is not |
| invoked as a result of an <literal><#include |
| ...></literal>, but it is directly invoked (<phrase |
| role="forProgrammers">with the <literal>process</literal> Java |
| method of class <literal>Template</literal> or |
| <literal>Environment</literal></phrase>); (b) the template is |
| invoked directly with <literal><#import |
| ...></literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>output_format</literal>: Specifies the <link |
| linkend="dgui_misc_autoescaping_outputformat">output |
| format</link> of this template. This must be a string literal, |
| which refers to the name of the output format. See the <link |
| linkend="topic.predefinedOutputFormats">table of predefined |
| output formats here</link>. Other names can exist if the |
| programmers has added them via the |
| <literal>registered_custom_output_formats</literal> |
| configuration setting |
| (<literal>Configuration.setRegisteredCustomOutputFormats(<replaceable>...</replaceable>)</literal>). |
| The referred output format must be known by the |
| <literal>Configuration</literal>, or else a <link |
| linkend="gloss.parseTimeError">parse-time error </link>will |
| occur. The name can also refer to a so called combined output |
| format as |
| <literal>"<replaceable>outerFormatName</replaceable>{<replaceable>innerFormatName</replaceable>}"</literal>; |
| <link linkend="topic.combinedOutputFormats">see more about |
| combined output formats here</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>strict_syntax</literal>: This turns on/off |
| <quote>strict syntax</quote>, which is the standard syntax after |
| FreeMarker 2.1. Valid values are the boolean constants |
| <literal>true</literal> and <literal>false</literal>. (And for |
| backward compatibility, strings <literal>"yes"</literal>, |
| <literal>"no"</literal>, <literal>"true"</literal>, |
| <literal>"false"</literal>). The default value (i.e., when you |
| don't use this parameter) depends on the FreeMarker |
| configuration set by the programmers, but it's most certainly |
| set to <literal>true</literal>. For more information read: <xref |
| linkend="ref_depr_oldsyntax"/></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>strip_text</literal>: When enabled, all top-level |
| text in a template is removed when the template is parsed. This |
| does not affect text within macros, directives, or |
| interpolations. Valid values are the boolean constants |
| <literal>true</literal> and <literal>false</literal>. (And for |
| backward compatibility, strings <literal>"yes"</literal>, |
| <literal>"no"</literal>, <literal>"true"</literal>, |
| <literal>"false"</literal>). The default value (i.e. when you |
| don't use this parameter) is <literal>false</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>strip_whitespace</literal>: This enables/disables |
| <link linkend="dgui_misc_whitespace_stripping">white-space |
| stripping</link>. Valid values are the boolean constants |
| <literal>true</literal> and <literal>false</literal>. (And for |
| backward compatibility, strings <literal>"yes"</literal>, |
| <literal>"no"</literal>, <literal>"true"</literal>, |
| <literal>"false"</literal>). The default value (i.e. when you |
| don't use this parameter) depends on the FreeMarker |
| configuration set by the programmers, but it should be |
| <literal>true</literal> for new projects.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <note> |
| <para>As of FreeMarker 2.3.23, you can use camel case instead of |
| snake case for parameter names, like |
| <literal>outputFormat</literal> instead of |
| <literal>output_format</literal>. But know that then within the |
| same template, FreeMarker will enforce the usage of camel case for |
| all identifiers that are part of the template language (user |
| defined names are not affected).</para> |
| </note> |
| |
| <para>This directive also determines if the template uses angle |
| bracket syntax (e.g. <literal><#include 'foo.ftl'></literal>) |
| or <link linkend="dgui_misc_alternativesyntax">square bracket |
| syntax</link> (e.g. <literal>[#include 'foo.ftl']</literal>). |
| Simply, the syntax used for this directive will be the syntax used |
| for the whole template, regardless of the FreeMarker configuration |
| settings.</para> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_function"> |
| <title>function, return</title> |
| |
| <anchor xml:id="ref.directive.function"/> |
| |
| <anchor xml:id="ref.directive.function.return"/> |
| |
| <indexterm> |
| <primary>function directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>return directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>method</primary> |
| |
| <secondary>defining with FTL</secondary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"> |
| <literal><#function <replaceable>name</replaceable> <replaceable>param1</replaceable> <replaceable>param2</replaceable> <replaceable>... paramN</replaceable>> |
| <replaceable>...</replaceable> |
| <#return <replaceable>returnValue</replaceable>> |
| <replaceable>...</replaceable> |
| </#function></literal> |
| </programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>name</replaceable></literal>: name |
| of method variable (not expression)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>param1</replaceable></literal>, |
| <literal><replaceable>param2</replaceable></literal>, ...etc.: |
| the name of the <link linkend="dgui_misc_var">local |
| variables</link> store the parameter values (not expression), |
| optionally followed by <literal>=</literal> and the default |
| value (that's an expression).</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>paramN</replaceable></literal>, the |
| last parameter, may optionally include a trailing ellipsis |
| (<literal>...</literal>), which indicates the macro takes a |
| variable number of parameters. Local variable |
| <literal><replaceable>paramN</replaceable></literal> will be a |
| sequence of the extra parameters.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>returnValue</replaceable></literal>: |
| the expression that calculates the value of the method |
| call.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>The <literal>return</literal> directive can be used anywhere |
| and for any times between the <literal><#function |
| <replaceable>...</replaceable>></literal> and |
| <literal></#function></literal>.</para> |
| |
| <para>Parameters without default value must precede parameters with |
| default value |
| (<literal><replaceable>paramName</replaceable>=<replaceable>defaultValue</replaceable></literal>).</para> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>Creates a method variable (in the current namespace, if you |
| know namespace feature). This directive works in the same way as the |
| <link linkend="ref.directive.macro"><literal>macro</literal> |
| directive</link>, except that <literal>return</literal> directive |
| <emphasis>must</emphasis> have a parameter that specifies the return |
| value of the method, and that attempts to write to the output will |
| be ignored. If the <literal></#function></literal> is reached |
| (i.e. there was no <literal>return |
| <replaceable>returnValue</replaceable></literal>), then the return |
| value of the method is an undefined variable.</para> |
| |
| <para>Example 1: Creating a method that calculates the average of |
| two numbers:</para> |
| |
| <programlisting role="template"><#function avg x y> |
| <#return (x + y) / 2> |
| </#function> |
| ${avg(10, 20)}</programlisting> |
| |
| <para>will print:</para> |
| |
| <programlisting role="output">15</programlisting> |
| |
| <para>Example 2: Creating a method that calculates the average of |
| multiple numbers:</para> |
| |
| <programlisting role="template"><#function avg nums...> |
| <#local sum = 0> |
| <#list nums as num> |
| <#local sum += num> |
| </#list> |
| <#if nums?size != 0> |
| <#return sum / nums?size> |
| </#if> |
| </#function> |
| ${avg(10, 20)} |
| ${avg(10, 20, 30, 40)} |
| ${avg()!"N/A"}</programlisting> |
| |
| <para>will print:</para> |
| |
| <programlisting role="output">15 |
| 25 |
| N/A</programlisting> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_global"> |
| <title>global</title> |
| |
| <anchor xml:id="ref.directive.global"/> |
| |
| <indexterm> |
| <primary>global directive</primary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"> |
| <literal><#global <replaceable>name</replaceable>=<replaceable>value</replaceable>></literal> |
| or |
| <literal><#global <replaceable>name1</replaceable>=<replaceable>value1</replaceable> <replaceable>name2</replaceable>=<replaceable>value2</replaceable> <replaceable>... nameN</replaceable>=<replaceable>valueN</replaceable>></literal> |
| or |
| <literal><#global <replaceable>name</replaceable>> |
| <replaceable>capture this</replaceable> |
| </#global></literal> |
| </programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>name</replaceable></literal>: name |
| of the variable. It is not expression. However, it can be |
| written as a string literal, which is useful if the variable |
| name contains reserved characters, for example |
| <literal><#global "foo-bar" = 1></literal>. Note that this |
| string literal does not expand interpolations (as |
| <literal>"${foo}"</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>=</literal>: Assignment operator, which can also |
| be one of the shorthand assignment operators |
| (<literal>++</literal>, <literal>+=</literal>, etc.), just like |
| with <link linkend="ref_directive_assign">the |
| <literal>assign</literal> directive</link>,</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>value</replaceable></literal>: the |
| value to store. Expression.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>This directive is similar to <link |
| linkend="ref.directive.assign"><literal>assign</literal></link>, but |
| the variable created will be visible in all <link |
| linkend="dgui_misc_namespace">namespaces</link>, and will not be |
| inside any namespace. Exactly as if you would create (or replace) a |
| variable of the data-model. Hence, the variable is global. If a |
| variable with the same name already exists in the data-model, it |
| will be hidden by the variable created with this directive. If a |
| variable with the same name already exists in the current namespace, |
| that will hide the variable created with <literal>global</literal> |
| directive.</para> |
| |
| <para>For example, with <literal><#global x = 1></literal> you |
| create a variable that is visible as <literal>x</literal> in all |
| namespaces, unless another variable called <literal>x</literal> |
| hides it (for example a variable what you have created as |
| <literal><#assign x = 2></literal>). In this case, you can use |
| <link linkend="dgui_template_exp_var_special">special |
| variable</link> <literal>globals</literal>, like |
| <literal>${.globals.x}</literal>. Note that with |
| <literal>globals</literal> you see all globally accessible |
| variables; not only the variables that were created with |
| <literal>global</literal> directive, but also the variables of the |
| data-model.</para> |
| |
| <para>Note for custom JSP tag users: The set of variables created |
| with this directive corresponds to the JSP page-scope. This means, |
| that if a custom JSP tag wants to get a page-scope attribute |
| (page-scope bean), a variable with the same name in the current |
| namespace will not hide it from the viewpoint of the JSP tag.</para> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_if"> |
| <title>if, else, elseif</title> |
| |
| <anchor xml:id="ref.directive.if"/> |
| |
| <anchor xml:id="ref.directive.else"/> |
| |
| <anchor xml:id="ref.directive.elseif"/> |
| |
| <indexterm> |
| <primary>if directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>else directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>elseif directive</primary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"> |
| <literal><#if <replaceable>condition</replaceable>> |
| <replaceable>...</replaceable> |
| <#elseif <replaceable>condition2</replaceable>> |
| <replaceable>...</replaceable> |
| <#elseif <replaceable>condition3</replaceable>> |
| <replaceable>...</replaceable> |
| <replaceable>...</replaceable> |
| <#else> |
| <replaceable>...</replaceable> |
| </#if></literal> |
| </programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>condition</replaceable></literal>, |
| <literal><replaceable>condition2</replaceable></literal>, |
| ...etc.: Expression evaluates to a boolean value.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>The <literal>elseif</literal>-s and the |
| <literal>else</literal> are optional.</para> |
| |
| <para>Camel case name variant: <literal>elseIf</literal></para> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>You can use <literal>if</literal>, <literal>elseif</literal> |
| and <literal>else</literal> directives to conditionally skip a |
| section of the template. The |
| <literal><replaceable>condition</replaceable></literal>-s must |
| evaluate to a boolean value, or else an error will abort template |
| processing. The <literal>elseif</literal>-s and |
| <literal>else</literal>-s must occur inside <literal>if</literal> |
| (that is, between the <literal>if</literal> start-tag and end-tag). |
| The <literal>if</literal> can contain any number of |
| <literal>elseif</literal>-s (including 0) and at the end optionally |
| one <literal>else</literal>. Examples:</para> |
| |
| <para><literal>if</literal> with 0 <literal>elseif</literal> and no |
| <literal>else</literal>:</para> |
| |
| <programlisting role="template"><#if x == 1> |
| x is 1 |
| </#if></programlisting> |
| |
| <para><literal>if</literal> with 0 <literal>elseif</literal> and |
| <literal>else</literal>:</para> |
| |
| <programlisting role="template"><#if x == 1> |
| x is 1 |
| <#else> |
| x is not 1 |
| </#if></programlisting> |
| |
| <para><literal>if</literal> with 2 <literal>elseif</literal> and no |
| <literal>else</literal>:</para> |
| |
| <programlisting role="template"><#if x == 1> |
| x is 1 |
| <#elseif x == 2> |
| x is 2 |
| <#elseif x == 3> |
| x is 3 |
| </#if></programlisting> |
| |
| <para><literal>if</literal> with 3 <literal>elseif</literal> and |
| <literal>else</literal>:</para> |
| |
| <programlisting role="template"><#if x == 1> |
| x is 1 |
| <#elseif x == 2> |
| x is 2 |
| <#elseif x == 3> |
| x is 3 |
| <#elseif x == 4> |
| x is 4 |
| <#else> |
| x is not 1 nor 2 nor 3 nor 4 |
| </#if></programlisting> |
| |
| <para>To see more about boolean expressions, see: <xref |
| linkend="dgui_template_exp"/>.</para> |
| |
| <para>You can nest <literal>if</literal> directives (of |
| course):</para> |
| |
| <programlisting role="template"><#if x == 1> |
| x is 1 |
| <#if y == 1> |
| and y is 1 too |
| <#else> |
| but y is not |
| </#if> |
| <#else> |
| x is not 1 |
| <#if y < 0> |
| and y is less than 0 |
| </#if> |
| </#if></programlisting> |
| |
| <note> |
| <para>When you want to test if <literal>x > 0</literal> or |
| <literal>x >= 0</literal>, writing <literal><#if x > |
| 0></literal> and <literal><#if x >= 0></literal> is |
| WRONG, as the first <literal>></literal> will close the |
| <literal>#if</literal> tag. To work that around, write |
| <literal><#if x gt 0></literal> or <literal><#if gte |
| 0></literal>. Also note that if the comparison occurs inside |
| parentheses, you will have no such problem, like <literal><#if |
| foo.bar(x > 0)></literal> works as expected.</para> |
| </note> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_import"> |
| <title>import</title> |
| |
| <anchor xml:id="ref.directive.import"/> |
| |
| <indexterm> |
| <primary>import directive</primary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"><literal><#import <replaceable>path</replaceable> as <replaceable>hash</replaceable>></literal> |
| </programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>path</replaceable></literal>: The |
| path of a template. This is an expression that evaluates to a |
| string. (With other words, it doesn't have to be a fixed string, |
| it can also be something like, for example, |
| <literal>profile.baseDir + "/menu.ftl"</literal>.)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>hash</replaceable></literal>: The |
| unquoted name of hash variable by which you can access the |
| namespace. Not an expression. (If you have to import into a |
| dynamically constructed name, you have to use <link |
| linkend="faq_assign_to_dynamic_variable_name">this |
| trick</link>.)</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>Used for making a collection of macros, functions, and other |
| variables available for the importing template, which were defined |
| in the imported template. For example, let's say you have written |
| macros to generate some commonly needed pieces output, and you have |
| put them into <literal>/libs/commons.ftl</literal>. Then, in the |
| template where you want to use them, do this (near the top of the |
| the template by convention, next to any other |
| <literal>import</literal>-s):</para> |
| |
| <programlisting role="template"><#import "/libs/commons.ftl" as com> |
| </programlisting> |
| |
| <para>Later in same template, let's say you want to use the |
| <literal>copyright</literal> macro defined in |
| <literal>/libs/commons.ftl</literal>. Then you can call that macro |
| like this:</para> |
| |
| <programlisting role="template"><@com.copyright date="1999-2002"/></programlisting> |
| |
| <para>Note the <literal>com.</literal> before the macro name above. |
| All that was defined in <literal>/libs/commons.ftl</literal> will be |
| inside <literal>com</literal>.</para> |
| |
| <para>Described more technically, <literal>import</literal> first |
| creates a new empty <link |
| linkend="dgui_misc_namespace">namespace</link>, and then executes |
| the template given with |
| <literal><replaceable>path</replaceable></literal> parameter inside |
| that namespace, so the template populates the namespace with |
| variables (macros, functions, ...etc.). Then the namespace is |
| assigned to the variable specified with the |
| <literal><replaceable>hash</replaceable></literal> parameter, and |
| you can access its contents through that. A namespace is <link |
| linkend="dgui_datamodel_container">a hash</link>, hence <link |
| linkend="dgui_template_exp_var_hash">the dot operator</link> worked |
| above. The assignment is like the <literal>assign</literal> |
| directive, that is, it sets the variable in the current namespace. |
| Except, if the import happens in the namespace of the main (topmost) |
| template, the hash variable is also created in the global |
| namespace.</para> |
| |
| <para>If you call <literal>import</literal> with the same |
| <literal><replaceable>path</replaceable></literal> for multiple |
| times, it will create the namespace and run the template for the |
| first call of <literal>import</literal> only. The later calls will |
| just give back the namespace that was created and initialized when |
| the template was imported for the first time, and will not execute |
| the imported template.</para> |
| |
| <para>Any output printed by the imported template will be ignored |
| (will not be inserted at the place of <literal>import</literal> |
| directive invocation). An imported template is executed to populate |
| its namespace with variables, and not to write to the output.</para> |
| |
| <para>The <literal><replaceable>path</replaceable></literal> |
| parameter can be a relative path like <literal>"foo.ftl"</literal> |
| and <literal>"../foo.ftl"</literal>, or an absolute like |
| <literal>"/foo.ftl"</literal>. Relative paths are relative to the |
| directory of the template that uses the <literal>import</literal> |
| directive. Absolute paths are relative to a base (often referred as |
| the ''root directory of the templates'') that the programmer defines |
| when configuring FreeMarker.</para> |
| |
| <para>Always use <literal>/</literal> (slash) to separate path |
| components, never <literal>\</literal> (backslash). If you are |
| loading templates from your local file system and it uses |
| backslashes (like under Windows), FreeMarker will do the necessary |
| conversions automatically.</para> |
| |
| <para>Like with the <literal>include</literal> directive, <link |
| linkend="ref_directive_include_acquisition">acquisition</link> and |
| <link linkend="ref_directive_include_localized">localized |
| lookup</link> may be used for resolving the path.</para> |
| |
| <para><phrase role="forProgrammers">Note that it's possible to |
| automatically do the commonly used imports for all templates, with |
| the "auto imports" setting of <literal>Configuration</literal>. |
| Because templates may not use all the automatically imported |
| namespaces, it's also possible to make imports lazy (on demand), |
| with the <quote>lazy auto imports</quote> setting of |
| <literal>Configuration</literal>.</phrase></para> |
| |
| <para>If you are new to namespaces, you should read: <xref |
| linkend="dgui_misc_namespace"/></para> |
| |
| <para>In case you are not sure if you should use the |
| <literal>import</literal>, or the somewhat similar |
| <literal>include</literal> directive, <link |
| linkend="topic.import_vs_include">then see this</link>.</para> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_include"> |
| <title>include</title> |
| |
| <anchor xml:id="ref.directive.include"/> |
| |
| <indexterm> |
| <primary>include directive</primary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"> |
| <literal><#include <replaceable>path</replaceable>></literal> |
| or |
| <literal><#include <replaceable>path</replaceable> <replaceable>options</replaceable>></literal> |
| </programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>path</replaceable></literal>: The |
| path of the file to include; an expression that evaluates to a |
| string. (With other words, it doesn't have to be a fixed string, |
| it can also be something like, for example, |
| <literal>profile.baseDir + "/menu.ftl"</literal>.)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>options</replaceable></literal>: One |
| or more of these: |
| <literal>encoding=<replaceable>encoding</replaceable></literal>, |
| <literal>parse=<replaceable>parse</replaceable></literal></para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>encoding</replaceable></literal>: |
| Expression evaluates to string</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>parse</replaceable></literal>: |
| Expression evaluates to boolean (also accepts a few string |
| values for backward compatibility)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>ignore_missing</replaceable></literal>: |
| Expression evaluates to boolean</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <note> |
| <para><emphasis>Using <literal>include</literal> directive is |
| almost always a bad practice</emphasis>, and you should consider |
| using <link linkend="ref.directive.import">the |
| <literal>import</literal> directive</link> instead! Even if using |
| <literal>import</literal> adds some verbosity, on the long run it |
| can pay off. See <link linkend="topic.import_vs_include">the |
| reasons here...</link></para> |
| </note> |
| |
| <para>You can use it to insert another FreeMarker template file |
| (specified by the <literal><replaceable>path</replaceable></literal> |
| parameter) into your template. The output from the included template |
| is inserted at the point where the <literal>include</literal> tag |
| occurs. The included file shares the variables with the including |
| template, similarly like if it was copy-pasted into it. The |
| <literal>include</literal> directive is not really replaced by the |
| content of the included file, instead it processes the included file |
| each time when FreeMarker reaches the <literal>include</literal> |
| directive in the course of template processing. So for example if |
| the <literal>include</literal> is inside a <literal>list</literal> |
| loop, you can specify different file names in each cycle.</para> |
| |
| <note> |
| <para>This directive is not be confused with the JSP (Servlet) |
| include, as it doesn't involve the Servlet container at all, just |
| processes another FreeMarker template, without "leaving" |
| FreeMarker. Regarding how to do a "JSP include" <link |
| linkend="faq_servlet_include">read this...</link></para> |
| </note> |
| |
| <para>The <literal><replaceable>path</replaceable></literal> |
| parameter can be a relative path like <literal>"foo.ftl"</literal> |
| and <literal>"../foo.ftl"</literal>, or an absolute like |
| <literal>"/foo.ftl"</literal>. Relative paths are relative to the |
| directory of the template that contains the |
| <literal>import</literal> directive. Absolute paths are relative to |
| a base (often referred as the 'root directory of the templates') |
| that the programmer defines when he configures FreeMarker.</para> |
| |
| <note> |
| <para>This is different than the way it worked prior FreeMarker |
| 2.1, where the path was always absolute. To preserve the old |
| behavior, enable the classic compatible mode in the |
| <literal>Configuration</literal> object.</para> |
| </note> |
| |
| <para>Always use <literal>/</literal> (slash) to separate path |
| components, never <literal>\</literal> (backslash). Even if you are |
| loading templates from your local file system and it uses |
| backslashes (like under. Windows), use <literal>/</literal>.</para> |
| |
| <para>Example:</para> |
| |
| <para>Assume /common/copyright.ftl contains:</para> |
| |
| <programlisting role="template">Copyright 2001-2002 ${me}<br> |
| All rights reserved.</programlisting> |
| |
| <para>Then this:</para> |
| |
| <programlisting role="template"><#assign me = "Juila Smith"> |
| <h1>Some test</h1> |
| <p>Yeah. |
| <hr> |
| <emphasis><#include "/common/copyright.ftl"></emphasis></programlisting> |
| |
| <para>will output this:</para> |
| |
| <programlisting role="output"><h1>Some test</h1> |
| <p>Yeah. |
| <hr> |
| <emphasis>Copyright 2001-2002 Juila Smith |
| All rights reserved.</emphasis></programlisting> |
| |
| <para>The supported |
| <literal><replaceable>options</replaceable></literal> are:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>parse</literal>: If it is |
| <literal>true</literal>, then the included file will be parsed |
| as FTL, otherwise the whole file will be considered as simple |
| text (i.e, no FreeMarker constructs will be searched in it). If |
| you omit this option, then it defaults to |
| <literal>true</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>encoding</literal>: The encoding (charset) of the |
| included template. You shouldn't use this option anymore; if |
| different template use different encodings, then the programmers |
| should associated the encoding to the templates via |
| <literal>Configuration.setTemplateConfigurations(<replaceable>...</replaceable>)</literal>-s |
| (which also overrides that you specify here). If |
| <literal>Configuration.setTemplateConfigurations(<replaceable>...</replaceable>)</literal> |
| doesn't specify an encoding for the included template, then the |
| included file inherits the encoding (the charset) of the |
| top-level template, unless you specify an encoding with this |
| option. Examples of valid names: UTF-8, ISO-8859-1, ISO-8859-2, |
| Shift_JIS, Big5, EUC-KR, GB2312. <phrase |
| role="forProgrammers">Encoding names are the same as the ones |
| supported be java.io.InputStreamReader (as of Java API 1.3: |
| MIME-preferred charset names from the IANA Charset |
| Registry)</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>ignore_missing</literal>: When |
| <literal>true</literal>, suppresses the error when the template |
| to include is missing, instead <literal><#include |
| ...></literal> will print nothing. When |
| <literal>false</literal>, the template processing will stop with |
| error if the template is missing. If you omit this option, then |
| it defaults to <literal>false</literal>. A more flexible |
| approach to handle missing templates (such as if you need to do |
| something when the template is missing) is using the <link |
| linkend="ref_specvar_get_optional_template"><literal>get_optional_template</literal> |
| special variable</link>.</para> |
| |
| <note> |
| <para>If <literal>ignore_missing</literal> is |
| <literal>true</literal>, yet the <literal>include</literal> |
| directive fails with <quote>Template inclusion failed</quote> |
| error when the template is missing, that's often because your |
| application uses a custom |
| <literal>freemarker.cache.TemplateLoader</literal> |
| implementation, which incorrectly (against the API |
| documentation) throws an <literal>IOException</literal> in the |
| <literal>findTemplateSource</literal> method instead of |
| returning <literal>null</literal> if a template is not found. |
| If it's so, the Java programmers need to fix that. Another |
| possibility is of course that it was indeed not possible to |
| tell if the template exists or not due to some technical |
| issues, in which case stopping with error is the correct |
| behavior. See the cause <literal>IOException</literal> in the |
| Java stack trace to figure out which case it is.</para> |
| </note> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template"><#include "/common/navbar.html" parse=false encoding="Shift_JIS"></programlisting> |
| |
| <para><phrase role="forProgrammers">Note, that it is possible to |
| automatically do the commonly used inclusions for all templates, |
| with the "auto includes" setting of |
| <literal>Configuration</literal>.</phrase></para> |
| |
| <section xml:id="ref_directive_include_acquisition"> |
| <title>Using acquisition</title> |
| |
| <indexterm> |
| <primary>acquisition</primary> |
| </indexterm> |
| |
| <para>There's a special path component represented by an asterisk |
| (<literal>*</literal>). It is interpreted as "this directory or |
| any of its parents". Therefore, if the template located in |
| <literal>/foo/bar/template.ftl</literal> has the following |
| line:</para> |
| |
| <programlisting role="template"><#include "*/footer.ftl"></programlisting> |
| |
| <para>then the engine will look for the template in following |
| locations, in this order:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>/foo/bar/footer.ftl</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>/foo/footer.ftl</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>/footer.ftl</literal></para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>This mechanism is called <emphasis |
| role="term">acquisition</emphasis> and allows the designers to |
| place commonly included files in a parent directory, and redefine |
| them on a per-subdirectory basis as needed. We say that the |
| including template acquires the template to include from the first |
| parent directory that has it. Note that you can specify not only a |
| template name to the right of the asterisk, but a subpath as well. |
| I.e. if the previous template instead read:</para> |
| |
| <programlisting role="template"><#include "*/commons/footer.ftl"></programlisting> |
| |
| <para>then the engine would look for the template in following |
| locations, in this order:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>/foo/bar/commons/footer.ftl</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>/foo/commons/footer.ftl</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>/commons/footer.ftl</literal></para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Finally, the asterisk needn't be the first element of the |
| path:</para> |
| |
| <programlisting role="template"><#include "commons/*/footer.ftl"></programlisting> |
| |
| <para>would cause the engine to look for the template in following |
| locations, in this order:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>/foo/bar/commons/footer.ftl</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>/foo/bar/footer.ftl</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>/foo/footer.ftl</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>/footer.ftl</literal></para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>However, there can be at most one asterisk in the path. If |
| you specifying more asterisks, the template won't be found.</para> |
| </section> |
| |
| <section xml:id="ref_directive_include_localized"> |
| <title>Localized lookup</title> |
| |
| <indexterm> |
| <primary>localization</primary> |
| </indexterm> |
| |
| <para>A locale is a language and an optional country or dialect |
| identifier (plus also maybe a further variant identifier, like |
| <quote>MAC</quote>). Whenever a template is requested, a desired |
| locale is always specified (explicitly or implicitly), and |
| FreeMarke will try to find a variant of the template that matches |
| that locale. When a template includes or imports another template, |
| internally that will also be requested for a locale, for the |
| locale that the <literal>locale</literal> setting is set to, and |
| that's usually for the locale of the top-level template.</para> |
| |
| <para>Suppose your template was loaded with locale |
| <literal>en_US</literal>, which means U.S. English. When you |
| include another template:</para> |
| |
| <programlisting role="template"><#include "footer.ftl"></programlisting> |
| |
| <para>the engine will in fact look for several templates, in this |
| order:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>footer_en_US.ftl</literal>,</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>footer_en.ftl</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>footer.ftl</literal></para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>and it will use the first one that exists.</para> |
| |
| <para>Note that if how (and if) FreeMarker searches the localized |
| variations is configurable by the programmers, so we are just |
| describing the default behavior here.<phrase |
| role="forProgrammers"> You can disable localized lookup with the |
| <literal>localized_lookup</literal> setting |
| (<literal>Configuration.setLocalizedLookup(boolean)</literal>). |
| Also, you can define your own sequence of deduced template names |
| with the <literal>template_lookup_strategy</literal> setting |
| (<literal>Configuration.setTemplateLookupStrategy(TemplateLookupStrategy)</literal>).</phrase></para> |
| |
| <para>When you use both acquisition (i.e., <literal>*</literal> |
| step in the path) and localized template lookup, the template with |
| more specific locale in a parent directory takes precedence over |
| template with less specific locale in a child directory. Suppose |
| you use the following include from |
| <literal>/foo/bar/template.ftl</literal>:</para> |
| |
| <programlisting role="template"><#include "*/footer.ftl"></programlisting> |
| |
| <para>the engine will look for these templates, in this |
| order:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>/foo/bar/footer_en_US.ftl</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>/foo/footer_en_US.ftl</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>/footer_en_US.ftl</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>/foo/bar/footer_en.ftl</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>/foo/footer_en.ftl</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>/footer_en.ftl</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>/foo/bar/footer.ftl</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>/foo/footer.ftl</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>/footer.ftl</literal></para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section xml:id="topic.import_vs_include"> |
| <title>Why <literal>import</literal> should be used instead of |
| <literal>include</literal></title> |
| |
| <para>Generally, using <link linkend="ref.directive.import">the |
| <literal>import</literal> directive</link> is a better practice |
| than using <literal>include</literal>.</para> |
| |
| <para>At first glance, import is only fitting if you have a |
| collection of commonly used macros, functions, and other |
| variables, which you put into a template for reuse. But, people |
| often use <literal>include</literal> to insert a common fragment |
| of output (e.g. page footer) into multiple templates. The |
| <literal>import</literal> directive has no output, so it's clearly |
| not a direct replacement. But, it's usually a better practice to |
| <link linkend="dgui_misc_userdefdir">put those output fragments |
| into macros</link>, as macros can have parameters, or even nested |
| content. If you do that, you have a collection of macros in a |
| template, that you can <literal>import</literal>.</para> |
| |
| <para>So if you have collection of macros, functions and other |
| variables in a template, this is why <literal>import</literal> is |
| generally a better choice:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Imported templates are processed only when first |
| requested. To compare with <literal>include</literal>, let's |
| say template <literal>top.ftl</literal> includes |
| <literal>commons.ftl</literal>, and |
| <literal>tables.ftl</literal>. If |
| <literal>tables.ftl</literal> also includes |
| <literal>commons.ftl</literal>, then now |
| <literal>commons.ftl</literal> will be processed twice. On the |
| other hand, importing <literal>commons.ftl</literal> for the |
| second time just gives back the namespace that was already |
| initialized during the first import.</para> |
| </listitem> |
| |
| <listitem> |
| <para>With imports, each imported template has its own |
| namespace. As they don't just drop everything into a common |
| shared namespace, it's easier to see in templates where a |
| referred variable, or macro/function is coming from. |
| Accidental name clashes are also avoided.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If you have several collections of useful |
| macros/functions/constants (say, |
| <literal>commons.ftl</literal>, <literal>form.ftl</literal>, |
| <literal>report.ftl</literal>, etc.), and you decide to |
| auto-import them, but a top-level template usually only uses |
| some of them, you can configure auto-imports to be lazy (i.e., |
| they on happen when something in their namespace is actually |
| accessed). This is not possible with auto-includes.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>import</literal> never prints to the output, |
| while <literal>include</literal> might prints unwanted output, |
| like some whitespace that wasn't removed by the automatic |
| whitespace removal.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_list"> |
| <title>list, else, items, sep, break, continue</title> |
| |
| <anchor xml:id="ref.directive.list"/> |
| |
| <indexterm> |
| <primary>list directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>sequence</primary> |
| |
| <secondary>iterate</secondary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <para>The simplest form for listing a sequence (or collection) |
| is:</para> |
| |
| <programlisting role="metaTemplate"><literal><#list <replaceable>sequence</replaceable> as <replaceable>item</replaceable>> |
| <replaceable>Part repeated for each item</replaceable> |
| </#list></literal></programlisting> |
| |
| <para>and to list the key-value pairs of a hash (since |
| 2.3.25):</para> |
| |
| <programlisting role="metaTemplate"><literal><#list <replaceable>hash</replaceable> as <replaceable>key</replaceable>, <replaceable>value</replaceable>> |
| <replaceable>Part repeated for each key-value pair</replaceable> |
| </#list></literal></programlisting> |
| |
| <para>But these are just special cases of the generic forms, which |
| are shown below. Note that for simplicity we only show the generic |
| forms for sequence listing; simply replace <quote><literal>as |
| <replaceable>item</replaceable></literal></quote> with |
| <quote><literal>as <replaceable>key</replaceable>, |
| <replaceable>value</replaceable></literal></quote> to get the |
| generic form for hash listing.</para> |
| |
| <para>Generic form 1:</para> |
| |
| <programlisting role="metaTemplate"><literal><#list <replaceable>sequence</replaceable> as <replaceable>item</replaceable>> |
| <replaceable>Part repeated for each item</replaceable> |
| <#else> |
| <replaceable>Part executed when there are 0 items</replaceable> |
| </#list></literal></programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>The <literal>else</literal> part is optional, and is only |
| supported since FreeMarker 2.3.23.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>sequence</replaceable></literal>: |
| Expressions evaluates to a sequence or collection of the items |
| we want to iterate through</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>item</replaceable></literal>: Name |
| of the <link linkend="dgui_misc_var">loop variable</link> (not |
| an expression)</para> |
| </listitem> |
| |
| <listitem> |
| <para>The various <quote>parts</quote> between the tags can |
| contain arbitrary FTL (including nested |
| <literal>list</literal>-s)</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Generic form 2 (since FreeMarker 2.3.23):</para> |
| |
| <programlisting role="metaTemplate"><literal><#list <replaceable>sequence</replaceable>> |
| <replaceable>Part executed once if we have more than 0 items</replaceable> |
| <#items as <replaceable>item</replaceable>> |
| <replaceable> Part repeated for each item</replaceable> |
| </#items> |
| <replaceable>Part executed once if we have more than 0 items</replaceable> |
| <#else> |
| <replaceable>Part executed when there are 0 items</replaceable> |
| </#list></literal></programlisting> |
| |
| <para>Where: see the <quote>Where</quote> section of Form 1 above |
| (and thus the <literal>else</literal> part is optional here |
| too).</para> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <section xml:id="ref_list_simple"> |
| <title>Simplest form</title> |
| |
| <para>Assuming <literal>users</literal> contains the |
| <literal>['Joe', 'Kate', 'Fred']</literal> sequence:</para> |
| |
| <programlisting role="template"><#list users as user> |
| <p>${user} |
| </#list></programlisting> |
| |
| <programlisting role="output"> <p>Joe |
| <p>Kate |
| <p>Fred</programlisting> |
| |
| <para>The <literal>list</literal> directive executes the code |
| between the <literal>list</literal> start-tag and |
| <literal>list</literal> end-tag (the body of |
| <literal>list</literal> from now on) for each value in the |
| sequence (or collection) specified as its first parameter. For |
| each such iteration the loop variable (<literal>user</literal> in |
| this example) will store the value of the current item.</para> |
| |
| <para>The loop variable (<literal>user</literal>) only exists |
| inside the <literal>list</literal> body. Also, macros/functions |
| called from within the loop won't see it (as if it were a local |
| variable).</para> |
| |
| <para>Listing hashes is very similar, but you need to provide two |
| variable names after the <literal>as</literal>; one for the hash |
| key, and another for the associated value. Assuming |
| <literal>products</literal> is <literal>{ "apple": 5, "banana": |
| 10, "kiwi": 15 }</literal>:</para> |
| |
| <programlisting role="template"><#list products as name, price> |
| <p>${name}: ${price} |
| </#list></programlisting> |
| |
| <programlisting role="output"> <p>apple: 5 |
| <p>banan: 10 |
| <p>kiwi: 15</programlisting> |
| |
| <para>Note that not all hash variables can be listed, because some |
| of them isn't able to enumerate its keys. It's practically safe to |
| assume though that hashes that stand for Java |
| <literal>Map</literal> objects can be listed.</para> |
| </section> |
| |
| <section xml:id="ref_list_else"> |
| <title>else directive</title> |
| |
| <anchor xml:id="ref.directive.list.else"/> |
| |
| <indexterm> |
| <primary>else directive inside list</primary> |
| </indexterm> |
| |
| <note> |
| <para><literal>else</literal> inside <literal>list</literal> is |
| only supported since FreeMarker 2.3.23</para> |
| </note> |
| |
| <para>The <literal>else</literal> directive is used if when there |
| are 0 items, you have to print something special instead of just |
| printing nothing:</para> |
| |
| <programlisting role="template"><#list users as user> |
| <p>${user} |
| <#else> |
| <p>No users |
| </#list></programlisting> |
| |
| <para>This outputs the same as the earlier example, except when |
| <literal>users</literal> contains 0 items:</para> |
| |
| <programlisting role="output"> <p>No users</programlisting> |
| |
| <para>Note that the loop variable (<literal>user</literal>) |
| doesn't exist between the <literal>else</literal> tag and the |
| <literal>list</literal> end-tag, since that part is not part of |
| the loop.</para> |
| |
| <para><literal>else</literal> must be literally (means, in the |
| source code) inside the body of the <literal>list</literal> |
| directive. That is, you can't moved it out into a macro or |
| included template.</para> |
| </section> |
| |
| <section xml:id="ref_list_items"> |
| <title>items directive</title> |
| |
| <anchor xml:id="ref.directive.items"/> |
| |
| <indexterm> |
| <primary>items directive</primary> |
| </indexterm> |
| |
| <note> |
| <para><literal>items</literal> exists since FreeMarker |
| 2.3.23</para> |
| </note> |
| |
| <para>The <literal>items</literal> directive is used if you have |
| to print (or do) something before the first list item, and after |
| the last list item, as far as there's at least 1 item. A typical |
| example:</para> |
| |
| <programlisting role="template"><#list users> |
| <ul> |
| <#items as user> |
| <li>${user}</li> |
| </#items> |
| </ul> |
| </#list></programlisting> |
| |
| <programlisting role="output"> <ul> |
| <li>Joe</li> |
| <li>Kate</li> |
| <li>Fred</li> |
| </ul></programlisting> |
| |
| <para>If there are 0 items, the above won't print anything, thus |
| you don't end up with an empty |
| <literal><ul></ul></literal>.</para> |
| |
| <para>That is, when the <literal>list</literal> directive has no |
| <literal>as <replaceable>item</replaceable></literal> parameter, |
| the body of its is executed exactly once if there's at least one |
| item, or not at all otherwise. It's the body of the mandatory |
| nested <literal>items</literal> directive that will be run for |
| each item, and hence it's also the <literal>items</literal> |
| directive that defines the loop variable with <literal>as |
| <replaceable>item</replaceable></literal>, not |
| <literal>list</literal>.</para> |
| |
| <para>A <literal>list</literal> directive with |
| <literal>items</literal> also can have an <literal>else</literal> |
| directive:</para> |
| |
| <programlisting role="template"><#list users> |
| <ul> |
| <#items as user> |
| <li>${user}</li> |
| </#items> |
| </ul> |
| <#else> |
| <p>No users |
| </#list></programlisting> |
| |
| <para>Some further details:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The parser will check that a <literal>list</literal> |
| without <literal>as <replaceable>item</replaceable></literal> |
| parameter always has a nested <literal>items</literal> |
| directive, and that an <literal>items</literal> directive |
| always has an enclosing <literal>list</literal> which has no |
| <literal>as <replaceable>item</replaceable></literal> |
| parameter. This is checked when the template is parsed, not |
| when the template is executed. Thus, these rules apply on the |
| FTL source code itself, so you can't move |
| <literal>items</literal> out into a macro or included |
| template.</para> |
| </listitem> |
| |
| <listitem> |
| <para>A <literal>list</literal> can have multiple |
| <literal>items</literal> directives, but only one of them will |
| be allowed to run (as far as you don't leave and re-enter the |
| enclosing <literal>list</literal> directive); and further |
| attempts to call <literal>items</literal> will cause error. So |
| multiple <literal>items</literal> can be utilized on different |
| <literal>if</literal>-<literal>else</literal> branches for |
| example, but not for iterating twice.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>items</literal> directive can't have its own |
| nested <literal>else</literal> directive, only the enclosing |
| <literal>list</literal> can have</para> |
| </listitem> |
| |
| <listitem> |
| <para>The loop variable (<literal>user</literal>) only exists |
| inside the body of the <literal>items</literal> |
| directive.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section xml:id="ref_list_sep"> |
| <title>sep directive</title> |
| |
| <anchor xml:id="ref.directive.sep"/> |
| |
| <indexterm> |
| <primary>sep directive</primary> |
| </indexterm> |
| |
| <note> |
| <para><literal>sep</literal> exists since FreeMarker |
| 2.3.23</para> |
| </note> |
| |
| <para><literal>sep</literal> is used when you have to display |
| something between each item (but not before the first item or |
| after the last item). For example:</para> |
| |
| <programlisting role="template"><#list users as user>${user}<emphasis><#sep>, </emphasis></#list></programlisting> |
| |
| <programlisting role="output">Joe, Kate, Fred</programlisting> |
| |
| <para>Above, <literal><#sep>, </#list></literal> is a |
| shorthand for <literal><#sep>, |
| </#sep></#list></literal>; the <literal>sep</literal> |
| end-tag can be omitted if you would put it where the enclosing |
| directive is closed anyway. In the next example, you couldn't use |
| such abbreviation (HTML tags close nothing, as they are just raw |
| text to output for FreeMarker):</para> |
| |
| <programlisting role="template"><#list users as user> |
| <div> |
| ${user}<emphasis><#sep>, </#sep></emphasis> |
| </div> |
| </#list></programlisting> |
| |
| <para><literal>sep</literal> is just a shorthand for |
| <literal><#if |
| <replaceable>item</replaceable>?has_next>...</#if></literal>. |
| Thus, it can be used anywhere where there's a |
| <literal>list</literal> or <literal>items</literal> loop variable |
| available, it can occur for multiple times, and it can have |
| arbitrary nested content.</para> |
| |
| <para>The parser ensures that <literal>sep</literal> is only used |
| on a place where there's a visible loop variable. This happens |
| earlier than the actual execution of the template. Thus, you can't |
| move <literal>sep</literal> from inside the associated |
| <literal>list</literal> or <literal>items</literal> directive into |
| a macro or included template (the parser can't know where those |
| will be called from).</para> |
| </section> |
| |
| <section xml:id="ref_list_break"> |
| <title>break directive</title> |
| |
| <anchor xml:id="ref.directive.list.break"/> |
| |
| <indexterm> |
| <primary>break directive</primary> |
| </indexterm> |
| |
| <note> |
| <para><literal>break</literal> is deprecated for most use cases, |
| as it doesn't work well with <literal><#sep></literal> and |
| <literal><replaceable>item</replaceable>?has_next</literal>. |
| Instead, use <link |
| linkend="ref_builtin_take_while"><literal><replaceable>sequence</replaceable>?take_while(<replaceable>predicate</replaceable>)</literal></link> |
| to cut the sequence before you list it. See also examples <link |
| linkend="ref_list_skipping">here.</link></para> |
| </note> |
| |
| <para>You can exit the iteration at any point with the |
| <literal>break</literal> directive. For example:</para> |
| |
| <programlisting role="template"><#list 1..10 as x> |
| ${x} |
| <#if x == 3> |
| <emphasis><#break></emphasis> |
| </#if> |
| </#list></programlisting> |
| |
| <programlisting role="output"> 1 |
| 2 |
| 3</programlisting> |
| |
| <para>The <literal>break</literal> directives can be placed |
| anywhere inside <literal>list</literal> as far as it has |
| <literal>as <replaceable>item</replaceable></literal> parameter, |
| otherwise it can be placed anywhere inside the |
| <literal>items</literal> directive. However, it's strongly |
| recommended to place it either before or after all the other |
| things that you do inside the iteration. Otherwise it's easy to |
| end up with unclosed elements in the output, or otherwise make the |
| template harder to understand. Especially, avoid breaking out from |
| the nested content of custom directives (like <literal><#list |
| ...>...<@foo>...<#break>...</@foo>...</#list></literal>), |
| as the author of the directive may not expect that the closing tag |
| (<literal></@foo></literal>) is never executed.</para> |
| |
| <para>If the <literal>break</literal> is inside |
| <literal>items</literal>, it will only exit from |
| <literal>items</literal>, not from <literal>list</literal>. In |
| general, <literal>break</literal> will only exit from the |
| directive whose body is called for each item, and can only be |
| placed inside such directive. So for example can't use |
| <literal>break</literal> inside <literal>list</literal>'s |
| <literal>else</literal> section, unless there's the |
| <literal>list</literal> is nested into another |
| <literal>break</literal>-able directive.</para> |
| |
| <para>Using <literal>break</literal> together with |
| <literal>sep</literal> or <literal>?has_next</literal> is |
| generally a bad idea, as these can't know if you will skip the |
| rest of items with a <literal>break</literal>. To solve such |
| situations see <link linkend="ref_list_skipping">these |
| examples</link>.</para> |
| |
| <para>Just like <literal>else</literal> and |
| <literal>items</literal>, <literal>break</literal> must be |
| literally inside body of the directive to break out from, and |
| can't be moved out into a macro or included template.</para> |
| </section> |
| |
| <section xml:id="ref_list_continue"> |
| <title>continue directive</title> |
| |
| <anchor xml:id="ref.directive.list.continue"/> |
| |
| <indexterm> |
| <primary>continue directive</primary> |
| </indexterm> |
| |
| <note> |
| <para><literal>continue</literal> is deprecated for most use |
| cases, as it doesn't work well with |
| <literal><#sep></literal>, |
| <literal><replaceable>item</replaceable>?has_next</literal>, |
| <literal><replaceable>item</replaceable>?counter</literal>, |
| <literal><replaceable>item</replaceable>?index</literal>, |
| <literal><replaceable>item</replaceable>?item_parity</literal>, |
| etc. Instead, use <link |
| linkend="ref_builtin_filter"><literal><replaceable>sequence</replaceable>?filter(<replaceable>predicate</replaceable>)</literal></link> |
| to remove unwanted elements. See also examples <link |
| linkend="ref_list_skipping">here.</link></para> |
| </note> |
| |
| <note> |
| <para>The <literal>continue</literal> directive exists since |
| FreeMarker 2.3.27.</para> |
| </note> |
| |
| <para>You can skip the rest of the iteration body (the section |
| until the <literal></#list></literal> or |
| <literal></#items></literal> tag) with the |
| <literal>continue</literal> directive, then FreeMarker will |
| continue with the next item. For example:</para> |
| |
| <programlisting role="template"><#list 1..5 as x> |
| <#if x == 3> |
| <#continue> |
| </#if> |
| ${x} |
| </#list></programlisting> |
| |
| <programlisting role="output"> 1 |
| 2 |
| 4 |
| 5</programlisting> |
| |
| <para>The <literal>continue</literal> directives can be placed |
| anywhere inside <literal>list</literal> as far as it has |
| <literal>as <replaceable>item</replaceable></literal> parameter, |
| otherwise it can be placed anywhere inside the |
| <literal>items</literal> directive. However, it's strongly |
| recommended to place it before all the other things you do inside |
| the iteration. Otherwise it's easy to end up with unclosed |
| elements in the output, or otherwise make the template harder to |
| understand. Especially, avoid breaking out from the nested content |
| of custom directives (like <literal><#list |
| ...>...<@foo>...<#continue>...</@foo>...</#list></literal>), |
| as the author of the directive may not expect that the closing tag |
| (<literal></@foo></literal>) is never executed.</para> |
| |
| <para>When you call <literal>continue</literal>, the |
| <literal>sep</literal> directive will not be executed for that |
| iteration. Using <literal>continue</literal> together with |
| <literal>sep</literal> is generally a bad idea anyway, also |
| <literal>?has_next</literal>, <literal>?counter</literal>, |
| <literal>?index</literal>, <literal>?item_parity</literal>, etc. |
| will not work as you certainly wanted if you completely skip |
| items. To solve such situations see <link |
| linkend="ref_list_skipping">these examples</link>.</para> |
| |
| <para>Just like <literal>break</literal>, |
| <literal>continue</literal> must be literally inside body of the |
| directive whose iteration need to be <quote>continued</quote>, and |
| can't be moved out into a macro or included template.</para> |
| </section> |
| |
| <section xml:id="ref_list_accessing_state"> |
| <title>Accessing iteration state</title> |
| |
| <indexterm> |
| <primary>iteration state</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>listing state</primary> |
| </indexterm> |
| |
| <para>Starting from 2.3.23, <link |
| linkend="ref_builtins_loop_var">loop variable built-ins</link> is |
| the preferred way of accessing current state of the iteration. For |
| example, here we use the <literal>counter</literal> and |
| <literal>item_parity</literal> loop variable built-ins (see all of |
| them <link linkend="ref_builtins_loop_var">in the |
| Reference</link>):</para> |
| |
| <programlisting role="template"><#list users> |
| <table> |
| <#items as user> |
| <tr class="${user<emphasis>?item_parity</emphasis>}Row"> |
| <td>${user<emphasis>?counter</emphasis>} |
| <td>${user} |
| </#items> |
| </table> |
| </#list></programlisting> |
| |
| <programlisting role="output"> <table> |
| <tr class="<emphasis>odd</emphasis>Row"> |
| <td><emphasis>1</emphasis> |
| <td>Joe |
| <tr class="<emphasis>even</emphasis>Row"> |
| <td><emphasis>2</emphasis> |
| <td>Kate |
| <tr class="<emphasis>odd</emphasis>Row"> |
| <td><emphasis>3</emphasis> |
| <td>Fred |
| </table></programlisting> |
| |
| <para>In 2.3.22 and earlier, there were two extra loop variables |
| to retrieve the iteration state instead (and they still exist for |
| backward compatibility):</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal><replaceable>item</replaceable>_index</literal> |
| (<emphasis>deprecated</emphasis> by |
| <literal><replaceable>item</replaceable>?index</literal>): The |
| index (0-based number) of the current item in the loop.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>item</replaceable>_has_next</literal> |
| (<emphasis>deprecated</emphasis> by |
| <literal><replaceable>item</replaceable>?has_next</literal>): |
| Boolean value that tells if the current item is the last in |
| the sequence or not.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>so in the above example, you could replace |
| <literal>${user?counter}</literal> with <literal>${user_index + |
| 1}</literal>.</para> |
| </section> |
| |
| <section xml:id="ref_list_skipping"> |
| <title>Skipping items conditionally</title> |
| |
| <para>If you need to skip certain element in a list, it's |
| generally a bad idea to use <link |
| linkend="ref.directive.if"><literal>if</literal> directive</link> |
| for that, because then <literal><#sep></literal>, |
| <literal><replaceable>item</replaceable>?has_next</literal>, |
| <literal><replaceable>item</replaceable>?counter</literal>, |
| <literal><replaceable>item</replaceable>?index</literal>, |
| <literal><replaceable>item</replaceable>?item_parity</literal>, |
| etc., will not be usable, as FreeMarker doesn't know what items |
| were and will be actually displayed. Instead, you should try to |
| remove the unwanted items from the sequence that you will list, |
| and then list it (since 2.3.29). Here are some typical examples |
| with and without <literal>if</literal>.</para> |
| |
| <simplesect> |
| <title>Filtering</title> |
| |
| <para>In this example, you want to show the recommended products |
| from <literal>products</literal>. Here's the wrong solution with |
| <literal>if</literal>:</para> |
| |
| <programlisting role="template"><#-- WRONG solution! The row parity classes will be possibly messed up: --> |
| <#list products as product> |
| <#<emphasis>if product.recommended</emphasis>> |
| <div class="${product<emphasis>?item_parity</emphasis>}Row">${product.name}</div> |
| </#if> |
| </#list></programlisting> |
| |
| <para>Here's the good solution that uses the <link |
| linkend="ref_builtin_filter"><literal>filter</literal> |
| built-in</link>:</para> |
| |
| <programlisting role="template"><#-- Good solution: --> |
| <#list products<emphasis>?filter(p -> p.recommended)</emphasis> as product> |
| <div class="${product?item_parity}Row">${product.name}</div> |
| </#list></programlisting> |
| </simplesect> |
| |
| <simplesect> |
| <title>Stop listing when a certain element is found</title> |
| |
| <para>Let's say you have a list of lines in |
| <literal>lines</literal>, and you need to stop at the first |
| empty line (if there's any). Furthermore you need to |
| <literal><br></literal> between the elements. Here's the |
| wrong solution with <literal>if</literal> and |
| <literal>break</literal>:</para> |
| |
| <programlisting role="template"><#-- WRONG solution! <br> might be added after the last printed line: --> |
| <#list lines as line> |
| <#if line == ''> |
| <#break> |
| </#if> |
| ${line}<#sep><br> |
| </#list></programlisting> |
| |
| <para>Here's the good solution that uses the <link |
| linkend="ref_builtin_take_while"><literal>take_while</literal> |
| built-in</link> (note that the condition is inverted compared to |
| the <literal>if</literal>+<literal>break</literal> |
| solution):</para> |
| |
| <programlisting role="template"><#-- Good solution: --> |
| <#list lines?take_while(line -> line != '') as line> |
| ${line}<#sep><br> |
| </#list></programlisting> |
| </simplesect> |
| </section> |
| |
| <section xml:id="ref_list_nesting"> |
| <title>Nesting loops into each other</title> |
| |
| <para>Naturally, <literal>list</literal> or |
| <literal>items</literal> can contain further |
| <literal>list</literal>-s:</para> |
| |
| <programlisting role="template"><#list 1..2 as i> |
| <#list 1..3 as j> |
| i = ${i}, j = ${j} |
| </#list> |
| </#list></programlisting> |
| |
| <programlisting role="output"> i = 1, j = 1 |
| i = 1, j = 2 |
| i = 1, j = 3 |
| i = 2, j = 1 |
| i = 2, j = 2 |
| i = 2, j = 3</programlisting> |
| |
| <para>It's also allowed to use clashing loop variable names |
| like:</para> |
| |
| <programlisting role="template"><#list 1..2 as i> |
| Outer: ${i} |
| <#list 10..12 as i> |
| Inner: ${i} |
| </#list> |
| Outer again: ${i} |
| </#list></programlisting> |
| |
| <programlisting role="output"> Outer: 1 |
| Inner: 10 |
| Inner: 11 |
| Inner: 12 |
| Outer again: 1 |
| Outer: 2 |
| Inner: 10 |
| Inner: 11 |
| Inner: 12 |
| Outer again: 2</programlisting> |
| </section> |
| |
| <section xml:id="ref_list_missing_element"> |
| <title>Treatment of missing (null) elements</title> |
| |
| <para>As you know by now, the <literal>list</literal> directive |
| will repeat its nested content for each element of the listed |
| value. However, it's technically possible that you have holes |
| (missing values, Java <literal>null</literal>-s) in the list of |
| elements. The nested content will executed for these |
| <quote>holes</quote> as well, but then the loop variable (the |
| variable whose name you specify after the <literal>as</literal> |
| keyword) will be missing. When FreeMarker finds that there's no |
| variable with the given name in the loop variable scope, it will |
| just fall back to a higher scopes to find it. However, this |
| fallback behavior can be problematic in this case. |
| Consider:</para> |
| |
| <programlisting role="template"><#list xs as x> |
| ${x!'Missing'} |
| </#list></programlisting> |
| |
| <para>Here, the intent of the author is to print |
| <quote>Missing</quote> for the missing elements (hopes) of |
| <literal>xs</literal>. But if accidentally there's an |
| <literal>x</literal> variable in a higher scope, like in the |
| data-model, then <literal>x</literal> will evaluate to that in |
| case the currently listed element is missing, and so it won't |
| default to <quote>Missing</quote>. To solve that, the programmers |
| should set the <literal>fallback_on_null_loop_variable</literal> |
| configuration setting to <literal>false</literal>. (Unfortunately, |
| the default must be <literal>true</literal> for backward |
| compatibility.) In that case no fallback will occur if a loop |
| variable is missing.</para> |
| </section> |
| |
| <section xml:id="ref_list_java_notes"> |
| <title>Notes for Java programmers</title> |
| |
| <para><phrase role="forProgrammers">If classic compatible mode |
| <literal>list</literal> accepts a scalar too and treats it as a |
| single-element sequence.</phrase></para> |
| |
| <para><phrase role="forProgrammers">If you pass a collection that |
| wraps an <literal>java.util.Iterator</literal> to the |
| <literal>list</literal>, you can iterate over its elements only |
| once, since <literal>Iterator</literal>s are by their nature |
| one-off objects. When you try to list a such collection variable |
| for the second time, an error will abort template |
| processing.</phrase></para> |
| </section> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_local"> |
| <title>local</title> |
| |
| <anchor xml:id="ref.directive.local"/> |
| |
| <indexterm> |
| <primary>local directive</primary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"> |
| <literal><#local <replaceable>name</replaceable>=<replaceable>value</replaceable>></literal> |
| or |
| <literal><#local <replaceable>name1</replaceable>=<replaceable>value1</replaceable> <replaceable>name2</replaceable>=<replaceable>value2</replaceable> <replaceable>... nameN</replaceable>=<replaceable>valueN</replaceable>></literal> |
| or |
| <literal><#local <replaceable>name</replaceable>> |
| <replaceable>capture this</replaceable> |
| </#local> |
| </literal> |
| </programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>name</replaceable></literal>: the |
| name of the local object in the root. It is not an expression. |
| However, it can be written as a string literal, which is useful |
| if the variable name contains reserved characters, for example |
| <literal><#local "foo-bar" = 1></literal>. Note that this |
| string literal does not expand interpolations (as |
| <literal>"${foo}"</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>=</literal>: Assignment operator, which can also |
| be one of the shorthand assignment operators |
| (<literal>++</literal>, <literal>+=</literal>, etc.), just like |
| with <link linkend="ref_directive_assign">the |
| <literal>assign</literal> directive</link>,</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>value</replaceable></literal>: the |
| value to store. Expression.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>It is similar to <link linkend="ref.directive.assign">assign |
| directive</link>, but it creates or replaces local variables. This |
| only works inside macro definitions and function definitions.</para> |
| |
| <para>For more information about variables, read this: <xref |
| linkend="dgui_misc_var"/></para> |
| |
| <note> |
| <para>A frequent mistake is trying to use |
| <literal>assign</literal> to change a local variable like: |
| <literal><#macro m><#local x = 1>${x}<#assign x = |
| 2>${x}</#macro></literal>. This prints |
| <literal>11</literal>, not <literal>12</literal>, because |
| <literal>assign</literal> creates/replaces the |
| <literal>x</literal> of the namespace that the template belongs |
| to, and doesn't change the <literal>x</literal> local variable. |
| Local variables should be always set with the <link |
| linkend="ref.directive.local"><literal>local</literal> |
| directive</link>, not just for the fist time.</para> |
| </note> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_macro"> |
| <title>macro, nested, return</title> |
| |
| <anchor xml:id="ref.directive.macro"/> |
| |
| <indexterm> |
| <primary>macro directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>nested directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>return directive</primary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"> |
| <literal><#macro <replaceable>name</replaceable> <replaceable>param1</replaceable> <replaceable>param2</replaceable> <replaceable>... paramN</replaceable>> |
| <replaceable>...</replaceable> |
| <#nested <replaceable>loopvar1</replaceable>, <replaceable>loopvar2</replaceable>, <replaceable>...</replaceable>, <replaceable>loopvarN</replaceable>> |
| <replaceable>...</replaceable> |
| <#return> |
| <replaceable>...</replaceable> |
| </#macro></literal> |
| </programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>name</replaceable></literal>: name |
| of macro variable. It's not an expression. It follows the same |
| syntax as <link linkend="dgui_template_exp_var_toplevel">like |
| top-level variable references</link>, like |
| <literal>myMacro</literal> or <literal>my\-macro</literal>. |
| However, it can also be written as a string literal, which is |
| useful if the macro name contains characters that can't be |
| specified in an identifier, for example <literal><#macro |
| "foo~bar"><replaceable>...</replaceable></literal>. Note that |
| this string literal does not expand interpolations (as |
| <literal>"${foo}"</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>param1</replaceable></literal>, |
| <literal><replaceable>param2</replaceable></literal>, ...etc.: |
| the name of the <link linkend="dgui_misc_var">local |
| variables</link> store the parameter values (not expression), |
| optionally followed by <literal>=</literal> and the default |
| value (that's an expression). The default value can even be |
| another parameter, for example <literal><#macro section title |
| label=title></literal>. The parameter name uses the same |
| syntax as <link linkend="dgui_template_exp_var_toplevel">like |
| top-level variable references</link>, so the same features and |
| restrictions apply.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>catch-all parameter</primary> |
| </indexterm><indexterm> |
| <primary>variable number of parameters</primary> |
| </indexterm><literal><replaceable>paramN</replaceable></literal>, |
| the last parameter may optionally has 3 trailing dots |
| (<literal>...</literal>), which indicates that the macro takes a |
| variable number of parameters and the parameters that doesn't |
| match any other parameters will be collected in this last |
| parameter (also called the catch-all parameter). When the macro |
| is called with named parameters, |
| <literal><replaceable>paramN</replaceable></literal> will be a |
| hash containing all of the undeclared key/value pairs passed to |
| the macro. When the macro is called using positional parameters, |
| <literal><replaceable>paramN</replaceable></literal> will be the |
| sequence of the extra parameter values. (Inside the macro, to |
| find out which was the case, you can use |
| <literal><replaceable>myCatchAllParam</replaceable>?is_sequence</literal>.)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>loopvar1</replaceable></literal>, |
| <literal><replaceable>loopvar2</replaceable></literal>, ...etc.: |
| Optional. The values of <link linkend="dgui_misc_var">loop |
| variables</link> that the <literal>nested</literal> directive |
| wants to create for the nested content. These are |
| expressions.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>The <literal>return</literal> and <literal>nested</literal> |
| directives are optional and can be used anywhere and for any times |
| between the <literal><#macro |
| <replaceable>...</replaceable>></literal> and |
| <literal></#macro></literal>.</para> |
| |
| <para>Parameters without default value must precede parameters with |
| default value |
| (<literal><replaceable>paramName</replaceable>=<replaceable>defaultValue</replaceable></literal>).</para> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>Creates a macro variable (in the current namespace, if you |
| know namespace feature). If you are new to macros and user-defined |
| directives you should read the <link |
| linkend="dgui_misc_userdefdir">the tutorial about user-defined |
| directives</link>.</para> |
| |
| <para>Macro variable stores a template fragment (called macro |
| definition body) that can be used as <link |
| linkend="ref.directive.userDefined">user-defined directive</link>. |
| The variable also stores the name of allowed parameters to the |
| user-defined directive. You must give value for all of those |
| parameters when you use the variable as directive, except for |
| parameters that has a default value. The default value will be used |
| if and only if you don't give value for the parameter when you call |
| the macro.</para> |
| |
| <para>The variable will be created at the beginning of the template; |
| it does not mater where the <literal>macro</literal> directive is |
| placed in the template. Thus, this will work:</para> |
| |
| <programlisting role="template"><#-- call the macro; the macro variable is already created: --> |
| <@test/> |
| ... |
| |
| <#-- create the macro variable: --> |
| <#macro test> |
| Test text |
| </#macro></programlisting> |
| |
| <para>However, if the macro definitions are inserted with |
| <literal>include</literal> directive, they will not be available |
| until FreeMarker has executed the <literal>include</literal> |
| directive.</para> |
| |
| <para>Example: Macro without parameters:</para> |
| |
| <programlisting role="template"><#macro test> |
| Test text |
| </#macro> |
| <#-- call the macro: --> |
| <@test/></programlisting> |
| |
| <para>Output:</para> |
| |
| <programlisting role="output"> Test text |
| </programlisting> |
| |
| <para>Example: Macro with parameters:</para> |
| |
| <programlisting role="template"><#macro test foo bar baaz> |
| Test text, and the params: ${foo}, ${bar}, ${baaz} |
| </#macro> |
| <#-- call the macro: --> |
| <@test foo="a" bar="b" baaz=5*5-2/></programlisting> |
| |
| <para>Output:</para> |
| |
| <programlisting role="output"> Test text, and the params: a, b, 23 |
| </programlisting> |
| |
| <para>Example: Macro with parameters and default parameter |
| values:</para> |
| |
| <programlisting role="template"><#macro test foo bar="Bar" baaz=-1> |
| Test text, and the params: ${foo}, ${bar}, ${baaz} |
| </#macro> |
| <@test foo="a" bar="b" baaz=5*5-2/> |
| <@test foo="a" bar="b"/> |
| <@test foo="a" baaz=5*5-2/> |
| <@test foo="a"/></programlisting> |
| |
| <para>Output:</para> |
| |
| <programlisting role="output"> Test text, and the params: a, b, 23 |
| Test text, and the params: a, b, -1 |
| Test text, and the params: a, Bar, 23 |
| Test text, and the params: a, Bar, -1 |
| </programlisting> |
| |
| <para>Example: A more complex macro.</para> |
| |
| <programlisting role="template"><#macro list title items> |
| <p>${title?cap_first}: |
| <ul> |
| <#list items as x> |
| <li>${x?cap_first} |
| </#list> |
| </ul> |
| </#macro> |
| <@list items=["mouse", "elephant", "python"] title="Animals"/></programlisting> |
| |
| <para>Output:</para> |
| |
| <programlisting role="output"> <p>Animals: |
| <ul> |
| <li>Mouse |
| <li>Elephant |
| <li>Python |
| </ul> |
| </programlisting> |
| |
| <para>Example: A macro with support for a variable number of named |
| parameters:</para> |
| |
| <programlisting role="template"><#macro img src extra...> |
| <img src="/myapp${src?ensure_starts_with('/')}" |
| <#list extra as attrName, attrVal> |
| ${attrName}="${attrVal}" |
| </#list> |
| > |
| </#macro> |
| <@img src="/images/test.png" width=100 height=50 alt="Test"/></programlisting> |
| |
| <para>Output:</para> |
| |
| <programlisting role="output"> <img src="/context/images/test.png" |
| alt="Test" |
| height="50" |
| width="100" |
| ></programlisting> |
| |
| <para>Example: A macro that supports a variable number of positional |
| parameters, regardless if it uses named or positional parameter |
| passing:</para> |
| |
| <programlisting role="template"><#macro m a b ext...> |
| a = ${a} |
| b = ${b} |
| <#if ext?is_sequence> |
| <#list ext as e> |
| ${e?index} = ${e} |
| </#list> |
| <#else> |
| <#list ext as k, v> |
| ${k} = ${v} |
| </#list> |
| </#if> |
| </#macro> |
| |
| <@m 1 2 3 4 5 /> |
| |
| <@m a=1 b=2 c=3 d=4 e=5 data\-foo=6 myns\:bar=7 /></programlisting> |
| |
| <para>Output:</para> |
| |
| <programlisting role="output"> a = 1 |
| b = 2 |
| 0 = 3 |
| 1 = 4 |
| 2 = 5 |
| |
| a = 1 |
| b = 2 |
| c = 3 |
| d = 4 |
| e = 5 |
| data-foo=6 |
| myns:bar=7</programlisting> |
| |
| <warning> |
| <para>Before FreeMarker 2.3.30, named catch-all parameters are |
| unordered, that is, you don't know what order will they be |
| enumerated. Only starting from 2.3.30 are they returned in the |
| same order as they were passed in.</para> |
| </warning> |
| |
| <section> |
| <title>nested</title> |
| |
| <anchor xml:id="ref.directive.nested"/> |
| |
| <para>The <literal>nested</literal> directive executes the |
| template fragment between the start-tag and end-tags of the |
| user-defined directive. The nested part can contain anything what |
| is valid in templates; interpolations, directives, ...etc. It is |
| executed in the context where the macro was called from, rather |
| than in the context of the macro definition body. Thus, for |
| example, you don't see the local variables of the macro in the |
| nested part. If you don't call the <literal>nested</literal> |
| directive, the part between the start-tag and end-tags of the |
| user-defined directive will be ignored.</para> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template"><#macro do_twice> |
| 1. <#nested> |
| 2. <#nested> |
| </#macro> |
| <@do_twice>something</@do_twice></programlisting> |
| |
| <programlisting role="output"> 1. something |
| 2. something |
| </programlisting> |
| |
| <para>The nested directive can create loop variables for the |
| nested content. For example:</para> |
| |
| <programlisting role="template"><#macro do_thrice> |
| <#nested <emphasis>1</emphasis>> |
| <#nested <emphasis>2</emphasis>> |
| <#nested <emphasis>3</emphasis>> |
| </#macro> |
| <@do_thrice <emphasis>; x</emphasis>> |
| ${<emphasis>x</emphasis>} Anything. |
| </@do_thrice></programlisting> |
| |
| <programlisting role="output"> 1 Anything. |
| 2 Anything. |
| 3 Anything. |
| </programlisting> |
| |
| <para>A more complex example:</para> |
| |
| <programlisting role="template"><#macro repeat count> |
| <#list 1..count as x> |
| <#nested <emphasis>x, x/2, x==count</emphasis>> |
| </#list> |
| </#macro> |
| <@repeat count=4 ; <emphasis>c, halfc, last</emphasis>> |
| ${<emphasis>c</emphasis>}. ${<emphasis>halfc</emphasis>}<#if <emphasis>last</emphasis>> Last!</#if> |
| </@repeat></programlisting> |
| |
| <programlisting role="output"> 1. 0.5 |
| 2. 1 |
| 3. 1.5 |
| 4. 2 Last! |
| </programlisting> |
| </section> |
| |
| <section> |
| <title>return</title> |
| |
| <anchor xml:id="ref.directive.macro.return"/> |
| |
| <para>With the <literal>return</literal> directive, you can leave |
| a macro or function definition body anywhere. Example:</para> |
| |
| <programlisting role="template"><#macro test> |
| Test text |
| <#return> |
| Will not be printed. |
| </#macro> |
| <@test/></programlisting> |
| |
| <programlisting role="output"> Test text |
| </programlisting> |
| </section> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_noautoesc"> |
| <title>noautoesc</title> |
| |
| <anchor xml:id="ref.directive.noautoesc"/> |
| |
| <indexterm> |
| <primary>noautoesc directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>auto-escaping</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>escaping</primary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"><literal><#noautoesc> |
| <replaceable>...</replaceable> |
| </#noautoesc></literal> |
| </programlisting> |
| |
| <para>Camel case name variant: <literal>noAutoEsc</literal></para> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>Disables <link |
| linkend="dgui_misc_autoescaping">auto-escaping</link> in the nested |
| section. Note that to prevent escaping for just a single |
| <literal>${<replaceable>expression</replaceable>}</literal> you |
| should use |
| <literal>${<replaceable>expression</replaceable>?no_esc}</literal> |
| instead.</para> |
| |
| <para>This directive only has effect on the section that is |
| literally (as in the text editor) inside the nested bock, not on the |
| parts that are called/included from there.</para> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template"><#ftl output_format="XML"> |
| ${"&"} |
| <#noautoesc> |
| ${"&"} |
| ... |
| ${"&"} |
| </#noautoesc> |
| ${"&"}</programlisting> |
| |
| <programlisting role="output">&amp; |
| & |
| ... |
| & |
| &amp;</programlisting> |
| |
| <para><literal>noautoesc</literal> can be used regardless of what |
| the current <link |
| linkend="dgui_misc_autoescaping_outputformat">output format</link> |
| is (unlike the <link |
| linkend="ref_directive_autoesc"><literal>autoesc</literal> |
| directive</link>).</para> |
| |
| <para><literal>noautoesc</literal> can also be used nested into |
| <link linkend="ref_directive_autoesc"><literal>autoesc</literal> |
| directive</link> to re-enable escaping.</para> |
| |
| <para><literal>noautoesc</literal> can be used on places where |
| auto-escaping is already disabled, such as even inside another |
| <literal>noautoesc</literal> block. Doing so is redundant but |
| allowed.</para> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_noparse"> |
| <title>noparse</title> |
| |
| <anchor xml:id="ref.directive.noparse"/> |
| |
| <indexterm> |
| <primary>noparse directive</primary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"> |
| <literal><#noparse> |
| <replaceable>...</replaceable> |
| </#noparse></literal> |
| </programlisting> |
| |
| <para>Camel case name variant: <literal>noParse</literal></para> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>FreeMarker will not search FTL tags and interpolations and |
| other special character sequences in the body of this directive, |
| except the noparse end-tag.</para> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template">Example: |
| -------- |
| |
| <emphasis><#noparse></emphasis> |
| <#list animals as animal> |
| <tr><td>${animal.name}<td>${animal.price} Euros |
| </#list> |
| <emphasis></#noparse></emphasis></programlisting> |
| |
| <programlisting role="output">Example: |
| -------- |
| |
| <#list animals as animal> |
| <tr><td>${animal.name}<td>${animal.price} Euros |
| </#list> |
| </programlisting> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_nt"> |
| <title>nt</title> |
| |
| <anchor xml:id="ref.directive.nt"/> |
| |
| <indexterm> |
| <primary>nt directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>trimmer directives</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>white-space removal</primary> |
| |
| <secondary>trimming</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>white-space removal</primary> |
| |
| <secondary>stripping</secondary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"> |
| <literal><#nt></literal> |
| </programlisting> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para><quote>No Trim</quote>. This directive disables <link |
| linkend="dgui_misc_whitespace_stripping">white-space |
| stripping</link> in the line where it occurs. It also disables the |
| effect of other trim directives occurring in the same line (the |
| effect of <literal>t</literal>, <literal>rt</literal>, |
| <literal>lt</literal>).</para> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_outputformat"> |
| <title>outputformat</title> |
| |
| <anchor xml:id="ref.directive.outputformat"/> |
| |
| <indexterm> |
| <primary>outputformat directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>auto-escaping</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>escaping</primary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"><literal><#outputformat <replaceable>formatName</replaceable>> |
| <replaceable>...</replaceable> |
| </#outputFormat></literal> |
| </programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>formatName</replaceable></literal>: |
| A string constant; can't contain runtime expressions! This is |
| the name of the output format, like <literal>"HTML"</literal>, |
| <literal>"XML"</literal>, etc.; see the <link |
| linkend="topic.predefinedOutputFormats">table of the predefined |
| output formats here</link>. The referred output format must be |
| known by the <literal>Configuration</literal>, or else a <link |
| linkend="gloss.parseTimeError">parse-time error</link> will |
| occur. The name can also be like |
| <literal>"<replaceable>outerFormatName</replaceable>{<replaceable>innerFormatName</replaceable>}"</literal>, |
| or |
| <literal>"{<replaceable>innerFormatName</replaceable>}"</literal>; |
| <link linkend="topic.combinedOutputFormats">see combined output |
| formats later</link>.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Camel case name variant: <literal>outputFormat</literal><note> |
| <para><literal>outputformat</literal> exists since FreeMarker |
| 2.3.24.</para> |
| </note></para> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>Sets the <link |
| linkend="dgui_misc_autoescaping_outputformat">output format</link> |
| to the specified one, inside the nested block. At the end of the |
| block, the earlier output format is restored.</para> |
| |
| <para>This directive only has effect on the section that is |
| literally (as in the text editor) inside the nested bock, not on the |
| parts that are called/included from there.</para> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template"><#ftl output_format="XML"> |
| XML escaping: ${"&{}"} |
| <#outputformat "RTF"> |
| RTF escaping: ${"&{}"} |
| </#outputformat> |
| <#outputformat "plainText"> |
| No escsaping: ${"&{}"} |
| </#outputformat> |
| XML escsaping: ${"&{}"}</programlisting> |
| |
| <programlisting role="output">XML escsaping: &amp;{} |
| RTF escaping: &\{\} |
| No escsaping: &{} |
| XML escsaping: &amp;{}</programlisting> |
| |
| <simplesect xml:id="topic.combinedOutputFormats"> |
| <title>Combined (nested) output formats</title> |
| |
| <para>When <literal>outputformat</literal>-s are nested into each |
| other, normally, only the innermost output format will count. For |
| example:</para> |
| |
| <programlisting role="template"><#ftl output_format="XML"> |
| ${"'{}"} |
| <#outputformat "HTML"> |
| ${"'{}"} |
| <#outputformat "RTF"> |
| ${"'{}"} |
| </#outputformat> |
| </#outputformat></programlisting> |
| |
| <programlisting role="output">&apos;{} |
| &#39;{} |
| '\{\}</programlisting> |
| |
| <para>But sometimes you want all enclosing output format escaping |
| to be applied at once. In that case the 2nd |
| <literal>${<replaceable>...</replaceable>}</literal> above should |
| be escaped with <literal>"HTML"</literal> and then with |
| <literal>"XML"</literal>, and the 3rd |
| <literal>${<replaceable>...</replaceable>}</literal> should be |
| escaped with <literal>"RTF"</literal> and then with |
| <literal>"HTML"</literal> and then with <literal>"XML"</literal>. |
| These are called combined output formats, and can be referred by |
| names like <literal>"XML{HTML}"</literal> and |
| <literal>"XML{HTML{RTF}}"</literal>, respectively. We could use |
| these names in the earlier two <literal>outputformat</literal> |
| calls, however, there's a shorthand where you inherit the part |
| outside the <literal>{<replaceable>...</replaceable>}</literal> |
| from the enclosing output format:</para> |
| |
| <programlisting role="template"><#ftl outputFormat="XML"> |
| ${"'{}"} |
| <#outputFormat "{HTML}"><#-- Same as "XML{HTML}" --> |
| ${"'{}"} |
| <#outputFormat '{RTF}'><#-- Same as "XML{HTML{RTF}}" --> |
| ${"'{}"} |
| </#outputFormat> |
| </#outputFormat> |
| </programlisting> |
| |
| <programlisting role="output">&apos;{} |
| &amp;#39;{} |
| &amp;#39;\{\}</programlisting> |
| </simplesect> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_setting"> |
| <title>setting</title> |
| |
| <anchor xml:id="ref.directive.setting"/> |
| |
| <indexterm> |
| <primary>setting directive</primary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"><literal><#setting <replaceable>name</replaceable>=<replaceable>value</replaceable>></literal></programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>name</replaceable></literal>: name |
| of the setting. It is not expression!</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>value</replaceable></literal>: New |
| value of the setting. Expression</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>Sets a setting for the further part of processing. Settings |
| are values that influence the behavior of FreeMarker. The new value |
| will be present only in the template processing where it was set, |
| and does not touch the template itself. The initial value of |
| settings is set by the programmer <phrase |
| role="forProgrammers">(see: <xref |
| linkend="pgui_config_settings"/>)</phrase>.</para> |
| |
| <para>The supported settings are:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><indexterm> |
| <primary>locale</primary> |
| </indexterm><literal>locale</literal>: The locale (language) |
| of the output. It can influence the presentation format of |
| numbers, dates, etc. The value is a string which consist of a |
| language code (lowercase two-letter ISO-639 code) plus optional |
| county code (uppercase two-letter ISO-3166 code) separated from |
| the language code with underscore, and if we have specified the |
| country then an optional variant code (not standardized) |
| separated from the country with underscore. Examples of valid |
| values: <literal>en</literal>, <literal>en_US</literal>, |
| <literal>en_US_MAC</literal>. FreeMarker will try to use the |
| most specific available locale, so if you specify |
| <literal>en_US_MAC</literal> but that is not known, then it will |
| try <literal>en_US</literal>, and then <literal>en</literal>, |
| and then the default locale of the computer (which is may set by |
| the programmer).</para> |
| </listitem> |
| |
| <listitem> |
| <para xml:id="ref.setting.number_format"><indexterm> |
| <primary>number_format</primary> |
| </indexterm><indexterm> |
| <primary>format</primary> |
| |
| <secondary>number</secondary> |
| </indexterm><literal>number_format</literal>: The number |
| format that is used to convert numbers to strings when no |
| explicit format is specified. Can be one of the |
| following:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Predefined values defined by the Java platform: |
| <literal>number</literal> (the default), |
| <literal>currency</literal>, or |
| <literal>percent</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>c</literal> since 2.3.24 (was called |
| <literal>computer</literal> before that, which still works), |
| which formats like <link linkend="ref_builtin_c">the |
| <literal>c</literal> built-in</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Format pattern written in <link |
| xlink:href="http://java.sun.com/j2se/1.4/docs/api/java/text/DecimalFormat.html">Java |
| decimal number format syntax</link>, for example |
| <literal>0.###</literal>. FreeMarker <link |
| linkend="topic.extendedJavaDecimalFormat">extends this |
| format</link> to allow specifying rounding mode, symbols |
| used, etc.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Values starting with <literal>@</literal> that's also |
| followed by a letter, refer to a <link |
| linkend="pgui_config_custom_formats">custom format</link>. |
| For example, <literal>"@price"</literal> refers to the |
| custom format registered with the <literal>"price"</literal> |
| name. The custom format name is possibly followed by space |
| or <literal>_</literal> and then format parameters, whose |
| interpretation depends on the custom format. For backward |
| compatibility, the initial <literal>@</literal> only has |
| this new meaning if either <link |
| linkend="pgui_config_incompatible_improvements_how_to_set">the |
| <literal>incompatible_improvements</literal> setting</link> |
| is at least 2.3.24, or there's any custom formats defined. |
| When the initial <literal>@</literal> isn't followed by a |
| letter (any UNICODE letter), it's never treated as a |
| reference to a custom format.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>boolean_format</primary> |
| </indexterm><indexterm> |
| <primary>format</primary> |
| |
| <secondary>boolean</secondary> |
| </indexterm><literal>boolean_format</literal>: The |
| comma-separated pair of strings for representing true and false |
| values respectively that is used to convert booleans to strings |
| when no explicit format is specified (like in |
| <literal>${<replaceable>booleanValue</replaceable>}</literal>). |
| Note that currently white space isn't removed from this string, |
| so don't put space after the comma. Default value is |
| <literal>"true,false"</literal>, but FreeMarker will deny using |
| that particular value for |
| <literal>${<replaceable>booleanValue</replaceable>}</literal>, |
| and requires using |
| <literal>${<replaceable>booleanValue</replaceable>?c}</literal> |
| instead (this works since 2.3.21). For any other value, like |
| <literal>"Y,N"</literal>, |
| <literal>${<replaceable>booleanValue</replaceable>}</literal> |
| will work. See also:<link |
| linkend="ref_builtin_string_for_boolean"><literal>string</literal> |
| built-in</link>.</para> |
| </listitem> |
| |
| <listitem xml:id="topic.dateTimeFormatSettings"> |
| <para xml:id="topic_date_format_settings"><indexterm> |
| <primary>date_format</primary> |
| </indexterm><indexterm> |
| <primary>time_format</primary> |
| </indexterm><indexterm> |
| <primary>datetime_format</primary> |
| </indexterm><indexterm> |
| <primary>format</primary> |
| |
| <secondary>date</secondary> |
| </indexterm><indexterm> |
| <primary>XML Schema date rendering</primary> |
| </indexterm><indexterm> |
| <primary>XML Schema time rendering</primary> |
| </indexterm><indexterm> |
| <primary>XML Schema dateTime rendering</primary> |
| </indexterm><indexterm> |
| <primary>ISO 8601</primary> |
| </indexterm> <literal>date_format</literal>, |
| <literal>time_format</literal>, |
| <literal>datetime_format</literal>: The format used to convert |
| date/time/date-time values (Java |
| <literal>java.util.Date</literal>-s and its subclasses) to |
| strings when no explicit format is specified via the <link |
| linkend="ref_builtin_string_for_date"><literal>string</literal> |
| built-in</link> (or otherwise), as in the case of |
| <literal>${someDate}</literal>. The |
| <literal>date_format</literal> setting only effects the |
| formatting of date values that store no time part, |
| <literal>time_format</literal> only effects the formatting of |
| times that store no date part, and |
| <literal>datetime_format</literal> only effects formatting of |
| date-time values. These settings also effects what format do |
| <link |
| linkend="ref_builtin_string_date"><literal>?time</literal>, |
| <literal>?date</literal>, and |
| <literal>?datetime</literal></link> expect when it's applied on |
| a string value.</para> |
| |
| <para><remark>The following part is copy-pasted from the JavaDoc |
| of Configurable.setDateTimeFormat(String); keep them in sync. |
| </remark>The possible setting values are (the quotation marks |
| aren't part of the value itself):</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Patterns <link |
| xlink:href="http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html">accepted |
| by Java's <literal>SimpleDateFormat</literal></link>, for |
| example <literal>"dd.MM.yyyy HH:mm:ss"</literal> (where |
| <literal>"HH"</literal> means 0-23 hours) or |
| <literal>"MM/dd/yyyy hh:mm:ss a"</literal> (where |
| <literal>"a"</literal> prints AM or PM, if the current |
| language is English).</para> |
| |
| <warning> |
| <para>Be careful <emphasis>not</emphasis> to use |
| <literal>YYYY</literal> (upper case, means <quote>week |
| year</quote>) instead of <literal>yyyy</literal> (lower |
| case, means year)! It's an easy mistake to do, and hard to |
| notice during testing, as <quote>week year</quote> only |
| differs from <quote>year</quote> near the edge of |
| years.</para> |
| </warning> |
| </listitem> |
| |
| <listitem> |
| <para><literal>"xs"</literal> for XML Schema format, or |
| <literal>"iso"</literal> for ISO 8601:2004 format. These |
| formats allow various additional options, separated with |
| space, like in <literal>"iso m nz"</literal> (or with |
| <literal>_</literal>, like in <literal>"iso_m_nz"</literal>; |
| this is useful in a case like |
| <literal>lastModified?string.iso_m_nz</literal>). The |
| options and their meanings are:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Accuracy options:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>ms</literal>: Milliseconds, always |
| shown with all 3 digits, even if it's all 0-s. |
| Example: <literal>13:45:05.800</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>s</literal>: Seconds (fraction |
| seconds are dropped even if non-0), like |
| <literal>13:45:05</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>m</literal>: Minutes, like |
| <literal>13:45</literal>. This isn't allowed for |
| <literal>"xs"</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>h</literal>: Hours, like |
| <literal>13</literal>. This isn't allowed for |
| <literal>"xs"</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Neither: Up to millisecond accuracy, but |
| trailing millisecond 0-s are removed, also the whole |
| milliseconds part if it would be 0 otherwise. |
| Example: <literal>13:45:05.8</literal></para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Time zone offset visibility options:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>fz</literal>: <quote>Force |
| Zone</quote>, always show time zone offset (even for |
| for <literal>java.sql.Date</literal> and |
| <literal>java.sql.Time</literal> values). But, |
| because ISO 8601 doesn't allow for dates (means date |
| without time of the day) to show the zone offset, |
| this option will have no effect in the case of |
| <literal>"iso"</literal> with dates.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>nz</literal>: <quote>No Zone</quote>, |
| never show time zone offset</para> |
| </listitem> |
| |
| <listitem> |
| <para>Neither: Always show time zone offset, except |
| for <literal>java.sql.Date</literal> and |
| <literal>java.sql.Time</literal>, and for |
| <literal>"iso"</literal> date values.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Time zone options:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>u</literal>: Use UTC instead of what |
| the <literal>time_zone</literal> setting suggests. |
| However, <literal>java.sql.Date</literal> and |
| <literal>java.sql.Time</literal> aren't affected by |
| this (see |
| <literal>sql_date_and_time_time_zone</literal> to |
| understand why)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>fu</literal>: <quote>Force |
| UTC</quote>, that is, use UTC instead of what the |
| <literal>time_zone</literal> or the |
| <literal>sql_date_and_time_time_zone</literal> |
| setting suggests. This also effects |
| <literal>java.sql.Date</literal> and |
| <literal>java.sql.Time</literal> values</para> |
| </listitem> |
| |
| <listitem> |
| <para>Neither: Use the time zone suggested by the |
| <literal>time_zone</literal> or the |
| <literal>sql_date_and_time_time_zone</literal> |
| configuration setting</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Options from the same category are mutually exclusive, |
| like using <literal>m</literal> and <literal>s</literal> |
| together is an error.</para> |
| |
| <para>The options can be specified in any order.</para> |
| |
| <para>The accuracy and time zone offset visibility options |
| don't influence parsing, only formatting. For example, even |
| if you use <literal>"iso m nz"</literal>, |
| <literal>"2012-01-01T15:30:05.125+01"</literal> will be |
| parsed successfully and with milliseconds accuracy. The time |
| zone options (like <literal>"u"</literal>) influence what |
| time zone is chosen only when parsing a string that doesn't |
| contain time zone offset.</para> |
| |
| <para>Parsing with <literal>"iso"</literal> understands both |
| <quote>extend format</quote> and <quote>basic |
| format</quote>, like <literal>20141225T235018</literal>. It |
| doesn't, however, support the parsing of all kind of ISO |
| 8601 strings: if there's a date part, it must use year, |
| month and day of the month values (not week of the year), |
| and the day can't be omitted.</para> |
| |
| <para>The output of <literal>"iso"</literal> is deliberately |
| so that it's also a good representation of the value with |
| XML Schema format, except for 0 and negative years, where |
| it's impossible. Also note that the time zone offset is |
| omitted for date values in the <literal>"iso"</literal> |
| format, while it's preserved for the <literal>"xs"</literal> |
| format.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>"short"</literal>, |
| <literal>"medium"</literal>, <literal>"long"</literal>, or |
| <literal>"full"</literal>, which has locale-dependent |
| meaning defined by the Java platform (see in the <link |
| xlink:href="http://docs.oracle.com/javase/7/docs/api/java/text/DateFormat.html">documentation |
| of <literal>java.text.DateFormat</literal></link>). For |
| date-time values, you can specify the length of the date and |
| time part independently, be separating them with |
| <literal>_</literal>, like |
| <literal>"short_medium"</literal>. |
| (<literal>"medium"</literal> means |
| <literal>"medium_medium"</literal> for date-time |
| values.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Values starting with <literal>@</literal> that's also |
| followed by a letter, refer to a <link |
| linkend="pgui_config_custom_formats">custom format</link>, |
| like <literal>"@worklog"</literal> refers to the custom |
| format registered with the <literal>"worklog"</literal> |
| name. The format name is possibly followed by space or |
| <literal>_</literal> and then format parameters, whose |
| interpretation depends on the custom format. For backward |
| compatibility, the initial <literal>@</literal> only has |
| this new meaning if either <link |
| linkend="pgui_config_incompatible_improvements_how_to_set">the |
| <literal>incompatible_improvements</literal> setting</link> |
| is at least 2.3.24, or there's any custom formats defined. |
| When the initial <literal>@</literal> isn't followed by a |
| letter (any UNICODE letter), it's never treated as a |
| reference to a custom format.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>time_zone</primary> |
| </indexterm><literal>time_zone</literal>: The name of the time |
| zone used to format times for display. As with all settings, the |
| default is chosen by the programmers when they set up FreeMarker |
| (<phrase role="forProgrammers">via the |
| <literal>Configuration</literal> class</phrase>), but it's most |
| often the default time zone of the JVM. Can be any value that is |
| accepted by <link |
| xlink:href="http://docs.oracle.com/javase/7/docs/api/java/util/TimeZone.html">Java |
| TimeZone API</link>, or <literal>"JVM default"</literal> (since |
| FreeMarker 2.3.21) to use the JVM default time zone. Examples: |
| <literal>"GMT"</literal>, <literal>"GMT+2"</literal>, |
| <literal>"GMT-1:30"</literal>, <literal>"CET"</literal>, |
| <literal>"PST"</literal>, |
| <literal>"America/Los_Angeles"</literal>.</para> |
| |
| <warning> |
| <para>If you change this setting from its default value, you |
| should certainly also set |
| <literal>sql_date_and_time_time_zone</literal> to "JVM |
| default". <phrase role="forProgrammers">See more in the Java |
| API documentation of |
| <literal>Configurable.setSQLDateAndTimeTimeZone(TimeZone)</literal>.</phrase></para> |
| </warning> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>time_zone</primary> |
| </indexterm><indexterm> |
| <primary>JDBC time zone</primary> |
| </indexterm><literal>sql_date_and_time_time_zone</literal> |
| (since FreeMarker 2.3.21): This handles a highly technical |
| issue, so it should usually be set from the Java code by the |
| programmers. <phrase role="forProgrammers">For programmers: If |
| this is set to non-<literal>null</literal>, for date-only and |
| time-only values coming from SQL database (more precisely, for |
| <literal>java.sql.Date</literal> and |
| <literal>java.sql.Time</literal> objects) FreeMarker will use |
| this time zone instead of the time zone specified by the |
| <literal>time_zone</literal> FreeMarker setting. See more in the |
| Java API documentation of |
| <literal>Configurable.setSQLDateAndTimeTimeZone(TimeZone)</literal>.</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>c_format</primary> |
| </indexterm><literal>c_format</literal> (since FreeMarker |
| 2.3.32): Sets what format to use when formatting for computer |
| consumption, like <literal>"JavaScript or JSON"</literal>. |
| Mostly prominently this affects the <link |
| linkend="ref_builtin_c"><literal>c</literal> built-in</link>, |
| hence the name. See valid values and their meaning here: <xref |
| linkend="dgui_misc_computer_vs_human_format"/>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>url_escaping_charset</primary> |
| </indexterm><literal>url_escaping_charset</literal>: The |
| charset used for URL escaping (e.g. for |
| <literal>${foo?url}</literal>) to calculate the escaped |
| (<literal>%<replaceable>XX</replaceable></literal>) parts. |
| Usually the framework that encloses FreeMarker should set it, so |
| you hardly ever should set this setting in templates. <phrase |
| role="forProgrammers">(Programmers can read more about this |
| <link |
| linkend="pgui_misc_charset">here...</link>)</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>output_encoding</primary> |
| </indexterm><literal>output_encoding</literal>: Tells |
| FreeMarker what the charset of the output is. As FreeMarker |
| outputs a stream of UNICODE characters (<phrase |
| role="forProgrammers">it writes into a |
| <literal>java.io.Writer</literal></phrase>), it's not affected |
| by the output encoding, but some macros/functions and built-ins |
| may want to use this information.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>classic_compatible</primary> |
| </indexterm><literal>classic_compatible</literal>: Used for |
| better compatibility with very old FreeMarker versions (mostly |
| 1.7.x). See the documentation of |
| <literal>freemarker.template.Configurable.isClassicCompatible()</literal> |
| for more information.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Example: Assume that the initial locale of template is |
| <literal>de_DE</literal> (German). Then this:</para> |
| |
| <programlisting role="template">${1.2} |
| <#setting locale="en_US"> |
| ${1.2}</programlisting> |
| |
| <para>will output this:</para> |
| |
| <programlisting role="output">1,2 |
| 1.2</programlisting> |
| |
| <para>because German people use the comma as their decimal |
| separator, while US people use the dot.</para> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_stop"> |
| <title>stop</title> |
| |
| <anchor xml:id="ref.directive.stop"/> |
| |
| <indexterm> |
| <primary>stop directive</primary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"><literal><#stop></literal> |
| or |
| <literal><#stop <replaceable>reason</replaceable>></literal> |
| </programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>reason</replaceable></literal>: |
| Informative message that describes the reason of the terminating |
| error. Expression, must evaluate to a string.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>Aborts template processing with the given (optional) error |
| message. <emphasis>This must not be used for ending template |
| processing in normal situations!</emphasis> The caller of the |
| FreeMarker template will see this as a failed template rendering, |
| not as a normally finished one.</para> |
| |
| <para><phrase role="forProgrammers">This directive throws a |
| <literal>StopException</literal>, and the |
| <literal>StopException</literal> will hold the value of the reason |
| parameter.</phrase></para> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_switch"> |
| <title>switch, case, default, break</title> |
| |
| <anchor xml:id="ref.directive.switch"/> |
| |
| <anchor xml:id="ref.directive.case"/> |
| |
| <anchor xml:id="ref.directive.default"/> |
| |
| <anchor xml:id="ref.directive.switch.break"/> |
| |
| <indexterm> |
| <primary>switch directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>case directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>default directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>break directive</primary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"> |
| <literal><#switch <replaceable>value</replaceable>> |
| <#case <replaceable>refValue1</replaceable>> |
| <replaceable>...</replaceable> |
| <#break> |
| <#case <replaceable>refValue2</replaceable>> |
| <replaceable>...</replaceable> |
| <#break> |
| <replaceable>...</replaceable> |
| <#case <replaceable>refValueN</replaceable>> |
| <replaceable>...</replaceable> |
| <#break> |
| <#default> |
| <replaceable>...</replaceable> |
| </#switch> |
| </literal> |
| </programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>value</replaceable></literal>, |
| <literal><replaceable>refValue1</replaceable></literal>, etc.: |
| Expressions evaluates to scalars of the same type.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>The <literal>break</literal>-s and <literal>default</literal> |
| are optional.</para> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>The usage of this directive is not recommended, as it's |
| error-prone because of the fall-through behavior. Use <link |
| linkend="ref.directive.elseif"><literal>elseif</literal></link>-s |
| instead unless you want to exploit the fall-through behavior.</para> |
| |
| <para>Switch is used to choose a fragment of template depending on |
| the value of an expression:</para> |
| |
| <programlisting role="template"><#switch animal.size> |
| <#case "small"> |
| This will be processed if it is small |
| <#break> |
| <#case "medium"> |
| This will be processed if it is medium |
| <#break> |
| <#case "large"> |
| This will be processed if it is large |
| <#break> |
| <#default> |
| This will be processed if it is neither |
| </#switch></programlisting> |
| |
| <para>Inside the <literal>switch</literal> must be one or more |
| <literal><#case <replaceable>value</replaceable>></literal>, |
| and after all such <literal>case</literal> tags optionally one |
| <literal><#default></literal>. When FM reaches the |
| <literal>switch</literal> directive, it chooses a |
| <literal>case</literal> directive where |
| <literal><replaceable>refValue</replaceable></literal> equals with |
| <literal><replaceable>value</replaceable></literal> and continues |
| the processing of the template there. If there is no |
| <literal>case</literal> directive with appropriate value then it |
| continues processing at the <literal>default</literal> directive if |
| that exists, otherwise it continues the processing after the end-tag |
| of <literal>switch</literal>. And now comes the confusing thing: |
| when it has chosen a <literal>case</literal> directive, it will |
| continue the processing there, and will go ahead until it reaches a |
| <literal>break</literal> directive. That is, it will not |
| automatically leave the <literal>switch</literal> directive when it |
| reaches another <literal>case</literal> directive or the |
| <literal><#default></literal> tag. Example:</para> |
| |
| <programlisting role="template"><#switch x> |
| <#case 1> |
| 1 |
| <#case 2> |
| 2 |
| <#default> |
| d |
| </#switch></programlisting> |
| |
| <para>If <literal>x</literal> is 1, then it will print 1 2 d; if |
| <literal>x</literal> is 2 then it will print 2 d; if |
| <literal>x</literal> is 3 then it will print d. This is the |
| mentioned fall-through behavior. The <literal>break</literal> tag |
| instructs FM to immediately skip past the <literal>switch</literal> |
| end-tag.</para> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_t"> |
| <title>t, lt, rt</title> |
| |
| <anchor xml:id="ref.directive.t"/> |
| |
| <anchor xml:id="ref.directive.lt"/> |
| |
| <anchor xml:id="ref.directive.rt"/> |
| |
| <indexterm> |
| <primary>t directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>lt directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>rt directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>trimmer directives</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>white-space removal</primary> |
| |
| <secondary>trimming</secondary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"> |
| <literal><#t></literal> |
| |
| <literal><#lt></literal> |
| |
| <literal><#rt></literal></programlisting> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>These directives, instruct FreeMarker to ignore certain |
| white-space in the line of the tag:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>t</literal> (for trim): Ignore all leading and |
| trailing white-space in this line.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>lt</literal> (for left trim): Ignore all leading |
| white-space in this line.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>rt</literal> (for right trim): Ignore all |
| trailing white-space in this line.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>where:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><quote>leading white-space</quote> means all space and tab |
| (and other character that are white-space according to <link |
| linkend="gloss.unicode">UNICODE</link>, except <link |
| linkend="gloss.lineBreak">line breaks</link>) before the first |
| non-white-space character of the line.</para> |
| </listitem> |
| |
| <listitem> |
| <para><quote>trailing white-space</quote> means all space and |
| tab (and other character that are white-space according to <link |
| linkend="gloss.unicode">UNICODE</link>, except line breaks) |
| after the last non-white-space character of the line, |
| <emphasis>and</emphasis> the line break at the end of the |
| line.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>It is important to understand that these directives examine |
| the template itself, and <emphasis>not</emphasis> the output what |
| the template generates when you merge it with the data-model. |
| <phrase role="forProgrammers">(That is, the white-space removal |
| happens on parse time.)</phrase></para> |
| |
| <para>For example this:</para> |
| |
| <programlisting role="template">-- |
| 1 <#t> |
| 2<#t> |
| 3<#lt> |
| 4 |
| 5<#rt> |
| 6 |
| -- |
| </programlisting> |
| |
| <para>will output this:</para> |
| |
| <programlisting role="output">-- |
| 1 23 |
| 4 |
| 5 6 |
| --</programlisting> |
| |
| <para>The placement of these directives inside the line has no |
| importance. That is, the effect will be the same regardless if you |
| put the directive at the beginning of the line, or at the end of the |
| line, or in the middle of the line.</para> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_userDefined"> |
| <title>User-defined directive (<@...>)</title> |
| |
| <anchor xml:id="ref.directive.userDefined"/> |
| |
| <indexterm> |
| <primary>user-defined directive</primary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"> |
| <literal><@<replaceable>user_def_dir_exp</replaceable> <replaceable>param1</replaceable>=<replaceable>val1</replaceable> <replaceable>param2</replaceable>=<replaceable>val2</replaceable> <replaceable>...</replaceable> <replaceable>paramN</replaceable>=<replaceable>valN</replaceable>/></literal> |
| (Note the XML-style <literal>/</literal> before the <literal>></literal>) |
| or if you need loop variables (<link |
| linkend="ref_directive_userDefined_loopVar">more details...</link>) |
| <literal><@<replaceable>user_def_dir_exp</replaceable> <replaceable>param1</replaceable>=<replaceable>val1</replaceable> <replaceable>param2</replaceable>=<replaceable>val2</replaceable> <replaceable>...</replaceable> <replaceable>paramN</replaceable>=<replaceable>valN</replaceable> ; <replaceable>lv1</replaceable>, <replaceable>lv2</replaceable>, <replaceable>...</replaceable>, <replaceable>lvN</replaceable>/></literal> |
| |
| Or the same as the above two but with end-tag (<link |
| linkend="ref_directive_userDefined_entTag">more details...</link>): |
| |
| <literal><@<replaceable>user_def_dir_exp</replaceable> <replaceable>...</replaceable>> |
| ... |
| </@<replaceable>user_def_dir_exp</replaceable>></literal> |
| or |
| <literal><@<replaceable>user_def_dir_exp</replaceable> <replaceable>...</replaceable>> |
| ... |
| </@></literal> |
| |
| Or all above but with positional parameter passing (<link |
| linkend="ref_directive_userDefined_positionalParam">more details...</link>): |
| |
| <literal><@<replaceable>user</replaceable> <replaceable>val1</replaceable>, <replaceable>val2</replaceable>, <replaceable>...</replaceable>, <replaceable>valN</replaceable>/></literal> |
| ...etc. |
| </programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>user_def_dir_exp</replaceable></literal>: |
| Expression evaluates to an user-defined directive (for example a |
| macro), that will be called.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>param1</replaceable></literal>, |
| <literal><replaceable>param2</replaceable></literal>, ...etc.: |
| The name of parameters. They are <emphasis>not</emphasis> |
| expressions.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>val1</replaceable></literal>, |
| <literal><replaceable>val2</replaceable></literal>, ...etc.: The |
| value of parameters. They <emphasis>are</emphasis> |
| expressions.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>lv1</replaceable></literal>, |
| <literal><replaceable>lv2</replaceable></literal>, ...etc.: The |
| name of <link linkend="dgui_misc_var">loop variables</link>. |
| They are <emphasis>not</emphasis> expressions.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>The number of parameters can be 0 (i.e. no parameters).</para> |
| |
| <para>The order of parameters is not significant (unless you use |
| positional parameter passing). The name of parameters must be |
| unique. Lower- and uppercase letters are considered as different |
| letters in parameter names (i.e. <literal>Color</literal> and |
| <literal>color</literal> is not the same).</para> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>This will call an user-defined directive, for example a macro. |
| The meaning of parameters, and the set of supported and required |
| parameters depend on the concrete user-defined directive.</para> |
| |
| <para>You may read <link linkend="dgui_misc_userdefdir">the tutorial |
| about user-defined directives</link>.</para> |
| |
| <para>Example 1: Calls the directive that is stored in the variable |
| <literal>html_escape</literal>:</para> |
| |
| <programlisting role="template"><@html_escape> |
| a < b |
| Romeo & Juliet |
| </@html_escape></programlisting> |
| |
| <para>Output:</para> |
| |
| <programlisting role="output"> a &lt; b |
| Romeo &amp; Juliet</programlisting> |
| |
| <para>Example 2: Calls a macro with parameters:</para> |
| |
| <programlisting role="template"><@list items=["mouse", "elephant", "python"] title="Animals"/> |
| <replaceable>...</replaceable> |
| <#macro list title items> |
| <p>${title?cap_first}: |
| <ul> |
| <#list items as x> |
| <li>${x?cap_first} |
| </#list> |
| </ul> |
| </#macro></programlisting> |
| |
| <para>Output:</para> |
| |
| <programlisting role="output"> <p>Animals: |
| <ul> |
| <li>Mouse |
| <li>Elephant |
| <li>Python |
| </ul> |
| |
| <replaceable>...</replaceable></programlisting> |
| |
| <section xml:id="ref_directive_userDefined_entTag"> |
| <title>End-tag</title> |
| |
| <para>You can omit the |
| <literal><replaceable>user_def_dir_exp</replaceable></literal> in |
| the <link linkend="gloss.endTag">end-tag</link>. That is, you can |
| always write <literal></@></literal> instead of |
| <literal></@<replaceable>anything</replaceable>></literal>. |
| This rule is mostly useful when the |
| <literal><replaceable>user_def_dir_exp</replaceable></literal> |
| expression is too complex, because you don't have to repeat the |
| expression in the end-tag. Furthermore, if the expression contains |
| other than simple variable names and dots, you are not allowed to |
| repeat the expression. For example, |
| <literal><@a_hash[a_method()]><replaceable>...</replaceable></@a_hash[a_method()]></literal> |
| is an error; you must write |
| <literal><@a_hash[a_method()]><replaceable>...</replaceable></@></literal>. |
| But |
| <literal><@a_hash.foo><replaceable>...</replaceable></@a_hash.foo></literal> |
| is OK.</para> |
| |
| <para>There's also a special rule that says that if the |
| <literal><replaceable>user_def_dir_exp</replaceable></literal> |
| ends with <literal><link |
| linkend="ref_builtin_with_args">?with_args(<replaceable>...</replaceable>)</link></literal>, |
| then that's ignored when the end-tag is matched, so you can write |
| something like |
| <literal><@myMacro?with_args(args)><replaceable>...</replaceable></@myMacro></literal>.</para> |
| </section> |
| |
| <section xml:id="ref_directive_userDefined_loopVar"> |
| <title>Loop variables</title> |
| |
| <para>Some user-defined directives create loop variables |
| (similarly to <literal>list</literal> directive). As with the |
| predefined directives (as <literal>list</literal>) the |
| <emphasis>name</emphasis> of loop variables is given when you call |
| the directive (as <literal>foo</literal> in <literal><#list |
| foos as |
| foo><replaceable>...</replaceable></#list></literal>), |
| while the <emphasis>value</emphasis> of the variable is set by the |
| directive itself. In the case of user-defined directives the |
| syntax is that the name of loop variables is given after a |
| semicolon. For example:</para> |
| |
| <programlisting role="template"><@myRepeatMacro count=4 ; <emphasis>x, last</emphasis>> |
| ${<emphasis>x</emphasis>}. Something... <#if <emphasis>last</emphasis>> This was the last!</#if> |
| </@myRepeatMacro></programlisting> |
| |
| <para>Note that the number of loop variable created by the |
| user-defined directive and the number of loop variables specified |
| after the semicolon need not match. Say, if you are not interested |
| if the repetition is the last, you can simply write:</para> |
| |
| <programlisting role="template"><@myRepeatMacro count=4 ; <emphasis>x</emphasis>> |
| ${<emphasis>x</emphasis>}. Something... |
| </@myRepeatMacro></programlisting> |
| |
| <para>or you can even:</para> |
| |
| <programlisting role="template"><@myRepeatMacro count=4> |
| Something... |
| </@myRepeatMacro></programlisting> |
| |
| <para>Furthermore, it does not cause error if you specify more |
| loop variables after the semicolon than the user-defined directive |
| creates, just the last few loop variables will not be created |
| (i.e. those will be undefined in the nested content). Trying to |
| use the undefined loop variables, however, will cause error |
| (unless you use built-ins like <literal>?default</literal>), since |
| you try to access a non-existing variable.</para> |
| |
| <para>See the <link linkend="dgui_misc_userdefdir">the tutorial |
| about user-defined directives</link> for more explanation.</para> |
| </section> |
| |
| <section xml:id="ref_directive_userDefined_positionalParam"> |
| <title>Positional parameter passing</title> |
| |
| <indexterm> |
| <primary>positional parameter passing</primary> |
| </indexterm> |
| |
| <para>Positional parameter passing (as <literal><@heading |
| "Preface", 1/></literal>) is a shorthand form of normal named |
| parameter passing (as <literal><@heading title="Preface" |
| level=1/></literal>), where you omit the parameter name. This |
| shorthand form should be used if a user-defined directive has only |
| one parameter, or if it is easy to remember the order of |
| parameters for a frequently used user-defined directive. To use |
| this form, you have to know the order in which the named |
| parameters are declared (trivial if the directive has only one |
| parameter). Say, if <literal>heading</literal> was created as |
| <literal><#macro heading title |
| level><replaceable>...</replaceable></literal>, then |
| <literal><@heading "Preface", 1/></literal> is equivalent |
| with <literal><@heading title="Preface" level=1/></literal> |
| (or <literal><@heading level=1 title="Preface"/></literal>; |
| if you use parameter names, the order is not important). Note that |
| positional parameter passing is currently only supported for |
| macros.</para> |
| </section> |
| </section> |
| </section> |
| |
| <section xml:id="ref_directive_visit"> |
| <title>visit, recurse, fallback</title> |
| |
| <anchor xml:id="ref.directive.visit"/> |
| |
| <indexterm> |
| <primary>visit directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>recurse directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>fallback directive</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>recursion</primary> |
| |
| <secondary>iterate</secondary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"><literal><#visit <replaceable>node</replaceable> using <replaceable>namespace</replaceable>></literal> |
| or |
| <literal><#visit <replaceable>node</replaceable>></literal></programlisting> |
| |
| <programlisting role="metaTemplate"><literal><#recurse <replaceable>node</replaceable> using <replaceable>namespace</replaceable>></literal> |
| or |
| <literal><#recurse <replaceable>node</replaceable>></literal> |
| or |
| <literal><#recurse using <replaceable>namespace</replaceable>></literal> |
| or |
| <literal><#recurse></literal></programlisting> |
| |
| <programlisting role="metaTemplate"><literal><#fallback></literal></programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>node</replaceable></literal>: |
| Expression evaluates to a <link linkend="xgui_expose_dom">node |
| variable</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>namespace</replaceable></literal>: A |
| <link linkend="dgui_misc_namespace">namespace</link>, or a |
| sequence of namespaces. A namespace can be given with the |
| namespace hash (a.k.a. gate hash), or with a string literal that |
| store the path of template that could be imported. Instead of |
| namespace hashes, you can use plain hashes as well.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>The <literal>visit</literal> and <literal>recurse</literal> |
| directives are used for the recursive processing of trees. In |
| practice, this will mostly be used for <link |
| linkend="xgui">processing XML.</link></para> |
| |
| <section> |
| <title>Visit</title> |
| |
| <para>When you call <literal><#visit |
| <replaceable>node</replaceable>></literal>, it looks for a |
| user-defined directive (like a macro) to invoke that has the name |
| deducted from the node's name |
| (<literal><replaceable>node</replaceable>?node_name</literal>) and |
| namespace |
| (<literal><replaceable>node</replaceable>?node_namespace</literal>). |
| The rules of name deduction:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>If the node doesn't support node namespaces (as text |
| nodes in XML), then the directive name is simply the name of |
| the node |
| (<literal><replaceable>node</replaceable>?node_name</literal>). |
| <phrase role="forProgrammers">A node does not support node |
| namespaces if the <literal>getNodeNamespace</literal> method |
| returns <literal>null</literal>.</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para>If the node does support node namespaces (as element |
| nodes in XML), then a prefix deduced from the node namespace |
| maybe appended before the node name with a colon used as |
| separator (e.g. <literal>e:book</literal>). The prefix, and if |
| there is a prefix used at all, depends on what prefixes has |
| been registered with the <literal>ns_prefixes</literal> |
| parameter of the <literal>ftl</literal> directive in the <link |
| linkend="dgui_misc_namespace">FTL namespace</link> where |
| <literal>visit</literal> looks for the handler directive |
| (which is not necessary the same as the FTL namespace where |
| <literal>visit</literal> was called from, as you will see |
| later). Concretely, if there was no default namespace |
| registered with <literal>ns_prefixes</literal> then for nodes |
| that does not belong to any namespace (<phrase |
| role="forProgrammers">when <literal>getNodeNamespace</literal> |
| returns <literal>""</literal></phrase>) no prefix is used. If |
| there was a default namespace registered with |
| <literal>ns_prefixes</literal> then for nodes that does not |
| belong to any namespace prefix <literal>N</literal> is used, |
| and for nodes that belong to the default node namespace no |
| prefix is used. Otherwise, in both case, the prefix associated |
| to the node namespace with the <literal>ns_prefixes</literal> |
| is used. If there is not prefix associated to the node |
| namespace of the node, then <literal>visit</literal> simply |
| behave as if there was no directive found with the proper |
| name.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>The node for which the user-defined directive was invoked is |
| available for it as special variable <literal>.node</literal>. |
| Example:</para> |
| |
| <programlisting role="template"><#-- Assume that nodeWithNameX?node_name is "x" --> |
| <#visit nodeWithNameX> |
| Done. |
| <#macro x> |
| Now I'm handling a node that has the name "x". |
| Just to show how to access this node: this node has ${.node?children?size} children. |
| </#macro></programlisting> |
| |
| <para>The output will be something like:</para> |
| |
| <programlisting role="output"> Now I'm handling a node that has the name "x". |
| Just to show how to access this node: this node has 3 children. |
| Done.</programlisting> |
| |
| <para>If one or more namespaces is specified using the optional |
| <literal>using</literal> clause, then <literal>visit</literal> |
| will look for the directives in those namespaces only, with the |
| earlier specified namespaces in the list getting priority. If no |
| <literal>using</literal> clause is specified, the namespace or |
| sequence of namespaces specified with the <literal>using</literal> |
| clause of the last uncompleted <literal>visit</literal> call is |
| reused. If there is no such pending <literal>visit</literal> call, |
| then the current namespace is used. For example, if you execute |
| this template:</para> |
| |
| <programlisting role="template"><#import "n1.ftl" as n1> |
| <#import "n2.ftl" as n2> |
| |
| <#-- This will call n2.x (because there is no n1.x): --> |
| <#visit nodeWithNameX using [n1, n2]> |
| |
| <#-- This will call the x of the current namespace: --> |
| <#visit nodeWithNameX> |
| |
| <#macro x> |
| Simply x |
| </#macro></programlisting> |
| |
| <para>and this is <literal>n1.ftl</literal>:</para> |
| |
| <programlisting role="template"><#macro y> |
| n1.y |
| </#macro></programlisting> |
| |
| <para>and this is <literal>n2.ftl</literal>:</para> |
| |
| <programlisting role="template"><#macro x> |
| n2.x |
| <#-- This callc n1.y as it inherits the "using [n1, n2]" from the pending visit call: --> |
| <#visit nodeWithNameY> |
| <#-- This will call n2.y: --> |
| <#visit nodeWithNameY using .namespace> |
| </#macro> |
| |
| <#macro y> |
| n2.y |
| </#macro></programlisting> |
| |
| <para>then this will print:</para> |
| |
| <programlisting role="output"> |
| n2.x |
| n1.y |
| n2.y |
| |
| Simply x |
| </programlisting> |
| |
| <para>If <literal>visit</literal> doesn't find a user-defined |
| directive in either FTL namespaces with the name identical to the |
| name deduced with the rules described earlier, then it tries to |
| find an user-defined directive with name |
| <literal>@<replaceable>node_type</replaceable></literal>, or if |
| the node does not support node type property (i.e. |
| <literal><replaceable>node</replaceable>?node_type</literal> |
| returns undefined variable), then with name |
| <literal>@default</literal>. For the lookup, it uses the same |
| mechanism as was explained earlier. If it still doesn't find an |
| user-defined directive to handle the node, then |
| <literal>visit</literal> stops template processing with error. |
| Some XML specific node types have special handling in this regard; |
| see: <xref linkend="xgui_declarative_details"/>. Example:</para> |
| |
| <programlisting role="template"><#-- Assume that nodeWithNameX?node_name is "x" --> |
| <#visit nodeWithNameX> |
| |
| <#-- Assume that nodeWithNameY?node_type is "foo" --> |
| <#visit nodeWithNameY> |
| |
| <#macro x> |
| Handling node x |
| </#macro> |
| |
| <#macro @foo> |
| There was no specific handler for node ${node?node_name} |
| </#macro></programlisting> |
| |
| <para>This would print:</para> |
| |
| <programlisting role="output">Handling node x |
| |
| There was no specific handler for node y |
| |
| </programlisting> |
| </section> |
| |
| <section> |
| <title>Recurse</title> |
| |
| <anchor xml:id="ref.directive.recurse"/> |
| |
| <para>The <literal><#recurse></literal> directive is really |
| syntactic sugar. It visits all children nodes of the node (and not |
| the node itself). So, to write:</para> |
| |
| <programlisting role="template"><#recurse <replaceable>someNode</replaceable> using <replaceable>someLib</replaceable>></programlisting> |
| |
| <para>is equivalent to writing:</para> |
| |
| <programlisting role="template"><#list <replaceable>someNode</replaceable>?children as <replaceable>child</replaceable>><#visit <replaceable>child</replaceable> using <replaceable>someLib</replaceable>></#list></programlisting> |
| |
| <para>However, target node is optional in the |
| <literal>recurse</literal> directive. If the target node is |
| unspecified, it simply uses the <literal>.node</literal>. Thus, |
| the terse instruction <literal><#recurse></literal> is |
| equivalent to:</para> |
| |
| <programlisting role="template"><#list .node?children as child><#visit child></#list></programlisting> |
| |
| <para>As a side comment for those who are familiar with XSLT, |
| <literal><#recurse></literal> is pretty much exactly |
| analogous to the <literal><xsl:apply-templates/></literal> |
| instruction in XSLT.</para> |
| </section> |
| |
| <section> |
| <title>Fallback</title> |
| |
| <anchor xml:id="ref.directive.fallback"/> |
| |
| <para>As you could learn earlier, in the documentation of the |
| <literal>visit</literal> directive, the user-defined directive |
| that handles the node is maybe searched in multiple FTL |
| name-spaces. The <literal>fallback</literal> directive can be used |
| in a user-defined directive that was invoked to handle a node. It |
| directs FreeMarker to continue the searching for the user-defined |
| directive in the further name-spaces (that is, in the name-spaces |
| that are after the name-space of the currently invoked |
| user-defined directive in the list of name-spaces). If a handler |
| for the node is found then it is invoked, otherwise |
| <literal>fallback</literal> does nothing.</para> |
| |
| <para>A typical usage of this to write customization layer over a |
| handler library, that sometimes passes the handling to the |
| customized library:</para> |
| |
| <programlisting role="template"><#import "/lib/docbook.ftl" as docbook> |
| |
| <#-- |
| We use the docbook library, but we override some handlers |
| in this namespace. |
| --> |
| <#visit document using [.namespace, docbook]> |
| |
| <#-- |
| Override the "programlisting" handler, but only in the case if |
| its "role" attribute is "java" |
| --> |
| <#macro programlisting> |
| <#if .node.@role[0]!"" == "java"> |
| <#-- Do something special here... --> |
| ... |
| <#else> |
| <#-- Just use the original (overidden) handler --> |
| <#fallback> |
| </#if> |
| </#macro></programlisting> |
| </section> |
| </section> |
| </section> |
| </chapter> |
| |
| <chapter xml:id="ref_specvar"> |
| <title>Special Variable Reference</title> |
| |
| <indexterm> |
| <primary>special variable</primary> |
| </indexterm> |
| |
| <para>Special variables are variables defined by the FreeMarker engine |
| itself. To access them, you use the |
| <literal>.<replaceable>variable_name</replaceable></literal> syntax. For |
| example, you can't write simply <literal>version</literal>; you have to |
| write <literal>.version</literal>.</para> |
| |
| <note> |
| <para>As of FreeMarker 2.3.23, you can use camel case instead of snake |
| case for special variable names, like <literal>dataModel</literal> |
| instead of <literal>data_model</literal>. But know that then within |
| the same template, FreeMarker will enforce the usage of camel case for |
| all identifiers that are part of the template language (user defined |
| names are not affected).</para> |
| </note> |
| |
| <para>The supported special variables are:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem xml:id="specvar.args"> |
| <para><indexterm> |
| <primary>args</primary> |
| </indexterm><literal>args</literal> (since 2.3.30): Used inside |
| the <link |
| linkend="ref.directive.macro"><literal>macro</literal></link> and |
| <link |
| linkend="ref.directive.function"><literal>function</literal></link> |
| directives, it returns all arguments of the current invocation of |
| the macro or function. This allows processing all the arguments in |
| an uniform way (like pass them to the <link |
| linkend="ref_builtin_with_args"><literal>with_args</literal> |
| built-in</link>). Further details:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>When used inside a macro, <literal>.args</literal> is |
| always a hash that maps the parameter names to the parameter |
| values. That's so even if the macro was called with positional |
| arguments, as the parameter names are declared by the |
| <literal>macro</literal> directive. But when used inside a |
| function, <literal>.args</literal> is always a sequence of the |
| argument values. That's because functions can only be called |
| with positional arguments, so the parameter names declared |
| inside the <literal>function</literal> directive aren't |
| relevant.</para> |
| </listitem> |
| |
| <listitem> |
| <para>For arguments that have a default value (as |
| <literal>b</literal> in <literal><#macro m1 a |
| b=0></literal>), if the caller of the macro or function has |
| omitted that argument (as in <literal><@m1 a=1 |
| /></literal>), <literal>.args</literal> will contain the |
| default value for that argument (<literal>{'a': 1, 'b': |
| 0}</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>If there's a catch-all argument, like |
| <literal>others</literal> in <literal><#macro m2 a, b, |
| others...></literal>, then <literal>.args</literal> will |
| contain the elements in the the catch-all parameter directly, |
| and won't contain the declared catch-all parameter |
| (<literal>others</literal>) itself. So for <literal><@m2 a=1 |
| b=2 c=3 d=4 /></literal> it will be <literal>{'a': 1, 'b': 2, |
| 'c': 3, 'd': 4}</literal>, and <emphasis>not</emphasis> |
| <literal>{'a': 1, 'b': 2, 'others': {'c':3, 'd': |
| 4}}</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If a macro has a catch-all parameter, and the actual |
| catch-all argument is not empty, and the macro uses |
| <literal>.args</literal> somewhere, it can only be called with |
| named arguments (like <literal><@m a=1 b=2 /></literal>), |
| and not with positional arguments (like <literal><@m 1 2 |
| /></literal>). That's because for macros |
| <literal>.args</literal> is always a hash, but if the arguments |
| are positional, the catch-all arguments won't have names, so |
| it's impossible to put them into the hash.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>.args</literal> is initialized immediately when |
| the macro or function is called, and so it doesn't reflect |
| changes made later on the local variables that correspond to the |
| arguments. (However, if the argument value is a mutable object, |
| and the objects itself is mutated, <literal>.args</literal> will |
| contain the mutated object. Setting an argument variable with |
| the <link linkend="ref.directive.local"><literal>local</literal> |
| directive</link> doesn't mutate the object.)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>.args</literal> must occur inside a |
| <literal>macro</literal> or <literal>function</literal> |
| directive on the source code level, or else it's a template |
| parsing error. So you can't use it in a template fragment that |
| you insert dynamically into a macro or function (like via the |
| <link linkend="ref.directive.include"><literal>include</literal> |
| directive</link>, <link |
| linkend="ref_builtin_eval"><literal>eval</literal> |
| built-in</link>, or <link |
| linkend="ref_builtin_interpret"><literal>interpret</literal> |
| built-in</link>). That's because the <literal>macro</literal> or |
| <literal>function</literal> has to know if it contains |
| <literal>.args</literal> earlier than it's called.</para> |
| </listitem> |
| |
| <listitem> |
| <para>For macros, the order of elements in the |
| <literal>.args</literal> hash is the same as the order in which |
| the parameters were declared in the <literal>macro</literal> |
| directive, and not the order the caller has used. Except, |
| catch-all arguments will use the order that the caller used. |
| (For functions and methods, as it only support positional |
| arguments, the parameter order of on the caller side is the same |
| as the parameter order in the <literal>function</literal> |
| directive or Java method, so there's no doubt there.)</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>auto_esc</primary> |
| </indexterm><literal>auto_esc</literal> (since 2.3.24): Boolean |
| value that tells if auto-escaping (based on output format) is on or |
| off at the place where this variable is referred (resolved |
| statically). This is <emphasis>not</emphasis> affected by the |
| deprecated <literal>escape</literal> directive. This only deals with |
| automatic escaping based on the output format mechanism.</para> |
| </listitem> |
| |
| <listitem> |
| <para xml:id="ref_specvar_caller_template_name"><indexterm> |
| <primary>caller_template_name</primary> |
| </indexterm><literal>caller_template_name</literal> (available |
| since FreeMarker 2.3.28): Returns the name (path) of the template |
| from which the current <link |
| linkend="ref.directive.macro">macro</link> or <link |
| linkend="ref.directive.function">function</link> was called. It's |
| mostly useful if you want to resolve paths relative to the caller |
| template (<link linkend="ref_builtin_absolute_template_name">see an |
| example here</link>). To serve that purpose better, if the caller |
| template is nameless, this will be an empty string (not a missing |
| value). Reading this variable will cause error if you aren't inside |
| a macro or function call. In particular, directives and |
| <quote>methods</quote> implemented in Java will not influence the |
| value of this variable; it's only for macros and functions |
| implemented in templates. (<phrase |
| role="forProgrammers"><literal>TemplateDirectiveModel</literal> |
| implementations can get similar information via the |
| <literal>freemarker.core.DirectiveCallPlace</literal> |
| object.</phrase>)</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>current_template_name</primary> |
| </indexterm><literal>current_template_name</literal>: The name of |
| the template where we are now (available since FreeMarker 2.3.23). |
| This can be missing (<literal>null</literal>) if the template was |
| created on-the-fly in Java <phrase role="forProgrammers">(via |
| <literal>new Template(null, |
| <replaceable>...</replaceable>)</literal>)</phrase>, rather than |
| loaded from a backing store by name <phrase |
| role="forProgrammers">(via |
| <literal><replaceable>cfg</replaceable>.getTemplate(name, |
| <replaceable>...</replaceable>)</literal>)</phrase>. Migration |
| notice: If you replace the deprecated |
| <literal>template_name</literal> with this, note that the later is a |
| 0-length string instead of missing (<literal>null</literal>) if the |
| template has no name, so you might want to write |
| <literal>current_template_name!''</literal> in legacy |
| templates.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>data_model</literal>: A hash that you can use to |
| access the data-model directly. That is, variables you did with |
| <literal>global</literal> directive are not visible here.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>error</primary> |
| </indexterm><literal>error</literal> (available since FreeMarker |
| 2.3.1): This variable accessible in the body of the <link |
| linkend="ref.directive.attempt"><literal>recover</literal> |
| directive</link>, where it stores the error message of the error we |
| recover from.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>globals</literal>: A hash that you can use to access |
| the globally accessible variables: the data-model and the variables |
| created with <literal>global</literal> directive. Note that |
| variables created with <literal>assign</literal> or |
| <literal>macro</literal> are not globals, thus they never hide the |
| variables when you use <literal>globals</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>incomplatible_improvements</primary> |
| </indexterm><literal>incompatible_improvements</literal> (since |
| FreeMarker 2.3.24): The <link |
| linkend="pgui_config_incompatible_improvements"><literal>incompatible_improvements</literal> |
| setting</link> of the current FreeMarker configuration, as a |
| string.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>language</primary> |
| </indexterm><indexterm> |
| <primary>lang</primary> |
| </indexterm><literal>lang</literal>: Returns the language part of |
| the current value of the locale setting. For example if |
| <literal>.locale</literal> is <literal>en_US</literal>, then |
| <literal>.lang</literal> is <literal>en</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>locale</primary> |
| </indexterm><literal>locale</literal>: Returns the current value |
| of the locale setting. This is a string, for example |
| <literal>en_US</literal>. For more information about locale strings |
| <link linkend="ref.directive.setting">see the |
| <literal>setting</literal> directive</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>locale_object</primary> |
| </indexterm><literal>locale_object</literal> (available since |
| FreeMarker 2.3.21): Returns the current value of the locale setting |
| as a <literal>java.util.Locale</literal> object, rather than as a |
| string. This meant to be used instead of <literal>.locale</literal> |
| when you want to pass it as a <literal>java.util.Locale</literal> |
| object to a Java method. (The <literal>Locale</literal> object will |
| be wrapped according the <literal>object_wrapper</literal> setting |
| value. Whether you can actually pass this value to a Java method as |
| a <literal>Locale</literal> object depends on the object wrapper, |
| but an object wrapper that let you call Java methods directly is |
| very unlikely to not support that.)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>locals</literal>: A hash that you can use to access |
| the local variables (the variables created with the |
| <literal>local</literal> directive, and the parameters of |
| macro).</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>main</literal>: A hash that you can use to access the |
| main <link linkend="dgui_misc_namespace">namespace</link>. Note that |
| global variables like the variables of data-model are |
| <emphasis>not</emphasis> visible through this hash.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>main_template_name</primary> |
| </indexterm><literal>main_template_name</literal>: The name of the |
| top level template (available since FreeMarker 2.3.23). <phrase |
| role="forProgrammers">(In Java, this is the template for which |
| <literal>Template.process</literal> was called.) </phrase>This can |
| be missing (<literal>null</literal>) if the template was created |
| on-the-fly in Java <phrase role="forProgrammers">(via <literal>new |
| Template(null, <replaceable>...</replaceable>)</literal>)</phrase>, |
| rather than loaded from a backing store by name <phrase |
| role="forProgrammers">(via |
| <literal><replaceable>cfg</replaceable>.getTemplate(name, |
| <replaceable>...</replaceable>)</literal>)</phrase>. Migration |
| notice: If you replace the deprecated |
| <literal>template_name</literal> with this, note that the later is a |
| 0-length string instead of missing (<literal>null</literal>) if the |
| template has no name, so you might want to write |
| <literal>main_template_name!''</literal> in legacy templates.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>namespace</literal>: A hash that you can use to |
| access the current <link |
| linkend="dgui_misc_namespace">namespace</link>. Note that global |
| variables like the variables of data-model are |
| <emphasis>not</emphasis> visible through this hash.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>node</literal> (alias <literal>current_node</literal> |
| for historical reasons): The node you are currently processing with |
| the visitor pattern (i.e. with the <link |
| linkend="ref_directive_visit"><literal>visit</literal>, |
| <literal>recurse</literal>, ...etc. directives</link>). Also, it |
| initially stores the root node when you use the <link |
| linkend="pgui_misc_ant">FreeMarker XML Ant task</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>now</primary> |
| </indexterm><indexterm> |
| <primary>current date-time</primary> |
| </indexterm><literal>now</literal>: Returns the current date-time. |
| Usage examples: "<literal>Page generated: ${.now}</literal>", |
| "<literal>Today is ${.now?date}</literal>", "<literal>The current |
| time is ${.now?time}</literal>".</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>output format</primary> |
| </indexterm> Returns the name of the current <link |
| linkend="dgui_misc_autoescaping_outputformat">output format</link>. |
| This value is never missing/null. It's maybe the string |
| <literal>"undefined"</literal>, which is just the name of the |
| default output format.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>output encoding</primary> |
| </indexterm><indexterm> |
| <primary>output charset</primary> |
| </indexterm><literal>output_encoding</literal> (available since |
| FreeMarker 2.3.1): Returns the name of the current output charset. |
| This special variable is not existent if the framework that |
| encapsulates FreeMarker doesn't specify the output charset for |
| FreeMarker. <phrase role="forProgrammers">(Programmers can read more |
| about charset issues <link |
| linkend="pgui_misc_charset">here...</link>)</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>get_optional_template</literal>: This is a method |
| that's used when you need to include or import a template that's |
| possibly missing, and you need to handle that case on some special |
| way. <link linkend="ref_specvar_get_optional_template">More |
| details...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>pass</literal>: This is a macro that does nothing. It |
| has no parameters. Mostly used as no-op node handler in XML |
| processing.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>template_name</primary> |
| </indexterm><literal>template_name</literal>: <emphasis>Don't use |
| it, because its behavior is strange when macros are used; use |
| <literal>current_template_name</literal> or |
| <literal>main_template_name</literal> instead (see migration notices |
| there).</emphasis> Gives the name of the main template, or if we are |
| running an included or imported template, the name of that template. |
| When calling macros, it becomes rather confusing: the macro call |
| won't change the value of this special variable, but when |
| <literal>nested</literal> is called, it changes it to the name of |
| the template that belongs to the current namespace. (Available since |
| FreeMarker 2.3.14.)</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>URL escaping charset</primary> |
| </indexterm><indexterm> |
| <primary>URL escaping charset</primary> |
| </indexterm><literal>url_escaping_charset</literal> (available |
| since FreeMarker 2.3.1): If exists, it stores the name of the |
| charset that should be used for URL escaping. If this variable |
| doesn't exist that means that nobody has specified what charset |
| should be used for URL encoding yet. In this case the <link |
| linkend="ref_builtin_url"><literal>url</literal> built-in</link> |
| uses the charset specified by the <literal>output_encoding</literal> |
| special variable for URL encoding; custom mechanism may follow the |
| same logic. <phrase role="forProgrammers">(Programmers can read more |
| about charset issues <link |
| linkend="pgui_misc_charset">here...</link>)</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>output_format</primary> |
| </indexterm><literal>output_format</literal> (since 2.3.24): The |
| name of output format at the place where this variable is referred |
| (resolved statically), such as <literal>"HTML"</literal>, |
| <literal>"XML"</literal>, <literal>"RTF"</literal>, |
| <literal>"plainText"</literal>, <literal>"undefined"</literal>, etc. |
| <phrase role="forProgrammers">(The available names can be extended |
| by the programmers, by the |
| <literal>registered_custom_output_formats</literal> |
| setting.)</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>vars</primary> |
| </indexterm><literal>vars</literal>: Expression |
| <literal>.vars.foo</literal> returns the same variable as expression |
| <literal>foo</literal>. It's useful if for some reasons you have to |
| use square bracket syntax, since that works only for hash sub |
| variables, so you need an artificial parent hash. For example, to |
| read a top-level variable that has a strange name that would confuse |
| FreeMarker, you can write |
| <literal>.vars["A strange name!"]</literal>. Or, to access a |
| top-level variable with dynamic name given with variable |
| <literal>varName</literal> you can write |
| <literal>.vars[varName]</literal>. Note that the hash returned by |
| <literal>.vars</literal> does not support <literal>?keys</literal> |
| and <literal>?values</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>version</primary> |
| </indexterm><literal>version</literal>: Returns the FreeMarker |
| version number as string, for example <literal>2.2.8</literal>. This |
| can be used to check which FreeMarker version does your application |
| use, but note that this special variable does not exist prior to the |
| 2.3.0 or 2.2.8 versions. The version number of non-final releases |
| contains dash and further info after the numbers, like in |
| 2.3.21-nightly_20140726T151800Z.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>time zone</primary> |
| </indexterm><indexterm> |
| <primary>time_zone</primary> |
| </indexterm><literal>time_zone</literal> (exists since FreeMarker |
| 2.3.31): The current value of the <literal>time_zone</literal> |
| setting, as a string. This is the ID of the time zone, like |
| <literal>GMT+01:00</literal>, or |
| <literal>America/Los_Angeles</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <simplesect xml:id="ref_specvar_get_optional_template"> |
| <title>Using get_optional_template</title> |
| |
| <indexterm> |
| <primary>get_optional_template</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>include optional</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>import optional</primary> |
| </indexterm> |
| |
| <para>This special variable is used when you need to include or import |
| a template that's possibly missing, and you need to handle that case |
| on some special way. It a method (so you meant to call it) that has |
| the following parameters:</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>The name of the template (can be relative or absolute), like |
| <literal>"/commonds/footer.ftl"</literal>; similar to the first |
| parameter of the <link |
| linkend="ref.directive.include"><literal>include</literal> |
| directive</link>. Required, string.</para> |
| </listitem> |
| |
| <listitem> |
| <para>An optional hash of options, like <literal>{ 'parse': false, |
| 'encoding': 'UTF-16BE' }</literal>. The valid keys are |
| <literal>encoding</literal> and <literal>parse</literal>. The |
| meaning of these are the same as of the similarly named <link |
| linkend="ref.directive.include"><literal>include</literal> |
| directive</link> parameters.</para> |
| </listitem> |
| </orderedlist> |
| |
| <para>This method returns a hash that contains the following |
| entries:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>exists</literal>: A boolean that tells if the |
| template was found.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>include</literal>: A directive that, when called, |
| includes the template. Calling this directive is similar to |
| calling the <link |
| linkend="ref.directive.include"><literal>include</literal> |
| directive</link>, but of course with this you spare looking up the |
| template again. This directive has no parameters, nor nested |
| content. If <literal>exists</literal> is <literal>false</literal>, |
| this key will be missing; see later how can this be utilized with |
| <link linkend="dgui_template_exp_missing_default">the |
| <literal><replaceable>exp</replaceable>!<replaceable>default</replaceable></literal> |
| operator</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>import</literal>: A method that, when called, |
| imports the template, and returns the namespace of the imported |
| template. Calling this method is similar to calling the |
| <literal>import</literal> directive, but of course with this you |
| spare looking up the template again, also, it doesn't assign the |
| namespace to anything, just returns it. The method has no |
| parameters. If <literal>exists</literal> is |
| <literal>false</literal>, this key will be missing; see later how |
| can this be utilized with <link |
| linkend="dgui_template_exp_missing_default">the |
| <literal><replaceable>exp</replaceable>!<replaceable>default</replaceable></literal> |
| operator</link>.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>When this method is called (like |
| <literal>.get_optional_template('some.ftl')</literal>), it immediately |
| loads the template if it exists, but doesn't yet process it, so it |
| doesn't have any visible effect yet. The template will be processed |
| only when <literal>include</literal> or <literal>import</literal> |
| members of the returned structure is called. (Of course, when we say |
| that it loads the template, it actually looks it up in the template |
| cache, just like the <link |
| linkend="ref.directive.include"><literal>include</literal> |
| directive</link> does.)</para> |
| |
| <para>While it's not an error if the template is missing, it's an |
| error if it does exist but still can't be loaded due to syntactical |
| errors in it, or due to some I/O error.</para> |
| |
| <note> |
| <para>If the template fails with <quote>I/O error when trying to |
| load optional template</quote> when the template is missing, that's |
| often because your application uses a custom |
| <literal>freemarker.cache.TemplateLoader</literal> implementation, |
| which incorrectly (against the API documentation) throws an |
| <literal>IOException</literal> in the |
| <literal>findTemplateSource</literal> method instead of returning |
| <literal>null</literal> if a template is not found. If it's so, the |
| Java programmers need to fix that. Another possibility is of course |
| that it was indeed not possible to tell if the template exists or |
| not due to some technical issues, in which case stopping with error |
| is the correct behavior. See the cause |
| <literal>IOException</literal> in the Java stack trace to figure out |
| which case it is.</para> |
| </note> |
| |
| <para>Example, in which depending on if <literal>some.ftl</literal> |
| exists, we either print <quote>Template was found:</quote> and the |
| include the template as <literal><#include 'some.ftl'></literal> |
| would, otherwise it we print <quote>Template was |
| missing.</quote>:</para> |
| |
| <programlisting role="template"><#assign optTemp = .get_optional_template('some.ftl')> |
| <#if optTemp.exists> |
| Template was found: |
| <@optTemp.include /> |
| <#else> |
| Template was missing. |
| </#if></programlisting> |
| |
| <para>Example, in which we try to include <literal>some.ftl</literal>, |
| but if that's missing then we try to include |
| <literal>some-fallback.ftl</literal>, and if that's missing too then |
| we call the <literal>ultimateFallback</literal> macro instead of |
| including anything (note the <literal>!</literal>-s after the |
| <literal>include</literal>-s; they belong to <link |
| linkend="dgui_template_exp_missing_default">the |
| <literal><replaceable>exp</replaceable>!<replaceable>default</replaceable></literal> |
| operator</link>):</para> |
| |
| <programlisting role="template"><#macro ultimateFallback> |
| Something |
| </#macro> |
| |
| <@( |
| .get_optional_template('some.ftl').include! |
| .get_optional_template('some-fallback.ftl').include! |
| ultimateFallback |
| ) /></programlisting> |
| |
| <para>Example, which behaves like <literal><#import 'tags.ftl' as |
| tags></literal>, except that if <literal>tags.ftl</literal> is |
| missing, then it creates an empty <literal>tags</literal> hash:</para> |
| |
| <programlisting role="template"><#assign tags = (.get_optional_template('tags.ftl').import())!{}></programlisting> |
| </simplesect> |
| </chapter> |
| |
| <chapter xml:id="ref_reservednames"> |
| <title>Reserved names in FTL</title> |
| |
| <indexterm> |
| <primary>reserved name</primary> |
| </indexterm> |
| |
| <para>The following names cannot be used for top-level variables without |
| square-bracket syntax (as <literal>.vars["in"]</literal>), since they |
| are keywords in FTL:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>true</literal>: boolean value |
| <quote>true</quote></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>false</literal>: boolean value |
| <quote>false</quote></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>gt</literal>: comparison operator <quote>greater |
| than</quote></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>gte</literal>: comparison operator <quote>greater |
| than or equivalent</quote></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>lt</literal>: comparison operator <quote>less |
| than</quote></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>lte</literal>: comparison operator <quote>less than |
| or equivalent</quote></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>as</literal>: used by a few directives</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>in</literal>: used by a few directives</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>using</literal>: used by a few directives</para> |
| </listitem> |
| </itemizedlist> |
| </chapter> |
| |
| <chapter xml:id="ref_deprecated"> |
| <title>Deprecated FTL constructs</title> |
| |
| <indexterm> |
| <primary>deprecated</primary> |
| </indexterm> |
| |
| <section xml:id="ref_depr_directive"> |
| <title>List of deprecated directives</title> |
| |
| <para>The following directives are deprecated, but still |
| working:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><link |
| linkend="ref.directive.call"><literal>call</literal></link>: use |
| <link linkend="ref.directive.userDefined">user-defined directive |
| call</link> instead</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>comment</literal>: This is the old format of |
| <literal><#--<replaceable>...</replaceable>--></literal>. |
| Anything between the <literal><#comment></literal> and |
| <literal></#comment></literal> will be ignored.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>foreach</literal>: it is a synonym of the |
| <literal>list</literal> directive with slightly different |
| parameter syntax. The syntax is <literal><#foreach |
| <replaceable>item</replaceable> in |
| <replaceable>sequence</replaceable>></literal> that is |
| equivalent with <literal><#list |
| <replaceable>sequence</replaceable> as |
| <replaceable>item</replaceable>></literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref.directive.transform"><literal>transform</literal></link>: |
| use <link linkend="ref.directive.userDefined">user-defined |
| directive call</link> instead</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>The following directives are not working anymore:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Legacy <literal>function</literal>: Originally |
| <literal>function</literal> was used to define macros, and was |
| deprecated in favor of the <literal>macro</literal> directive. As |
| of FreeMarker 2.3, this directive is reintroduced with different |
| meaning: it is used to define methods.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section xml:id="ref_depr_builtin"> |
| <title>List of deprecated built-ins</title> |
| |
| <para>The following built-ins are deprecated, but still |
| working:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><indexterm> |
| <primary>default built-in</primary> |
| </indexterm> <literal>default</literal>: This was deprecated |
| with the introduction of the <link |
| linkend="dgui_template_exp_missing_default">default value |
| operator</link>. |
| <literal><replaceable>exp1</replaceable>?default(<replaceable>exp2</replaceable>)</literal> |
| is near equivalent with |
| <literal><replaceable>exp1</replaceable>!<replaceable>exp2</replaceable></literal>, |
| and |
| <literal>(<replaceable>exp1</replaceable>)?default(<replaceable>exp2</replaceable>)</literal> |
| is near equivalent with with |
| <literal>(<replaceable>exp1</replaceable>)!<replaceable>exp2</replaceable></literal>. |
| The only difference is that prior to FreeMarker 2.4, the |
| <literal>default</literal> built-in has always evaluated |
| <literal><replaceable>exp2</replaceable></literal>, while the |
| default value operator only evaluates it when the default value is |
| really needed. Starting from FreeMarker 2.4, however, the |
| <literal>default</literal> built-in was improved, and behaves |
| exactly like the default value operator.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>exists built-in</primary> |
| </indexterm><literal>exists</literal>: This was deprecated with |
| the introduction of the <link |
| linkend="dgui_template_exp_missing_test">missing value test |
| operator</link>. |
| <literal><replaceable>exp1</replaceable>?exists</literal> is |
| equivalent with |
| <literal><replaceable>exp1</replaceable>??</literal>, also |
| <literal>(<replaceable>exp1</replaceable>)?exists</literal> is |
| equivalent with with |
| <literal>(<replaceable>exp1</replaceable>)??</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>if_exists built-in</primary> |
| </indexterm><literal>if_exists</literal>: This was deprecated |
| with the introduction of the <link |
| linkend="dgui_template_exp_missing_default">default value |
| operator</link>. |
| <literal><replaceable>exp1</replaceable>?if_exists</literal> is |
| similar to <literal><replaceable>exp1</replaceable>!</literal>, |
| and <literal>(<replaceable>exp1</replaceable>)?if_exists</literal> |
| is similar to |
| <literal>(<replaceable>exp1</replaceable>)!</literal>. The |
| difference is that the default value with |
| <literal>if_exists</literal> is not only empty string, empty |
| sequence and empty hashs at the same time, but also boolean |
| <literal>false</literal> and a transform that does nothing and |
| ignores all parameters.</para> |
| </listitem> |
| |
| <listitem> |
| <para><indexterm> |
| <primary>web_safe built-in</primary> |
| </indexterm><literal>web_safe</literal>: the same as <link |
| linkend="ref_builtin_html"><literal>html</literal></link></para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section xml:id="ref_depr_oldmacro"> |
| <title>Old-style macro and call directives</title> |
| |
| <anchor xml:id="ref.directive.oldmacro"/> |
| |
| <anchor xml:id="ref.directive.call"/> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"><literal><#macro <replaceable>name</replaceable>(<replaceable>argName1</replaceable>, <replaceable>argName2</replaceable>, <replaceable>... argNameN</replaceable>)> |
| ... |
| </#macro></literal> |
| |
| <literal><#call <replaceable>name</replaceable>(<replaceable>argValue1</replaceable>, <replaceable>argValue2</replaceable>, <replaceable>... argValueN</replaceable>)></literal></programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>name</replaceable></literal>: name |
| of the macro (not expression)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>argName1</replaceable></literal>, |
| <literal><replaceable>argName2</replaceable></literal>, ...etc.: |
| the name of the <link linkend="dgui_misc_var">local |
| variables</link> store the parameter values (not |
| expression)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>argValue1</replaceable></literal>, |
| <literal><replaceable>argValue2</replaceable></literal>, |
| ...etc.: expressions, the value of the parameters</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <note> |
| <para>This is the documentation of FreeMarker 2.1 macro and macro |
| related directives. These are still working, but deprecated. You |
| may want to read the FreeMarker 2.2+ references: <link |
| linkend="ref.directive.macro">macro, return</link>, <link |
| linkend="ref.directive.userDefined">user-defined directive |
| call</link></para> |
| </note> |
| |
| <para>A macro is a template fragment with an associated name. You |
| can use that named fragment on multiple places in your template, so |
| it helps in repetitive tasks. A macro can have parameters that |
| influence the output generated when you use the macro.</para> |
| |
| <para>You define a macro with the <literal>macro</literal> |
| directive, and then you can use the defined macro in the whole |
| template. The <literal>macro</literal> directive itself does not |
| write anything to the output, it just defines the macro. For example |
| this will define a macro called <literal>warning</literal>:</para> |
| |
| <programlisting role="template"><emphasis><#macro warning(message)></emphasis> |
| <div align=center> |
| <table border=1 bgcolor=yellow width="80%"><tr><td align=center> |
| <b>Warning!</b> |
| <p>${message} |
| </td></tr></table> |
| </div> |
| <emphasis></#macro></emphasis></programlisting> |
| |
| <para>The macro definition body (the section between the macro |
| start-tag and end-tag) will be processed whenever you use the |
| <literal>call</literal> directive with the name of the macro. For |
| example this calls the macro called |
| <literal>warning</literal>:</para> |
| |
| <programlisting role="template"><#call warning("Unplug the machine before opening the cover!")></programlisting> |
| |
| <para>and will write this to the output:</para> |
| |
| <programlisting role="output"> <div align=center> |
| <table border=1 bgcolor=yellow width="80%"><tr><td align=center> |
| <b>Warning!</b> |
| <p>Unplug the machine before opening the cover! |
| </td></tr></table> |
| </div> |
| </programlisting> |
| |
| <para>The parameters passed in as parameters to the |
| <literal>call</literal> directive will be accessible in the macro |
| definition body as <link linkend="dgui_misc_var">local |
| variables</link>.</para> |
| |
| <para>When you call a macro, you must specify the same number of |
| parameters as were specified in the macro definition. For example if |
| this is the macro definition:</para> |
| |
| <programlisting role="template"><#macro test(a, b, c)>Nothing...</#macro></programlisting> |
| |
| <para>then these are valid macro calls:</para> |
| |
| <programlisting role="template"><#call test(1, 2, 3)> |
| <#call test("one", 2 + x, [1234, 2341, 3412, 4123])></programlisting> |
| |
| <para>If a macro has no parameters, then you can omit the |
| parentheses:</para> |
| |
| <programlisting role="template"><#macro test>mooo</#macro> |
| <#call test></programlisting> |
| |
| <para>When you define a macro it will be available in the template, |
| where you have defined it only. But probably you want to use the |
| same macros in more templates. In this case you can store your macro |
| definitions in a common file, and then include that file in all |
| templates where you need those macros.</para> |
| |
| <para>It's fine to call a macro that's defined further down in the |
| template <phrase role="forProgrammers">(since macros are defined at |
| parse time, not in process time)</phrase>. However, if the macro |
| definitions are inserted with <literal>include</literal> directive, |
| they will not be available until FreeMarker has executed the |
| <literal>include</literal> directive.</para> |
| |
| <para>You can leave a macro definition body before the |
| <literal></#macro></literal> tag with the |
| <literal>return</literal> directive.</para> |
| </section> |
| </section> |
| |
| <section xml:id="ref_depr_transform"> |
| <title>Transform directive</title> |
| |
| <anchor xml:id="ref.directive.transform"/> |
| |
| <indexterm> |
| <primary>transform directive</primary> |
| </indexterm> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"> |
| <literal><transform <replaceable>transVar</replaceable>> |
| <replaceable>...</replaceable> |
| </transform></literal> |
| or |
| <literal><transform <replaceable>transVar</replaceable> <replaceable>name1</replaceable>=<replaceable>value1</replaceable> <replaceable>name2</replaceable>=<replaceable>value2</replaceable> <replaceable>...</replaceable> <replaceable>nameN</replaceable>=<replaceable>valueN</replaceable>> |
| <replaceable>...</replaceable> |
| </transform></literal> |
| </programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>transVar</replaceable></literal>: |
| Expression evaluates to a transform</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>name1</replaceable></literal>, |
| <literal><replaceable>name2</replaceable></literal>, ... |
| <literal><replaceable>nameN</replaceable></literal>: Name of |
| parameters. Literal value, not expression.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>value1</replaceable></literal>, |
| <literal><replaceable>value2</replaceable></literal>, ... |
| <literal><replaceable>valueN</replaceable></literal>: |
| Expressions evaluate to the values of parameters</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <note> |
| <para>This directive is still working, but deprecated. You may |
| want to read about <link |
| linkend="ref.directive.userDefined">user-defined directive |
| calls</link> to see the replacement.</para> |
| </note> |
| |
| <para>Captures the output generated inside its body (i.e. between |
| its start-tag and end-tag), and let the given transform modify it |
| before it is written to the final output.</para> |
| |
| <para>Example:</para> |
| |
| <programlisting role="template"><p>A very simple HTML file: |
| <pre> |
| <emphasis><transform html_escape></emphasis> |
| <html> |
| <body> |
| <p>Hello word! |
| </body> |
| </html> |
| <emphasis></transform></emphasis> |
| </pre></programlisting> |
| |
| <para>the output will be:</para> |
| |
| <programlisting role="output"><p>A very simple HTML file: |
| <pre> |
| &lt;html&gt; |
| &lt;body&gt; |
| &lt;p&gt;Hello word! |
| &lt;/body&gt; |
| &lt;/html&gt; |
| </pre></programlisting> |
| |
| <para>Some transforms may take parameters. The name and meaning of |
| parameters depends on the transform in question. For example here we |
| give a parameter called <quote>var</quote>:</para> |
| |
| <programlisting role="template"><#-- This transform stores the output in the variable x, |
| rather than sending it to the output --> |
| <transform capture_output<emphasis> var="x"</emphasis>> |
| some test |
| </transform></programlisting> |
| |
| <para>It is the task of the programmers to put the necessary |
| transforms into the data-model. For the name and usage of accessible |
| transforms ask the programmers. <phrase |
| role="forProgrammers">Initially there is a <link |
| linkend="pgui_config_sharedvariables">shared variable</link> for |
| most transforms in the |
| <literal>freemarker.template.utility</literal> package. For more |
| information see: <xref |
| linkend="pgui_config_sharedvariables"/></phrase></para> |
| </section> |
| </section> |
| |
| <section xml:id="ref_depr_oldsyntax"> |
| <title>Old FTL syntax</title> |
| |
| <indexterm> |
| <primary>strict syntax</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>old FTL syntax</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>new FTL syntax</primary> |
| </indexterm> |
| |
| <para>With the old FTL syntax the <literal>#</literal> was not |
| required (prior 2.1 not even allowed) in the FTL tags. For example, |
| you could write this:</para> |
| |
| <programlisting role="template"><html> |
| <head> |
| <title>Welcome!</title> |
| </head> |
| <body> |
| <h1>Welcome ${user}!</h1> |
| <p>We have there animals: |
| <ul> |
| <emphasis><list animals as animal></emphasis> |
| <li>${animal.name} for ${animal.price} Euros |
| <emphasis></list></emphasis> |
| </ul> |
| <emphasis><include "common_footer.html"></emphasis> |
| </body> |
| </html></programlisting> |
| |
| <para>While the <literal>#</literal>-less syntax was more natural for |
| HTML authors, it had too many drawbacks, so finally we have decided to |
| deprecate it. With the newer syntax (a.k.a <quote>strict |
| syntax</quote>), the <literal>#</literal> is strictly required. That |
| is, things like <literal><include |
| "common_footer.html"></literal> will go to the output as is, since |
| they are not considered as FTL tags. Note that user-defined directives |
| use <literal>@</literal> <emphasis>instead of</emphasis> |
| <literal>#</literal>.</para> |
| |
| <para>However, to give users time to prepare for this change, in |
| FreeMarker 2.1 and 2.2 the usage of <literal>#</literal> is optional, |
| unless the programmer enables strict syntax mode in the FreeMarker |
| configuration by calling <literal>setStrictSyntaxMode(true)</literal> |
| on <literal>Configuration</literal>. In fact, we strongly recommend |
| this to programmers. Starting from some later release this setting |
| will be initially set to <literal>true</literal>. Also, you can |
| specify if you want to use strict syntax or old syntax in the template |
| files with the <link |
| linkend="ref.directive.ftl"><literal>ftl</literal> |
| directive</link>.</para> |
| |
| <para>The advantages of <quote>strict syntax</quote> over the legacy |
| FTL syntax are:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Since all |
| <literal><#<replaceable>...</replaceable>></literal> and |
| <literal></#<replaceable>...</replaceable>></literal> are |
| reserved for FTL:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>We can introduce new directives without breaking |
| backward compatibility.</para> |
| </listitem> |
| |
| <listitem> |
| <para>We can detect if you made a typo, i.e. |
| <literal><#inculde |
| <replaceable>...</replaceable>></literal> is treated as |
| parse-time error, rather than silently treated as simple |
| text.</para> |
| </listitem> |
| |
| <listitem> |
| <para>It is easier for third-party tools to handle templates |
| (e.g. do syntax highlighting), especially since they don't |
| have to know about the new directives introduced with new |
| releases.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Templates are more readable, since it is easier to spot |
| <literal><#...></literal> tags embedded into HTML or |
| other markup.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para><literal><#</literal> and <literal></#</literal> is |
| illegal XML (except in CDATA sections), and illegal in almost all |
| other SGML applications, so they can't interfere with the tags |
| used in the static text parts (e.g. if you have |
| <literal>include</literal> element in the generated XML).</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section xml:id="ref_depr_numerical_interpolation"> |
| <title>#{...}: Numerical interpolation</title> |
| |
| <indexterm> |
| <primary>#{...}</primary> |
| </indexterm> |
| |
| <para>Deprecated: Use the <link |
| linkend="ref.setting.number_format"><literal>number_format</literal> |
| setting</link> and <link linkend="ref_builtin_string_for_number">the |
| <literal>string</literal> built-in</link> instead. For formatting for |
| computer audience (i.e., no localized formatting) use the <link |
| linkend="ref_builtin_c"><literal>c</literal> built-in</link> (like |
| <literal><replaceable>number</replaceable>?c</literal>).</para> |
| |
| <para>While by default |
| <literal>#{<replaceable>...</replaceable>}</literal> is interpreted, |
| that can be disabled by setting the |
| <literal>interpolation_syntax</literal> configuration setting |
| (<literal>Configuration.setInterpolationSyntax</literal> in the Java |
| API) to <literal>dollar</literal>. Then |
| <literal>#{<replaceable>...</replaceable>}</literal> will be just |
| static text, and only |
| <literal>${<replaceable>...</replaceable>}</literal> will operate as |
| interpolation.</para> |
| |
| <section> |
| <title>Synopsis</title> |
| |
| <programlisting role="metaTemplate"><literal>#{<replaceable>expression</replaceable>}</literal> |
| or |
| <literal>#{<replaceable>expression</replaceable>; <replaceable>format</replaceable>}</literal></programlisting> |
| |
| <para>Where:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal><replaceable>expression</replaceable></literal>: |
| expression that can be evaluated as a number.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>format</replaceable></literal>: |
| optional format specifier.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Description</title> |
| |
| <para>The numerical interpolation is used to output a number value. |
| If the expression doesn't evaluate to a number, the evaluation ends |
| with an error.</para> |
| |
| <para>The optional format specifier specifies the minimum and the |
| maximum number of displayed fractional digits using syntax |
| <literal>m<replaceable>min</replaceable>M<replaceable>max</replaceable></literal>. |
| For example, <literal>m2M5</literal> means "at least two, at most |
| five fractional digits". The minimum or the maximum specifier part |
| can be omitted. If only the minimum is specified, the maximum is |
| equal to the minimum. If only maximum is specified, the minimum is |
| 0.</para> |
| |
| <para>The decimal separator character of the output is |
| internationalized (according the current locale setting), which |
| means that it is not necessarily a dot.</para> |
| |
| <para>Unlike <literal>${...}</literal>, <literal>#{...}</literal> |
| ignores the <link |
| linkend="ref.setting.number_format"><literal>number_format</literal> |
| setting</link>. This is actually a backward compatibility quirk, but |
| it can be useful when you print numbers in situations like |
| <literal><a href="queryDatabase?id=#{id}"></literal>, where |
| you surely don't want grouping separators or something fancy like |
| that. However, starting from FreeMarker 2.3.3 rather use the <link |
| linkend="ref_builtin_c"><literal>?c</literal> built-in</link> for |
| this purpose, like <literal><a |
| href="queryDatabase?id=${id?c}"></literal>.</para> |
| |
| <para>Examples. Assume that <literal>x</literal> is |
| <literal>2.582</literal> and <literal>y</literal> is |
| <literal>4</literal>:</para> |
| |
| <programlisting role="template"> <#-- If the language is US English the output is: --> |
| #{x} <#-- 2.582 --> |
| #{y} <#-- 4 --> |
| #{x; M2} <#-- 2.58 --> |
| #{y; M2} <#-- 4 --> |
| #{x; m1} <#-- 2.6 --> |
| #{y; m1} <#-- 4.0 --> |
| #{x; m1M2} <#-- 2.58 --> |
| #{y; m1M2} <#-- 4.0 --></programlisting> |
| </section> |
| </section> |
| </chapter> |
| </part> |
| |
| <part xml:id="xgui"> |
| <title>XML Processing Guide</title> |
| |
| <preface xml:id="xgui_preface"> |
| <title>Preface</title> |
| |
| <para>Although FreeMarker was originally designed as a web page template |
| engine, as of version 2.3 it also targets another application domain: |
| transforming XML into arbitrary textual output (e.g. HTML files). Thus, |
| in many cases, FreeMarker is an XSLT alternative.</para> |
| |
| <para>Technically, there is nothing special in transforming XML |
| documents. It's just like when you do anything else with FreeMarker: you |
| drop the XML document into the data-model (and possibly other |
| variables), and then you merge the data-model with the FTL template(s) |
| that generate the output text. The extra features introduced for better |
| XML processing are the node FTL variable type (symbolizes a node in |
| generic tree structures, usable not only for XML) and the built-ins and |
| directives dealing with them, and the XML wrapper you get out-of-the-box |
| that exposes XML documents as FTL variables for the templates.</para> |
| |
| <para>What's the difference between using FreeMarker or XSLT? The FTL |
| language has the usual imperative/procedural logic. On the other hand, |
| XSLT is a language with declarative style, designed by "too clever" |
| people, so it's not easy to adopt its logic, nor to use it in many |
| cases. Also its syntax is terribly verbose. However, XSLT's |
| "apply-templates" method can be very handy when you process XML |
| documents, thus FreeMarker supports something similar called the |
| <quote>visitor pattern</quote>. So in many applications, it is much |
| easier to write FTL stylesheets than XSLT style-sheets. Another |
| fundamental difference is that FTL "transforms" the node tree to text, |
| while XSLT transforms the tree to another tree. So you cannot always use |
| FreeMarker where you can use XSLT.</para> |
| </preface> |
| |
| <chapter xml:id="xgui_expose"> |
| <title>Exposing XML documents</title> |
| |
| <indexterm> |
| <primary>XML</primary> |
| |
| <secondary>exposing</secondary> |
| </indexterm> |
| |
| <section xml:id="xgui_expose_dom"> |
| <title>The DOM tree</title> |
| |
| <para>We will use this XML document for the examples:</para> |
| |
| <anchor xml:id="misc.example.bookXml"/> |
| |
| <programlisting role="unspecified"><book> |
| <title>Test Book</title> |
| <chapter> |
| <title>Ch1</title> |
| <para>p1.1</para> |
| <para>p1.2</para> |
| <para>p1.3</para> |
| </chapter> |
| <chapter> |
| <title>Ch2</title> |
| <para>p2.1</para> |
| <para>p2.2</para> |
| </chapter> |
| </book></programlisting> |
| |
| <para>W3C DOM models an XML document as a tree of nodes. The node tree |
| of the above XML can be visualized as:</para> |
| |
| <programlisting role="unspecified">document |
| | |
| +- element book |
| | |
| +- text "\n " |
| | |
| +- element title |
| | | |
| | +- text "Test Book" |
| | |
| +- text "\n " |
| | |
| +- element chapter |
| | | |
| | +- text "\n " |
| | | |
| | +- element title |
| | | | |
| | | +- text "Ch1" |
| | | |
| | +- text "\n " |
| | | |
| | +- element para |
| | | | |
| | | +- text "p1.1" |
| | | |
| | +- text "\n " |
| | | |
| | +- element para |
| | | | |
| | | +- text "p1.2" |
| | | |
| | +- text "\n " |
| | | |
| | +- element para |
| | | |
| | +- text "p1.3" |
| | |
| +- element |
| | |
| +- text "\n " |
| | |
| +- element title |
| | | |
| | +- text "Ch2" |
| | |
| +- text "\n " |
| | |
| +- element para |
| | | |
| | +- text "p2.1" |
| | |
| +- text "\n " |
| | |
| +- element para |
| | |
| +- text "p2.2"</programlisting> |
| |
| <para>Note that the disturbing <literal>"\n  "</literal>-s are the |
| line-breaks (indicated here with <literal>\n</literal>, an escape |
| sequence used in FTL string literals) and the indentation spaces |
| between the tags.</para> |
| |
| <para>Notes on the DOM related terminology:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The topmost node of a tree is called the <emphasis |
| role="term">root</emphasis>. In the case of XML documents, it is |
| always the <quote>document</quote> node, and not the top-most |
| element (<literal>book</literal> in this example).</para> |
| </listitem> |
| |
| <listitem> |
| <para>We say that node B is the <emphasis |
| role="term">child</emphasis> of node A, if B is the |
| <emphasis>immediate</emphasis> descendant of A. For example, the |
| two <literal>chapter</literal> element nodes are the children of |
| the <literal>book</literal> element node, but the |
| <literal>para</literal> element nodes are not.</para> |
| </listitem> |
| |
| <listitem> |
| <para>We say that node A is the <emphasis |
| role="term">parent</emphasis> of node B, if A is the |
| <emphasis>immediate</emphasis> ascendant of node B, that is, if B |
| is the children of A. For example, the <literal>book</literal> |
| element node is the parent of the two <literal>chapter</literal> |
| element nodes, but it is not the parent of the |
| <literal>para</literal> element nodes.</para> |
| </listitem> |
| |
| <listitem> |
| <para>There are several kind of components that can occur in XML |
| documents, such as elements, text, comments, processing |
| instructions, etc. All such components are nodes in the DOM tree, |
| so there are element nodes, text nodes, comment nodes, etc. In |
| principle, the attributes of elements are also nodes in the tree |
| -- they are the children of the element --, but still, usually we |
| (and other XML related technologies) exclude them of element |
| children. So basically they don't count as children nodes.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>The programmer drops the document node of the DOM tree into the |
| FreeMarker data-model, and then the template author can walk the DOM |
| tree using that variable as the starting-point.</para> |
| |
| <para>The DOM nodes in FTL correspond to <emphasis role="term">node |
| variables</emphasis>. This is a variable type, similarly to type |
| string, number, hash, etc. Node variable type makes it possible for |
| FreeMarker to get the parent node and the child nodes of a node. This |
| is technically required to allow the template author to navigate |
| between the nodes, say, to use the <link |
| linkend="ref_builtins_node">node built-ins</link> or the <link |
| linkend="ref.directive.visit"><literal>visit</literal></link> and |
| <link |
| linkend="ref.directive.recurse"><literal>recurse</literal></link> |
| directives; we will show the usage of these in the further |
| chapters.</para> |
| </section> |
| |
| <section xml:id="xgui_expose_put"> |
| <title>Putting the XML into the data-model</title> |
| |
| <note> |
| <para>This section is for programmers.</para> |
| </note> |
| |
| <para>It's easy to create a simple program to try the examples. Just |
| replace the <quote>Create a data-model</quote> part of <link |
| linkend="pgui_quickstart_all">the example of Programmer's Guide |
| Quickstart</link> with this:</para> |
| |
| <programlisting role="unspecified">/* Create a data-model */ |
| Map root = new HashMap(); |
| root.put( |
| "doc", |
| freemarker.ext.dom.NodeModel.parse(new File("<replaceable>the/path/of/the.xml</replaceable>")));</programlisting> |
| |
| <para>and then you have a program that outputs the result of the XML |
| transformation to the standard output (usually the terminal |
| screen).</para> |
| |
| <para>Notes:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The <literal>parse</literal> method removes comment and |
| processing instruction nodes by default. See the API for more |
| details.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>NodeModel</literal> also allows you to wrap |
| <literal>org.w3c.dom.Node</literal>-s directly. You may want to |
| clean up the DOM tree first with the static utility methods, such |
| as <literal>NodeModel.simplify</literal> or your own custom |
| cleanup routines.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Note that there are tools available that you can use to generate |
| files from XML documents, so you don't have to write your own for this |
| common task. <link linkend="pgui_misc_ant">See here...</link></para> |
| </section> |
| </chapter> |
| |
| <chapter xml:id="xgui_imperative"> |
| <title>Imperative XML processing</title> |
| |
| <indexterm> |
| <primary>XML</primary> |
| |
| <secondary>imperative processing</secondary> |
| </indexterm> |
| |
| <section xml:id="xgui_imperative_learn"> |
| <title>Basics</title> |
| |
| <note> |
| <para>This section uses the DOM tree and the variable made in the |
| <link linkend="xgui_expose">previous chapter</link>.</para> |
| </note> |
| |
| <para>Assume that the programmer has put the XML document into the |
| data-model as variable <literal>doc</literal>. This variable |
| corresponds to the root of the <link linkend="xgui_expose_dom">DOM |
| tree</link>, the <quote>document</quote>. The actual variable |
| structure behind <literal>doc</literal> is wily enough, and only |
| roughly resembles the DOM tree. So instead of getting lost in the |
| details, let's see how to use it by example.</para> |
| |
| <section> |
| <title>Accessing elements by name</title> |
| |
| <para>This FTL prints the title of the book:</para> |
| |
| <programlisting role="template"><h1>${doc.book.title}</h1></programlisting> |
| |
| <para>The output will be:</para> |
| |
| <programlisting role="output"><h1>Test Book</h1></programlisting> |
| |
| <para>As you see, both <literal>doc</literal> and |
| <literal>book</literal> can be used as hashes; you get their child |
| nodes as sub variables. Basically, you describe the path by which |
| you reach the target (element <literal>title</literal>) in the DOM |
| tree. You may notice that there was some swindle above: with |
| <literal>${doc.book.title}</literal>, it seems that we instruct |
| FreeMarker to print the <literal>title</literal> element itself, but |
| we should print its child text node (check the <link |
| linkend="xgui_expose_dom">DOM tree</link>). It still works, because |
| elements are not only hash variables, but string variables as well. |
| The scalar value of an element node is the string resulting from the |
| concatenation of all its text child nodes. However, trying to use an |
| element as scalar will cause error if the element has child |
| elements. For example <literal>${doc.book}</literal> would stop with |
| error.</para> |
| |
| <para>This FTL prints the titles of the two chapters:</para> |
| |
| <programlisting role="template"><h2>${doc.book.chapter[0].title}</h2> |
| <h2>${doc.book.chapter[1].title}</h2></programlisting> |
| |
| <para>Here, as <literal>book</literal> has 2 |
| <literal>chapter</literal> element children, |
| <literal>doc.book.chapter</literal> is a sequence that stores the |
| two element nodes. Thus, we can generalize the above FTL, so it |
| works with any number of chapters:</para> |
| |
| <programlisting role="template"><#list doc.book.chapter as ch> |
| <h2>${ch.title}</h2> |
| </#list></programlisting> |
| |
| <para>But what's if there is only one chapter? Actually, when you |
| access an element as hash subvariable, it is |
| <emphasis>always</emphasis> a sequence as well (not only hash and |
| string), but if the sequence contains exactly 1 item, then the |
| variable also acts as that item itself. So, returning to the first |
| example, this would print the book title as well:</para> |
| |
| <programlisting role="template"><h1>${doc.book[0].title[0]}</h1></programlisting> |
| |
| <para>But you know that there is exactly 1 <literal>book</literal> |
| element, and that a book has exactly 1 title, so you can omit the |
| <literal>[0]</literal>-s. |
| <literal>${doc.book.chapter.title}</literal> would work too, if the |
| book happen to have only 1 <literal>chapter</literal>-s (otherwise |
| it is ambiguous: how is it to know if the <literal>title</literal> |
| of which <literal>chapter</literal> you want? So it stops with an |
| error.). But since a book can have multiple chapters, you don't use |
| this form. If the element <literal>book</literal> has no |
| <literal>chapter</literal> child, then |
| <literal>doc.book.chapter</literal> will be a 0 length sequence, so |
| the FTL with <literal><#list ...></literal> will still |
| work.</para> |
| |
| <para>It is important to realize the consequence that, for example, |
| if <literal>book</literal> has no <literal>chapter</literal>-s then |
| <literal>book.chapter</literal> is an empty sequence, so |
| <literal>doc.book.chapter??</literal> will <emphasis>not</emphasis> |
| be <literal>false</literal>, it will be always |
| <literal>true</literal>! Similarly, |
| <literal>doc.book.somethingTotallyNonsense??</literal> will not be |
| <literal>false</literal> either. To check if there was no children |
| found, use <literal>doc.book.chapter[0]??</literal> (or |
| <literal>doc.book.chapter?size == 0</literal>). Of course you can |
| use similarly all the <link |
| linkend="dgui_template_exp_missing">missing value handler |
| operators</link> (e.g. |
| <literal>doc.book.author[0]!"Anonymous"</literal>), just don't |
| forget that <literal>[0]</literal>.</para> |
| |
| <note> |
| <para>The rule with sequences of size 1 is a convenience feature |
| of the XML wrapper (implemented via multi-type FTL variables). It |
| will not work with other sequences in general.</para> |
| </note> |
| |
| <para>Now we finish the example by printing all the |
| <literal>para</literal>-s of each chapter:</para> |
| |
| <programlisting role="template"><h1>${doc.book.title}</h1> |
| <#list doc.book.chapter as ch> |
| <h2>${ch.title}</h2> |
| <#list ch.para as p> |
| <p>${p} |
| </#list> |
| </#list></programlisting> |
| |
| <para>this will print:</para> |
| |
| <programlisting role="output"><h1>Test</h1> |
| <h2>Ch1</h2> |
| <p>p1.1 |
| <p>p1.2 |
| <p>p1.3 |
| <h2>Ch2</h2> |
| <p>p2.1 |
| <p>p2.2</programlisting> |
| |
| <para>The above FTL could be written more nicely as:</para> |
| |
| <programlisting role="template"><#assign book = doc.book> |
| <h1>${book.title}</h1> |
| <#list book.chapter as ch> |
| <h2>${ch.title}</h2> |
| <#list ch.para as p> |
| <p>${p} |
| </#list> |
| </#list></programlisting> |
| |
| <para>Finally, a generalized usage of the child selector mechanism: |
| this template lists all <literal>para</literal>-s of the example XML |
| document:</para> |
| |
| <programlisting role="template"><#list doc.book.chapter.para as p> |
| <p>${p} |
| </#list></programlisting> |
| |
| <para>The output will be:</para> |
| |
| <programlisting role="output"> <p>p1.1 |
| <p>p1.2 |
| <p>p1.3 |
| <p>p2.1 |
| <p>p2.2 |
| </programlisting> |
| |
| <para>This example shows that hash sub variables select the children |
| of a sequence of notes (just in the earlier examples that sequence |
| happened to be of size 1). In this concrete case, subvariable |
| <literal>chapter</literal> returns a sequence of size 2 (since there |
| are two <literal>chapter</literal>-s), and then subvariable |
| <literal>para</literal> selects the <literal>para</literal> child |
| nodes of all nodes in that sequence.</para> |
| |
| <para>A negative consequence of this mechanism is that things like |
| <literal>doc.somethingNonsense.otherNonsesne.totalNonsense</literal> |
| will just evaluate to an empty sequence, and you don't get any error |
| messages.</para> |
| </section> |
| |
| <section> |
| <title>Accessing attributes</title> |
| |
| <para>This XML is the same as the original, except that it uses |
| attributes for the titles, instead of elements:</para> |
| |
| <programlisting role="unspecified"><!-- THIS XML IS USED FOR THE "Accessing attributes" CHAPTER ONLY! --> |
| <!-- Outside this chapter examples use the XML from earlier. --> |
| |
| <book title="Test"> |
| <chapter title="Ch1"> |
| <para>p1.1</para> |
| <para>p1.2</para> |
| <para>p1.3</para> |
| </chapter> |
| <chapter title="Ch2"> |
| <para>p2.1</para> |
| <para>p2.2</para> |
| </chapter> |
| </book></programlisting> |
| |
| <para>The attributes of an element can be accessed in the same way |
| as the child elements of the element, except that you put an at-sign |
| (@) before the name of the attribute:</para> |
| |
| <programlisting role="template"><#assign book = doc.book> |
| <h1>${book.@title}</h1> |
| <#list book.chapter as ch> |
| <h2>${ch.@title}</h2> |
| <#list ch.para as p> |
| <p>${p} |
| </#list> |
| </#list></programlisting> |
| |
| <para>This will print exactly the same as the previous |
| example.</para> |
| |
| <para>Getting attributes follows the same logic as getting child |
| elements, so the result of <literal>ch.@title</literal> above is a |
| sequence of size 1. If there were no <literal>title</literal> |
| attribute, then the result would be a sequence of size 0. So be |
| ware, using existence built-ins is tricky here too: if you are |
| curious if <literal>foo</literal> has attribute |
| <literal>bar</literal> then you have to write |
| <literal>foo.@bar[0]??</literal>. (<literal>foo.@bar??</literal> is |
| wrong, because it always returns <literal>true</literal>.) |
| Similarly, if you want a default value for the |
| <literal>bar</literal> attribute, then you have to write |
| <literal>foo.@bar[0]!"theDefaultValue"</literal>.</para> |
| |
| <para>As with child elements, you can select the attributes of |
| multiple nodes. For example, this template prints the titles of all |
| chapters:</para> |
| |
| <programlisting role="template"><#list doc.book.chapter.@title as t> |
| ${t} |
| </#list></programlisting> |
| </section> |
| |
| <section> |
| <title>Exploring the tree</title> |
| |
| <para>This FTL will enumerate all child nodes of the book |
| element:</para> |
| |
| <programlisting role="template"><#list doc.book?children as c> |
| - ${c?node_type} <#if c?node_type == 'element'>${c?node_name}</#if> |
| </#list></programlisting> |
| |
| <para>this will print:</para> |
| |
| <programlisting role="output">- text |
| - element title |
| - text |
| - element chapter |
| - text |
| - element chapter |
| - text</programlisting> |
| |
| <para>The meaning of <literal>?node_type</literal> is probably clear |
| without explanation. There are several node types that can occur in |
| a DOM tree, such as <literal>"element"</literal>, |
| <literal>"text"</literal>, <literal>"comment"</literal>, |
| <literal>"pi"</literal>, ...etc.</para> |
| |
| <para>The <literal>?node_name</literal> returns the name of element |
| for element nodes. For other node types, it also returns something, |
| but that's mainly useful for declarative XML processing, which will |
| be discussed in a <link linkend="xgui_declarative">later |
| chapter</link>.</para> |
| |
| <para>If the book element had attributes, they would |
| <emphasis>not</emphasis> appear in the above list, for practical |
| reasons. But you can get a list that contains all attributes of the |
| element, with subvariable <literal>@@</literal> of the element |
| variable. If you modify the first line of the XML to this:</para> |
| |
| <programlisting role="unspecified"><book foo="Foo" bar="Bar" baaz="Baaz"></programlisting> |
| |
| <para>and run this FTL:</para> |
| |
| <programlisting role="template"><#list doc.book.@@ as attr> |
| - ${attr?node_name} = ${attr} |
| </#list></programlisting> |
| |
| <para>then you get this output (or something similar):</para> |
| |
| <programlisting role="output">- baaz = Baaz |
| - bar = Bar |
| - foo = Foo</programlisting> |
| |
| <para>Returning to the listing of children, there is a convenience |
| subvariable to list only the element children of an element:</para> |
| |
| <programlisting role="template"><#list doc.book.* as c> |
| - ${c?node_name} |
| </#list></programlisting> |
| |
| <para>This will print:</para> |
| |
| <programlisting role="output">- title |
| - chapter |
| - chapter</programlisting> |
| |
| <para>You get the parent of an element with the |
| <literal>parent</literal> built-in:</para> |
| |
| <programlisting role="template"><#assign e = doc.book.chapter[0].para[0]> |
| <#-- Now e is the first para of the first chapter --> |
| ${e?node_name} |
| ${e?parent?node_name} |
| ${e?parent?parent?node_name} |
| ${e?parent?parent?parent?node_name}</programlisting> |
| |
| <para>This will print:</para> |
| |
| <programlisting role="output">para |
| chapter |
| book |
| @document</programlisting> |
| |
| <para>In the last line you have reached the root of the DOM tree, |
| the document node. It's not an element, and this is why it has that |
| strange name; don't deal with it now. Obviously, the document node |
| has no parent.</para> |
| |
| <para>You can quickly go back to the document node using the |
| <literal>root</literal> built-in:</para> |
| |
| <programlisting role="template"><#assign e = doc.book.chapter[0].para[0]> |
| ${e?root?node_name} |
| ${e?root.book.title}</programlisting> |
| |
| <para>This will print:</para> |
| |
| <programlisting role="output">@document |
| Test Book</programlisting> |
| |
| <para>For the complete list of built-ins you can use to navigate in |
| the DOM tree, read the <link linkend="ref_builtins_node">reference |
| of node built-ins</link>.</para> |
| </section> |
| |
| <section xml:id="xgui_imperative_learn_xpath"> |
| <title>Using XPath expressions</title> |
| |
| <note> |
| <para>XPath expressions work only if <link |
| xlink:href="http://xml.apache.org/xalan/">Apache Xalan</link> or |
| <link xlink:href="http://jaxen.org/">Jaxen</link> (at least 1.1) |
| classes are available. However, up to Java 1.8 you don't need any |
| additional dependencies, as Apache Xalan is included in Java with |
| changed package names, which FreeMarker will automatically use |
| (unless plain Apache Xalan is also present). This internal Xalan |
| isn't available anymore on OpenJDK 9, but is still available on |
| Oracle JDK/JRE 9 (at least on official stable release <quote>build |
| 9+181</quote>).</para> |
| </note> |
| |
| <note> |
| <para>Don't use the sample XML from the previous section, where |
| <literal>title</literal> is an attribute; that applies only to |
| that section.</para> |
| </note> |
| |
| <para>If a hash key used with a node variable can't be interpreted |
| otherwise (see the <link linkend="xgui_imperative_formal">next |
| section</link> for the precise definition), then it will by |
| interpreted as an XPath expression. For more information on XPath, |
| please visit <link |
| xlink:href="http://www.w3.org/TR/xpath">http://www.w3.org/TR/xpath</link>.</para> |
| |
| <para>For example, here we list the <literal>para</literal> elements |
| of the chapter with <literal>title</literal> element (not |
| attribute!) content "Ch1'':</para> |
| |
| <programlisting role="template"><#list doc["book/chapter[title='Ch1']/para"] as p> |
| <p>${p} |
| </#list></programlisting> |
| |
| <para>It will print:</para> |
| |
| <programlisting role="output"> <p>p1.1 |
| <p>p1.2 |
| <p>p1.3</programlisting> |
| |
| <para>The rule with sequences of length 1 (explained in earlier |
| sections) stands for XPath results as well. That is, if the |
| resulting sequence contains exactly 1 node, it also acts as the node |
| itself. For example, print the first paragraph of chapter |
| <quote>Ch1</quote>:</para> |
| |
| <programlisting role="template">${doc["book/chapter[title='Ch1']/para[1]"]}</programlisting> |
| |
| <para>which prints the same as:</para> |
| |
| <programlisting role="template">${doc["book/chapter[title='Ch1']/para[1]"][0]}</programlisting> |
| |
| <para>The context node of the XPath expression is the node (or |
| sequence of nodes) whose hash subvariable is used to issue the XPath |
| expression. Thus, this prints the same as the previous |
| example:</para> |
| |
| <programlisting role="template">${doc.book["chapter[title='Ch1']/para[1]"]}</programlisting> |
| |
| <para>Note that currently you can use a sequence of 0 or multiple |
| (more than 1) nodes as context only if the programmer has set up |
| FreeMarker to use Jaxen instead of Xalan.</para> |
| |
| <para>Also note that XPath indexes sequence items from 1, while FTL |
| indexes sequence items from 0. Thus, to select the first chapter, |
| the XPath expression is <literal>"/book/chapter[1]"</literal>, while |
| the FTL expression is <literal>book.chapter[0]</literal>.</para> |
| |
| <para>If the programmer has set up FreeMarker to use Jaxen instead |
| of Xalan, then FreeMarker variables are visible with XPath variable |
| references:</para> |
| |
| <programlisting role="template"><#assign <emphasis>currentTitle</emphasis> = "Ch1"> |
| <#list doc["book/chapter[title=<emphasis>$currentTitle</emphasis>]/para"] as p> |
| <replaceable>...</replaceable></programlisting> |
| |
| <para>Note that <literal>$currentTitle</literal> is not a FreeMarker |
| interpolation, as there are no <literal>{</literal> and |
| <literal>}</literal> there. That's an XPath expression.</para> |
| |
| <para>The result of some XPath expressions is not a node-set, but a |
| string, a number, or a boolean. For those XPath expressions, the |
| result is an FTL string, number, or boolean variable respectively. |
| For example, the following will count the total number of |
| <literal>para</literal> elements in the XML document, so the result |
| is a number:</para> |
| |
| <programlisting role="template">${x["count(//para)"]}</programlisting> |
| |
| <para>The output will be:</para> |
| |
| <programlisting role="output">5</programlisting> |
| </section> |
| |
| <section> |
| <title>XML namespaces</title> |
| |
| <indexterm> |
| <primary>XML namespace</primary> |
| |
| <secondary>in imperative processing</secondary> |
| </indexterm> |
| |
| <para>Be default, when you write something like |
| <literal>doc.book</literal>, then it will select the element with |
| name <literal>book</literal> that does not belongs to any XML |
| namespace (similarly to XPath). If you want to select an element |
| that is inside an XML namespace, you must register a prefix and use |
| that. For example, if element <literal>book</literal> is in XML |
| namespace <literal>http://example.com/ebook</literal>, then you have |
| to associate a prefix with it at the top of the template with the |
| <literal>ns_prefixes</literal> parameter of the <link |
| linkend="ref.directive.ftl"><literal>ftl</literal> |
| directive</link>:</para> |
| |
| <programlisting role="template"><#ftl ns_prefixes={"e":"http://example.com/ebook"}> |
| </programlisting> |
| |
| <para>And now you can write expressions as |
| <literal>doc["e:book"]</literal>. (The usage of square bracket |
| syntax was required because the colon would confuse FreeMarker |
| otherwise.)</para> |
| |
| <para>As the value of <literal>ns_prefixes</literal> is a hash, you |
| can register multiple prefixes:</para> |
| |
| <programlisting role="template"><#ftl ns_prefixes={ |
| "e":"http://example.com/ebook", |
| "f":"http://example.com/form", |
| "vg":"http://example.com/vectorGraphics"} |
| ></programlisting> |
| |
| <para>The <literal>ns_prefixes</literal> parameter affects the whole |
| <link linkend="dgui_misc_namespace">FTL namespace</link>. This means |
| in practice that the prefixes you have registered in the main page |
| template will be visible in all <literal><#include |
| ...></literal>-d templates, but not in <literal><#imported |
| ...></literal>-d templates (often referred as FTL libraries). Or |
| from another point of view, an FTL library can register XML |
| namespace prefixes for it's own use, without interfering with the |
| prefix registrations of the main template and other |
| libraries.</para> |
| |
| <para>Note that, if an input document is dominated by a given XML |
| namespace, you can set that as the default namespace for |
| convenience. This means that if you don't use prefix, as in |
| <literal>doc.book</literal>, then it selects element that belongs to |
| the default namespace. The setting of the default namespace happens |
| with reserved prefix <literal>D</literal>, for example:</para> |
| |
| <programlisting role="template"><#ftl ns_prefixes={"D":"http://example.com/ebook"}> |
| </programlisting> |
| |
| <para>Now expression <literal>doc.book</literal> select the |
| <literal>book</literal> element that belongs to XML namespace |
| <literal>http://example.com/ebook</literal>. Unfortunately, XPath |
| does not support this idea of a default namespace. Thus, in XPath |
| expressions, element names without prefixes always select the |
| elements that does not belong to any XML namespace. However, to |
| access elements in the default namespace you can directly use prefix |
| <literal>D</literal>, for example: |
| <literal>doc["D:book/D:chapter[title='Ch1']"]</literal>.</para> |
| |
| <para>Note that when you use a default namespace, then you can |
| select elements that does not belong to any node namespace with |
| reserved prefix <literal>N</literal>, for example |
| <literal>doc.book["N:foo"]</literal>. It doesn't go for XPath |
| expressions, where the above can be witten as |
| <literal>doc["D:book/foo"]</literal>.</para> |
| </section> |
| |
| <section> |
| <title>Don't forget escaping!</title> |
| |
| <para>As we generate output of HTML format in these examples, and |
| HTML format reserves characters as <literal><</literal>, |
| <literal>&</literal>, etc., we have to ensure that those will be |
| escaped. For that, either FreeMarker has to be <link |
| linkend="pgui_config_outputformatsautoesc">properly |
| configured</link>, or add <literal>output_format="HTML"</literal> in |
| the template to the <literal>ftl</literal> directive calls.</para> |
| |
| <para>So if the book title is "Romeo & Juliet", the resulting |
| HTML output will be correctly:</para> |
| |
| <programlisting role="output"><replaceable>...</replaceable> |
| <h1>Romeo &amp; Juliet</h1> |
| <replaceable>...</replaceable></programlisting> |
| </section> |
| </section> |
| |
| <section xml:id="xgui_imperative_formal"> |
| <title>Details</title> |
| |
| <para>Every variable that corresponds to a single node in the DOM tree |
| is a multi-type variable of type node and type hash (for programmers: |
| implements both <literal>TemplateNodeModel</literal> and |
| <literal>TemplateHashModel</literal>). Thus, you can use the <link |
| linkend="ref_builtins_node">node built-ins</link> with them. Hash keys |
| are interpreted as XPath expressions, except the special keys shown in |
| the table below. Some of the node variables also have string type, so |
| you can use them as string variables (for programmers: they implement |
| <literal>TemplateScalarModel</literal>).</para> |
| |
| <anchor xml:id="misc.xguiTable"/> |
| |
| <informaltable border="1"> |
| <thead> |
| <tr> |
| <th>Node type (<literal>?node_type</literal>)</th> |
| |
| <th>Node name (<literal>?node_name</literal>)</th> |
| |
| <th>String value (e.g. <literal><p>${node}</literal>)</th> |
| |
| <th>Special hash keys</th> |
| </tr> |
| </thead> |
| |
| <tbody> |
| <tr> |
| <td><literal>"document"</literal></td> |
| |
| <td><literal>"@document"</literal></td> |
| |
| <td>No string value. (Error when you try to use it as |
| string.)</td> |
| |
| <td><literal><replaceable>elementName</replaceable></literal>, |
| <literal>"<replaceable>prefix</replaceable>:<replaceable>elementName</replaceable>"</literal>, |
| <literal>*</literal>, <literal>**</literal>, |
| <literal>@@markup</literal>, <literal>@@nested_markup</literal>, |
| <literal>@@text</literal>, <literal>@@local_name</literal>, |
| <literal>@@qname</literal>, <literal>@@namespace</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>"element"</literal></td> |
| |
| <td><literal>"<replaceable>name</replaceable>"</literal>: the |
| name of the element. This is the local name (i.e. name without |
| namespace prefix).</td> |
| |
| <td>If it has no element children, the text of all text node |
| children concatenated together. Error otherwise, when you try to |
| use it as string.</td> |
| |
| <td><literal><replaceable>elementName</replaceable></literal>, |
| <literal>"<replaceable>prefix</replaceable>:<replaceable>elementName</replaceable>"</literal>, |
| <literal>*</literal>, <literal>**</literal>, |
| <literal>@<replaceable>attrName</replaceable></literal>, |
| <literal>"@<replaceable>prefix</replaceable>:<replaceable>attrName</replaceable>"</literal>, |
| <literal>@@</literal>, <literal>"@*"</literal>, |
| <literal>@@start_tag</literal>, <literal>@@end_tag</literal>, |
| <literal>@@attributes_markup</literal>, |
| <literal>@@next_sibling_element</literal>, |
| <literal>@@previous_sibling_element</literal>, |
| <literal>@@markup</literal>, <literal>@@nested_markup</literal>, |
| <literal>@@text</literal>, <literal>@@local_name</literal>, |
| <literal>@@qname</literal>, <literal>@@namespace</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>"text"</literal></td> |
| |
| <td><literal>"@text"</literal></td> |
| |
| <td>The text itself.</td> |
| |
| <td><literal>@@markup</literal>, |
| <literal>@@nested_markup</literal>, <literal>@@text</literal>, |
| <literal>@@local_name</literal>, <literal>@@qname</literal>, |
| <literal>@@namespace</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>"pi"</literal></td> |
| |
| <td><literal>"@pi$<replaceable>target</replaceable>"</literal></td> |
| |
| <td>The part between the target name and the |
| <literal>?></literal>.</td> |
| |
| <td><literal>@@markup</literal>, |
| <literal>@@nested_markup</literal>, <literal>@@text</literal>, |
| <literal>@@local_name</literal>, <literal>@@qname</literal>, |
| <literal>@@namespace</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>"comment"</literal></td> |
| |
| <td><literal>"@comment"</literal></td> |
| |
| <td>The text of the comment, without the delimiters |
| <literal><!--</literal> and <literal>--></literal>.</td> |
| |
| <td><literal>@@markup</literal>, |
| <literal>@@nested_markup</literal>, <literal>@@text</literal>, |
| <literal>@@local_name</literal>, <literal>@@qname</literal>, |
| <literal>@@namespace</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>"attribute"</literal></td> |
| |
| <td><literal>"<replaceable>name</replaceable>"</literal>: the |
| name of the attribute. This is the local name (i.e. name without |
| namespace prefix).</td> |
| |
| <td>The value of the attribute.</td> |
| |
| <td><literal>@@markup</literal>, |
| <literal>@@nested_markup</literal>, <literal>@@text</literal>, |
| <literal>@@qname</literal>, <literal>@@local_name</literal>, |
| <literal>@@qname</literal>, <literal>@@namespace</literal></td> |
| </tr> |
| |
| <tr> |
| <td><literal>"document_type"</literal></td> |
| |
| <td><literal>"@document_type$<replaceable>name</replaceable>"</literal>: |
| <literal><replaceable>name</replaceable></literal> is the name |
| of the document element.</td> |
| |
| <td>No string value. (Error when you try to use it as |
| string.)</td> |
| |
| <td><literal>@@markup</literal>, |
| <literal>@@nested_markup</literal>, <literal>@@text</literal>, |
| <literal>@@local_name</literal>, <literal>@@qname</literal>, |
| <literal>@@namespace</literal></td> |
| </tr> |
| </tbody> |
| </informaltable> |
| |
| <para>Notes:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>There is no CDATA type. CDATA nodes are transparently |
| considered as text nodes.</para> |
| </listitem> |
| |
| <listitem> |
| <para>These variables do <emphasis>not</emphasis> support |
| <literal>?keys</literal> and <literal>?values</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Element and attribute node names are local names, that is, |
| they do not contain the namespace prefix. The URI of the namespace |
| the node belongs to can be queried with the |
| <literal>?node_namespace</literal> built-in.</para> |
| </listitem> |
| |
| <listitem> |
| <para>XPath expression needs Jaxen (recommended, but please use |
| 1.1-beta-8 or later; <link xlink:href="http://jaxen.org/">download |
| it here</link>) or Apache Xalan classes available, or an error |
| will stop template execution. Note, however, that as some special |
| hash keys hide the XPath expressions of the same meaning, those |
| XPath expressions will work even if there is no XPath |
| implementation available. <phrase role="forProgrammers">If both |
| Xalan and Jaxen is available, FreeMarker will use Xalan, unless |
| you choose Jaxen by calling |
| <literal>freemarker.ext.dom.NodeModel.useJaxenXPathSupport()</literal> |
| from Java.</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para>If Jaxen is used for the XPath support (not Xalan), then |
| FreeMarker variables are visible with XPath variable references |
| (e.g. |
| <literal>doc["book/chapter[title=$currentTitle]"]</literal>).</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Meaning of special hash keys:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal><replaceable>elementName</replaceable></literal>, |
| <literal>"<replaceable>prefix</replaceable>:<replaceable>elementName</replaceable>"</literal>: |
| Returns the sequence of child nodes that are elements of name |
| <literal><replaceable>elementName</replaceable></literal>. (Note |
| that the term <quote>child</quote> means |
| <emphasis>immediate</emphasis> descendant.) The selection is XML |
| name-space aware, unless the XML document was persed with an XML |
| parser that was not in namespace aware mode. In XML name-space |
| aware mode, names without prefix |
| (<replaceable>elementName</replaceable>) selects only elements |
| that doesn't belong to any XML name-space (unless you have |
| registered a default XML namespace), and names with prefix |
| (<replaceable>prefix</replaceable>:<replaceable>elementName</replaceable>) |
| selects only elements that are belonging to the XML namespace |
| denoted by the prefix. The registration of prefixes and the |
| setting of the default XML namespace is done with the |
| <literal>ns_prefixes</literal> parameter of the <link |
| linkend="ref.directive.ftl"><literal>ftl</literal> |
| directive</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>*</literal>: Returns the sequence of all child |
| (direct descendant) <emphasis>element</emphasis> nodes. The |
| sequence will contain the elements in the <quote>document |
| order</quote>, that is, in the order in which the first character |
| of the XML representation of each node occurs (after expansion of |
| general entities).</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>**</literal>: Returns the sequence of all |
| descendant <emphasis>element</emphasis> nodes. The sequence will |
| contain the elements in the document order.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>@<replaceable>attName</replaceable></literal>, |
| <literal>"@<replaceable>prefix</replaceable>:<replaceable>attrName</replaceable>"</literal>: |
| Returns the attribute |
| <literal><replaceable>attName</replaceable></literal> of the |
| element as a sequence of size 1 that contains the attribute node, |
| or as an empty sequence if the attribute does not exist (so to |
| check if an attribute exists use |
| <literal>foo.@<replaceable>attName</replaceable>[0]??</literal>, |
| <emphasis>not</emphasis> |
| <literal>foo.@<replaceable>attName</replaceable>??</literal>). As |
| with special key |
| <literal>"<replaceable>elementName</replaceable>"</literal>, if |
| the length of the sequence is 1, then it also acts as its first |
| subvariable. If no |
| <literal><replaceable>prefix</replaceable></literal> is used, then |
| it returns only attribute that does not use XML namespace (even if |
| you have set a default XML namespace). If a |
| <literal><replaceable>prefix</replaceable></literal> is used, it |
| returns only the attribute that belongs to the XML namespace |
| associated with the |
| <literal><replaceable>prefix</replaceable></literal>. The |
| registration of prefixes is done with the |
| <literal>ns_prefixes</literal> parameter of the <link |
| linkend="ref.directive.ftl"><literal>ftl</literal> |
| directive</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>@@</literal> or <literal>"@*"</literal>: Returns |
| the sequence of attribute nodes belonging to the parent element. |
| This is the same as XPath <literal>@*</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>@@qname</literal>: Returns the full-qualified name |
| of the element (such as <literal>e:book</literal>, in contrast to |
| the local name returned by <literal>?node_name</literal> that is |
| <literal>book</literal>) . The prefix used (as |
| <literal>e</literal>) is chosen based on the prefix registered in |
| the current namespace with the <literal>ns_prefixes</literal> |
| parameter of the <literal>ftl</literal> directive, and not |
| influenced by the prefix used in the source XML document. If you |
| have set a default XML namespace, then for nodes that use that, |
| prefix <literal>D</literal> will be used. For nodes that does not |
| belong to an XML namespace, no prefix is used (even if you have |
| set a default namespace). If there is no prefix registered for the |
| namespace of the node, the result is a non-existent variable |
| (<literal>node.@@qname??</literal> is |
| <literal>false</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>@@local_mame</literal>: The name of the node |
| without the namespace prefix.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>@@namespace</literal>: The namespace URL (not the |
| namespace prefix) of the node.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>@@markup</literal>: This returns the full XML |
| markup of a node, as a string. (Full XML markup means that it also |
| contains the markup of the child nodes, and the markup of the |
| children of the child nodes, and so on.) The markup you get is not |
| necessary the same as the markup in the source XML file, it's just |
| semantically identical. Especially, note that CDATA sections will |
| become to plain text. Also note that depending on how did you |
| wrapped the original XML document with FreeMarker, comment or |
| processing instruction nodes may were removed, and then they will |
| be missing from the output of course. The first outputted start |
| tag will contain |
| <literal>xmlns:<replaceable>prefix</replaceable></literal> |
| attributes for each XML name-spaces used in the outputted XML |
| fragment, and those prefixes will be used in the outputted element |
| and attribute names. These prefixes will be the same as the |
| prefixes registered with the <literal>ns_prefixes</literal> |
| parameter of the <literal>ftl</literal> directive (no prefix will |
| be used for <literal>D</literal>, as it will be registered as the |
| default name-space with an <literal>xmlns</literal> attribute), or |
| if no prefix was assigned for a XML name-space with that, then an |
| arbitrary chosen unused prefix is used.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>@@nested_markup</literal>: This is similar to |
| <literal>@@markup</literal>, but it returns the XML markup of an |
| element without its opening and closing tags. For the document |
| node, it returns the same as <literal>@@markup</literal>. For |
| other node types (text, processing instruction, etc.), it returns |
| an empty string. Unlike with <literal>@@markup</literal>, no |
| <literal>xmlns:<replaceable>prefix</replaceable></literal> |
| attributes will be placed into the output, but regarding the |
| prefixes used in element and attribute names the rules are the |
| same.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>@@text</literal>: This returns the value of all |
| text nodes that occur within the node (all descendant text nodes, |
| not just direct children), concatenated together into a single |
| string. If the node has no text node children, then the result is |
| an empty string.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>@@start_tag</literal>: Returns the markup of the |
| <link linkend="gloss.startTag">start-tag</link> of the element |
| node. As with <literal>@@markup</literal>, the output is not |
| necessary the same as in the original XML document, but it is |
| semantically equivalent with that. Regarding the XML name-spaces |
| (<literal>xmlns:<replaceable>prefix</replaceable></literal> |
| attributes in the output, etc.) the rules are the same as with |
| <literal>"@@markup"</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>@@end_tag</literal>: Returns the markup of the |
| <link linkend="gloss.endTag">end-tag</link> of the element node. |
| As with <literal>@@markup</literal>, the output is not necessary |
| the same as in the original XML document, but it is semantically |
| equivalent with that.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>@@attributes_markup</literal>: Returns the markup |
| of the <link linkend="gloss.attribute">attributes</link> of the |
| element node. As with <literal>@@markup</literal>, the output is |
| not necessary the same as in the original XML document, but it is |
| semantically equivalent with that.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>@@next_sibling_element</literal> (since 2.3.26): |
| The following sibling element of an element node or an empty node |
| sequence if there's no such element. An element counts as a |
| sibling of another element if they are on the same hierarchical |
| level, and there's no other element or non-whitespace character |
| data (text or CDATA) between the two elements. For example in |
| <literal><a/><!-- comment |
| -->&#x20;<b/></literal> the two elements are |
| siblings, but not in <literal><a/>text<b/></literal> |
| or <literal><a/><x/><b/></literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>@@previous_sibling_element</literal> (since |
| 2.3.26): The previous sibling element of an element node or an |
| empty node sequence if there's no such element. See the last point |
| for the meaning of sibling.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <section> |
| <title>Node sequences</title> |
| |
| <para>Many of the special hash keys (indicated in the above list), |
| and XPath expressions that result in node-sets (see the <link |
| xlink:href="http://www.w3.org/TR/xpath">XPath recommendation</link>) |
| return a sequence of nodes.</para> |
| |
| <para>These node sequences, if they store exactly 1 subvariable, |
| will also act as the subvariable itself. For example, |
| <literal>${book.title[0]}</literal> will do the same as |
| <literal>${book.title}</literal>, if there is only one |
| <literal>title</literal> element child of element |
| <literal>book</literal>.</para> |
| |
| <para>Returning an empty node sequence is a normal situation. For |
| example, if in a concrete XML document, element |
| <literal>book</literal> has no child element |
| <literal>chapter</literal>, then <literal>book.chapter</literal> |
| results in an empty node sequence. Beware! This also means, that |
| <literal>book.chaptre</literal> (note the typo) will also return |
| empty node sequence, and will not stop with error. Also, |
| <literal>book.chaptre??</literal> (note the typo) will return |
| <literal>true</literal> because the empty sequence exists, so you |
| have to use <literal>book.chaptre[0]??</literal> for the |
| check.</para> |
| |
| <para>Node sequences that store not 1 nodes (but 0 or more than 1 |
| nodes) also support some of the hash keys described above. Namely, |
| the following special keys are supported:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal><replaceable>elementName</replaceable></literal>, |
| <literal>"<replaceable>prefix</replaceable>:<replaceable>elementName</replaceable>"</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>@<replaceable>attrName</replaceable></literal>, |
| <literal>"@<replaceable>prefix</replaceable>:<replaceable>attrName</replaceable>"</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>@@markup</literal>, |
| <literal>@@nested_markup</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>@@text</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>*</literal>, <literal>**</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>@@</literal>, <literal>"@*"</literal></para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>When you apply one of the above special keys on a node |
| sequence that contains more than 1 or 0 nodes, then for each node in |
| the sequence (where the special key does make sense, e.g. text nodes |
| will be skipped for key <literal>*</literal> or |
| <literal>@foo</literal>), the special key will be applied as it was |
| explained for single nodes, and the results will be concatenated to |
| form the final result. The results will be concatenated in the order |
| as the corresponding nodes occur in the node sequence. The |
| concatenation means string or sequence concatenation depending on |
| the type of the results. If the special key would result in a string |
| for a single node, then for multiple nodes the result is a single |
| string too (the results for the single nodes concatenated), and if |
| the special key would return a sequence for a single node, then for |
| multiple nodes the result is a single sequence too. If there are 0 |
| nodes in the sequence you apply the special key on, the string |
| result is an empty string or an empty sequence respectively.</para> |
| |
| <para>XPath expressions can be used with node sequences. However, |
| for 0 or more than 1 nodes it will work only if you use Jaxen |
| instead of Xalan, because of the limitations of the Xalan XPath |
| implementation.</para> |
| </section> |
| </section> |
| </chapter> |
| |
| <chapter xml:id="xgui_declarative"> |
| <title>Declarative XML processing</title> |
| |
| <indexterm> |
| <primary>XML</primary> |
| |
| <secondary>declarative processing</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>XSLT</primary> |
| </indexterm> |
| |
| <section xml:id="xgui_declarative_basics"> |
| <title>Basics</title> |
| |
| <note> |
| <para>This section uses the DOM tree and the variable made in <link |
| linkend="xgui_expose">a previous chapter</link>.</para> |
| </note> |
| |
| <para>With the imperative approach of XML processing -- this was shown |
| in the previous chapter -- you write an FTL program that walks the |
| tree to find the different kind of nodes. With the declarative |
| approach, you rather define how to handle the different kind of nodes, |
| and then let FreeMarker walk the tree and call the handlers you have |
| defined. This approach is useful for complex XML schemas, where the |
| same element can occur as the child of many other elements. Examples |
| of such schemas are XHTML and XDocBook.</para> |
| |
| <para>The directive you most often use with the declarative approach |
| is the <link |
| linkend="ref.directive.recurse"><literal>recurse</literal> |
| directive</link>. This directive gets a node variable as parameter, |
| and <quote>visits</quote> all its children nodes, one after the other, |
| starting with the first child. <quote>Visiting</quote> a node means |
| that it calls a user-defined directive (like a macro) that has the |
| same name as the name of the child node |
| (<literal>?node_name</literal>). We say on this, that the user-defined |
| directive <emphasis>handles</emphasis> the node. The node that the |
| user-defined directive just handles is available as special variable |
| <literal>.node</literal>. For example, this FTL:</para> |
| |
| <programlisting role="template"><#recurse doc> |
| |
| <#macro book> |
| I'm the book element handler, and the title is: ${.node.title} |
| </#macro></programlisting> |
| |
| <para>will print (I have removed some disturbing white-space form the |
| output):</para> |
| |
| <programlisting role="output">I'm the book element handler, and the title is: Test Book |
| </programlisting> |
| |
| <para>If you call <literal>recurse</literal> without parameter, then |
| it uses <literal>.node</literal>, that is, it visits all children |
| nodes of the node currently handled. So this FTL:</para> |
| |
| <programlisting role="template"><#recurse doc> |
| |
| <#macro book> |
| Book element with title ${.node.title} |
| <#recurse> |
| End book |
| </#macro> |
| |
| <#macro title> |
| Title element |
| </#macro> |
| |
| <#macro chapter> |
| Chapter element with title: ${.node.title} |
| </#macro></programlisting> |
| |
| <para>will print (I have removed disturbing white-space form the |
| output):</para> |
| |
| <programlisting role="output">Book element with title Test Book |
| Title element |
| Chapter element with title: Ch1 |
| Chapter element with title: Ch2 |
| End book</programlisting> |
| |
| <para>You have seen how to define handlers for element nodes, but not |
| how to define handler for the text nodes. Since the name of the |
| handler is the same as the node-name of nodes it handles, and as the |
| node-name of all text nodes is <literal>@text</literal> (see <link |
| linkend="misc.xguiTable">the table</link>), you define handler for the |
| text nodes like this:</para> |
| |
| <programlisting role="template"> |
| <#macro @text>${.node?html}</#macro> |
| </programlisting> |
| |
| <para>Note the <literal>?html</literal>. You have to HTML-escape the |
| text, since you generate output of HTML format.</para> |
| |
| <para>Here it is the template that transforms the XML to complete |
| HTML:</para> |
| |
| <anchor xml:id="misc.example.declarativeBookProcessor"/> |
| |
| <programlisting role="template"><#recurse doc> |
| |
| <#macro book> |
| <html> |
| <head> |
| <title><#recurse .node.title></title> |
| </head> |
| <body> |
| <h1><#recurse .node.title></h1> |
| <#recurse> |
| </body> |
| </html> |
| </#macro> |
| |
| <#macro chapter> |
| <h2><#recurse .node.title></h2> |
| <#recurse> |
| </#macro> |
| |
| <#macro para> |
| <p><#recurse> |
| </#macro> |
| |
| <#macro title> |
| <#-- |
| We have handled this element imperatively, |
| so we do nothing here. |
| --> |
| </#macro> |
| |
| <#macro @text>${.node?html}</#macro></programlisting> |
| |
| <para>and the output will be (now I will honestly include the annoying |
| white-space...):</para> |
| |
| <programlisting role="output"> <html> |
| <head> |
| <title>Test Book</title> |
| </head> |
| <body> |
| <h1>Test Book</h1> |
| |
| |
| <h2>Ch1</h2> |
| |
| |
| <p>p1.1 |
| |
| <p>p1.2 |
| |
| <p>p1.3 |
| |
| |
| <h2>Ch2</h2> |
| |
| |
| <p>p2.1 |
| |
| <p>p2.2 |
| |
| |
| </body> |
| </html> |
| |
| </programlisting> |
| |
| <para>Note that you can reduce substantially the amount of superfluous |
| whitespace in the output by using the <link |
| linkend="ref_directive_t">trim directives</link>, as |
| <literal><#t></literal>. See also: <xref |
| linkend="dgui_misc_whitespace"/></para> |
| |
| <para>You may say that the FTL that did it with imperative approach |
| was much shorter. That's true, but the example XML uses a very simple |
| schema, and as I said, the declarative approach brings its form with |
| XML schemas that are not that firm about what element can occur where. |
| Say, introduce element <literal>mark</literal>, that should color text |
| to red, does not mater where do you use it; in a |
| <literal>title</literal>, or in a <literal>para</literal>. For this, |
| with the declarative approach, you just add a macro:</para> |
| |
| <programlisting role="template"><#macro mark><font color=red><#recurse></font></#macro></programlisting> |
| |
| <para>And then <literal><mark>...</mark></literal> will |
| automatically work everywhere. So for certain XML schemas, declarative |
| XML processing will actually result in shorter, and what is even more |
| important, much clearer FTL-s, than imperative XML processing. It's up |
| to you to decide which approach to use when; don't forget that you can |
| mix the two approaches freely. Say, in an element handler, you can use |
| imperative approach to process the contents of that element.</para> |
| </section> |
| |
| <section xml:id="xgui_declarative_details"> |
| <title>Details</title> |
| |
| <section> |
| <title>Default handlers</title> |
| |
| <para>For some XML node types, there is a default handler, which |
| will handle the node if you haven't defined a handler for the node |
| (i.e. if there is no user-defined directive available with name |
| identical to the node name). Here are these node types, and what the |
| default handler does:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Text node: prints the text as it. Note, that in most |
| applications, this will not be good for you, because you should |
| escape the text before you send it to the output (with |
| <literal>?html</literal> or <literal>?xml</literal> or |
| <literal>?rtf</literal>, ...etc. depends on the output |
| format).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Processing instruction node: call handler called |
| <literal>@pi</literal> if you have created such user-defined |
| directive, otherwise do nothing (ignore the node).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Comment node, document type node: Do nothing (ignore the |
| node).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Document node: Call <literal>recurse</literal>, that is, |
| visit all children of the document node.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Element and attribute nodes will be handled according to the |
| usual, XML independent mechanism. That is, |
| <literal>@<replaceable>node_type</replaceable></literal> will be |
| called as handler, and if that's not defined, then an error stops |
| template processing.</para> |
| |
| <para>In the case of element nodes, this means that if you define a |
| macro (or other kind of user-defined directive) called |
| <literal>@element</literal>, that will catch all element nodes, |
| which has no more specific handler. If you have no |
| <literal>@element</literal> handler, then you |
| <emphasis>must</emphasis> define a handler for all possible |
| elements.</para> |
| |
| <para>Attribute nodes are not visited by the |
| <literal>recurse</literal> directive, so you don't need to write |
| handlers for them.</para> |
| </section> |
| |
| <section> |
| <title>Visiting a single node</title> |
| |
| <para>With the <link |
| linkend="ref.directive.visit"><literal>visit</literal> |
| directive</link> you can visit a single node, instead of the |
| children of the node: |
| <literal><#visit <replaceable>nodeToVisist</replaceable>></literal>. |
| This can be useful sometimes.</para> |
| </section> |
| |
| <section> |
| <title>XML namespaces</title> |
| |
| <indexterm> |
| <primary>XML namespaces</primary> |
| |
| <secondary>in declarative processing</secondary> |
| </indexterm> |
| |
| <para>We said that the name of the handler user-defined directive |
| (like a macro) for an element is the name of the element. In fact, |
| it is the full-qualified name of the element: |
| <literal><replaceable>prefix</replaceable>:<replaceable>elementName</replaceable></literal>. |
| The rules regarding the usage of |
| <literal><replaceable>prefix</replaceable></literal>-es is the same |
| as with imperative processing. Thus, the user-defined |
| <literal>book</literal> directive handles only element |
| <literal>book</literal> that does not belong to any XML namespace |
| (unless you have specified a default XML namespace). So if the |
| example XML would use XML namespace |
| <literal>http://example.com/ebook</literal>:</para> |
| |
| <programlisting role="unspecified"><book xmlns="http://example.com/ebook"> |
| <replaceable>...</replaceable></programlisting> |
| |
| <para>Then the FTL should look as this:</para> |
| |
| <programlisting role="template"><emphasis><#ftl ns_prefixes={"e":"http://example.com/ebook"}></emphasis> |
| |
| <#recurse doc> |
| |
| <#macro "<emphasis>e:</emphasis>book"> |
| <html> |
| <head> |
| <title><#recurse .node["<emphasis>e:</emphasis>title"]></title> |
| </head> |
| <body> |
| <h1><#recurse .node["<emphasis>e:</emphasis>title"]></h1> |
| <#recurse> |
| </body> |
| </html> |
| </#macro> |
| |
| <#macro "<emphasis>e:</emphasis>chapter"> |
| <h2><#recurse .node["<emphasis>e:</emphasis>title"]></h2> |
| <#recurse> |
| </#macro> |
| |
| <#macro "<emphasis>e:</emphasis>para"> |
| <p><#recurse> |
| </#macro> |
| |
| <#macro "<emphasis>e:</emphasis>title"> |
| <#-- |
| We have handled this element imperatively, |
| so we do nothing here. |
| --> |
| </#macro> |
| |
| <#macro @text>${.node?html}</#macro></programlisting> |
| |
| <para>Or, you can define a default XML namespace, and then the |
| further part of the template remains the same as in the original XML |
| namespace free example:</para> |
| |
| <programlisting role="template"><#ftl ns_prefixes={"<emphasis>D</emphasis>":"http://example.com/ebook"}> |
| |
| <#recurse doc> |
| |
| <#macro book> |
| <replaceable>...</replaceable></programlisting> |
| |
| <para>But in this case don't forge that in XPath expressions (we |
| didn't used any in the example) the default XML namespace must be |
| accessed with an explicit <literal>D:</literal> since names without |
| prefix always refer to nodes with no XML namespace in XPath. Also |
| note that with the same logic as with imperative XML processing, the |
| name of handlers for elements that has no XML namespace is |
| <literal>N:<replaceable>elementName</replaceable></literal> if (and |
| only if) there is a default XML namespace. However, for nodes that |
| are not of type element (such as text nodes), you never use the |
| <literal>N</literal> prefix in the handler name, because those nodes |
| are free of the idea of XML namespaces. So for example, the handler |
| for text nodes is always just <literal>@text</literal>.</para> |
| |
| <para>For more detailed information, please read <link |
| linkend="ref_directive_visit">the reference of |
| <literal>recurse</literal> and <literal>visit</literal></link> |
| directives.</para> |
| </section> |
| </section> |
| </chapter> |
| </part> |
| |
| <part xml:id="app"> |
| <title>Appendixes</title> |
| |
| <appendix xml:id="app_faq"> |
| <title>FAQ</title> |
| |
| <indexterm> |
| <primary>FAQ</primary> |
| </indexterm> |
| |
| <qandaset> |
| <qandaentry xml:id="faq_jsp_vs_freemarker"> |
| <question> |
| <para>JSP versus FreeMarker?</para> |
| |
| <indexterm> |
| <primary>JSP</primary> |
| </indexterm> |
| </question> |
| |
| <answer> |
| <para>We compare FreeMarker with the JSP 2.0 + JSTL combo |
| here.</para> |
| |
| <para>FreeMarker Pros:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>FreeMarker is not tied to Servlets or networking/Web; it |
| is just a class library to generate text output by merging a |
| template with Java objects (the data-model). You can execute |
| templates anywhere and anytime; no HTTP request forwarding or |
| similar tricks needed, no Servlet environment needed at all. |
| Because of this you can easily integrate it into any |
| system.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Terser syntax. Consider this JSP (assuming |
| <literal><%@ taglib prefix="c" |
| uri="http://java.sun.com/jsp/jstl/core" |
| %></literal>):</para> |
| |
| <programlisting role="template"><c:if test="${t}"> |
| True |
| </c:if> |
| |
| <c:choose> |
| <c:when test="${n == 123}"> |
| Do this |
| </c:when> |
| <c:otherwise> |
| Do that |
| </c:otherwise> |
| </c:choose> |
| |
| <c:forEach var="i" items="${ls}"> |
| - ${i} |
| </c:forEach></programlisting> |
| |
| <para>and the equivalent FTL:</para> |
| |
| <programlisting role="template"><#if t> |
| True |
| </#if> |
| |
| <#if n == 123> |
| Do this |
| <#else> |
| Do that |
| </#if> |
| |
| <#list ls as i> |
| - ${i} |
| </#list></programlisting> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="dgui_misc_autoescaping">Auto-escaping |
| option</link> to escape HTML and XML special characters |
| printed with |
| <literal>${<replaceable>...</replaceable>}</literal>. So you |
| can just write <literal>${x}</literal> instead of |
| <literal><c:out value="${x}"/></literal>, and most |
| importantly, you can't accidentally forget to do |
| escaping.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Locale-sensitive number and date formatting by default. |
| When you output for a human audience, all you need to do is |
| just write <literal>${x}</literal> rather than |
| <literal><fmt:formatNumber value="${x}" |
| /></literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>No servlet specific scopes and other highly technical |
| things in templates (unless, of course, you expose them into |
| the data-model deliberately). It was made for MVC from the |
| beginning, it focuses only on the presentation.</para> |
| </listitem> |
| |
| <listitem> |
| <para>You can load the templates from anywhere; from the class |
| path, from a data-base, etc.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Easier to define ad-hoc macros and functions.</para> |
| </listitem> |
| |
| <listitem> |
| <para>No sweeping errors under the carpet. Missing variables |
| and <literal>null</literal>-s will not silently default to |
| <literal>0</literal>/<literal>false</literal>/empty-string, |
| but cause error. <link |
| linkend="faq_picky_about_missing_vars">See more about this |
| here...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><quote>Object wrapping</quote>. This lets you show the |
| objects to templates in a customized, presentation oriented |
| way (e.g. <link linkend="xgui_imperative_learn">see |
| here</link> how a W3C DOM nodes can be seen by templates using |
| this technology.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Macros and functions are just variables, so they can be |
| easily passed around as parameter values, put into the |
| data-model, etc., just like any other values.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Virtually unnoticeable delay when visiting a page for |
| the first time (or after it was changed), because no expensive |
| compilation happens.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>FreeMarker Cons:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Not a <quote>standard</quote>. There are fewer tools and |
| IDE integrations, fewer developers knows it and there's much |
| less industry support in general. (However, most JSP tag |
| libraries can work in FreeMarker templates with the proper |
| setup, unless they are base on <literal>.tag</literal> |
| files.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Its syntax doesn't follow the HTML/XML rules apart from |
| some visual similarity, which is confusing for new users (it's |
| the price of the terseness). JSP doesn't follow it either, but |
| it's closer to it.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Since macros and functions are just variables, incorrect |
| directive and parameter names and missing required parameters |
| can be detected only on runtime.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Doesn't work with JSF. (It could work technically, but |
| nobody has implemented that yet.)</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>You may read this if you are considering replacing JSP with |
| FreeMarker in an existing application or in a legacy framework |
| that only supports JSP: <xref |
| linkend="pgui_misc_servlet_model2"/></para> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_picky_about_missing_vars"> |
| <question> |
| <para>Why is FreeMarker so picky about <literal>null</literal>-s |
| and missing variables, and what to do with it?</para> |
| </question> |
| |
| <answer> |
| <para>To recapitulate what's this entry is about: FreeMarker by |
| default treats an attempt to access a non-existent variable or a |
| <literal>null</literal> value (<link linkend="faq_null">this two |
| is the same for FreeMarker</link>) as error, which aborts the |
| template execution.</para> |
| |
| <para>First of all, you should understand the reason of being |
| picky. Most scripting languages and template languages are rather |
| forgiving with missing variables (and with |
| <literal>null</literal>-s), and they usually treat them as empty |
| string and/or 0 and/or logical false. This behavior has several |
| problems:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>It potentially hides accidental mistakes, like a typo in |
| a variable name, or when the template author refers to a |
| variable that the programmer doesn't put into the data-model |
| for that template, or for which the programmer uses a |
| different name. Humans are prone to do such mistakes, while |
| computers are not, so missing this opportunity that the |
| template engine can show these errors is a bad business. Even |
| if you very carefully check the output of the templates during |
| development, it is easy to look over mistakes like |
| <literal><#if hasWarnigs><replaceable>print warnings |
| here...</replaceable></#if></literal>, which would then |
| silently never print the warnings, since you have mistyped the |
| variable name (have you noticed it?). Also think about |
| maintenance, when you later modify your application; probably |
| you will not re-check templates (many applications has |
| hundreds of them) that carefully each time, for all possible |
| scenarios. Unit tests typically doesn't cover web page content |
| very good either (if you have them at all...); they mostly |
| only check certain manually set patterns in the web page, so |
| they will often gloss though changes that are actually bugs. |
| But if the page fails with exception, that's something human |
| testers will notice and unit test will notice (as the whole |
| page will fail), and in production the maintainers will notice |
| (assuming somebody check error logs).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Makes dangerous assumptions. The script language or |
| template engine knows nothing about the application domain, so |
| when it decides the value of something that it doesn't know to |
| be 0/false, it is a quite irresponsible and arbitrary thing. |
| Just because it's not know what's your current balance at your |
| bank, can we just say it's $0? Just because it is not known if |
| a patient has penicillin allergy, can we just say he/she |
| doesn't have it? Just consider the implications of such |
| mistakes. Showing an error page is often better than showing |
| incorrect information that looks good, leading to bad |
| decisions on the user side.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Being not picky is mostly sweeping under the carpet in this |
| case (not facing the problems), which of course most people feels |
| more convenient, but still, we believe that in most cases being |
| strict will save your time and increase your software quality on |
| the long run.</para> |
| |
| <para>On the other hand, we recognize that there are cases where |
| you don't want FreeMarker to be that picky for good reason, and |
| there is solution for them:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>It's often normal that your data-model contains |
| <literal>null</literal>-s or have optional variables. In such |
| cases use <link linkend="dgui_template_exp_missing">these |
| operators</link>. If you use them too often, try to rethink |
| your data-model, because depending on them too much won't just |
| make the templates too verbose, but increases the probability |
| of hiding errors and printing arbitrary incorrect output (for |
| the reasons described earlier).</para> |
| </listitem> |
| |
| <listitem> |
| <para>In some application you may rather want to show an |
| incomplete/damaged page than an error page. In this case you |
| can <link linkend="pgui_config_errorhandling">use another |
| error handler</link> than the default one. A custom error |
| handler can skip the problematic part, or show an error |
| indicator there, instead of aborting the whole page rendering. |
| Note, however, that although the error handlers don't give |
| arbitrary default values to variables, for pages that show |
| critical information it's maybe still better to show an error |
| page.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If the pages contain parts that aren't critically |
| important (like some side bars), another feature you may |
| interested in is <link linkend="ref_directive_attempt">the |
| <literal>attempt</literal>/<literal>recover</literal> |
| directives</link>.</para> |
| </listitem> |
| </itemizedlist> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_number_grouping"> |
| <question> |
| <para>Why does FreeMarker print the numbers with strange |
| formatting (as 1,000,000 or 1Â 000Â 000 instead of 1000000)?</para> |
| </question> |
| |
| <answer> |
| <para>FreeMarker uses the locale-sensitive number formatting |
| capability of the Java platform. The default number format for |
| your locale may use grouping or other formatting. If you don't |
| want that, you have to override the number format suggested by the |
| Java platform with the <literal>number_format</literal> <link |
| linkend="pgui_config_settings">FreeMarker setting</link>. For |
| example:</para> |
| |
| <programlisting role="unspecified">cfg.setNumberFormat("0.######"); // now it will print 1000000 |
| // where cfg is a freemarker.template.Configuration object</programlisting> |
| |
| <para>Note however than humans often find it hard to read big |
| numbers without grouping separator. So in general it is |
| recommended to keep them, and in cases where the numbers are for |
| ''computer audience'' (which is confused on the grouping |
| separators), use the <link |
| linkend="ref_builtin_c"><literal>c</literal> built-in</link>. For |
| example:</para> |
| |
| <programlisting role="template"><a href="/shop/productdetails?id=${<emphasis>product.id?c</emphasis>}">Details...</a></programlisting> |
| |
| <para>For computer audience you need <literal>?c</literal> anyway, |
| as the decimal separators can also wary depending on the |
| locale.</para> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_number_decimal_point"> |
| <question> |
| <para>Why does FreeMarker print bad decimal and/or grouping |
| separator symbol (as 3.14 instead of 3,14)?</para> |
| </question> |
| |
| <answer> |
| <para>Different countries use different decimal/grouping separator |
| symbols. If you see incorrect symbols, then probably your locale |
| is not set properly. Set the default locale of the JVM or override |
| the default locale with the <literal>locale</literal> <link |
| linkend="pgui_config_settings">FreeMarker setting</link>. For |
| example:</para> |
| |
| <programlisting role="unspecified">cfg.setLocale(java.util.Locale.ITALY); |
| // where cfg is a freemarker.template.Configuration object</programlisting> |
| |
| <para>However, sometimes you want to output a number not for human |
| audience, but for <quote>computer audience</quote> (like you want |
| to print a size in CSS), in which case you must use dot as decimal |
| separator, regardless of the locale (language) of the page. For |
| that use the <link linkend="ref_builtin_c"><literal>c</literal> |
| built-in</link>, for example:</para> |
| |
| <programlisting role="template">font-size: ${<emphasis>fontSize?c</emphasis>}pt;</programlisting> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_number_boolean_formatting"> |
| <question> |
| <para>Why does FreeMarker give an error when I try to print a |
| boolean like <literal>${aBoolean}</literal>, and how to fix |
| it?</para> |
| </question> |
| |
| <answer> |
| <para><literal>${<replaceable>...</replaceable>}</literal> meant |
| to format values for human consumption, and unlike numbers, |
| booleans has no commonly accepted format |
| (<literal>true</literal>/<literal>false</literal> is common in |
| computer languages, but you rarely use it outside that). The |
| proper format depends quite much on the context, therefore, |
| usually the template author should decide the proper format for |
| each case, like <literal>${washable?string("yes", |
| "no")}</literal>, <literal>${caching?string("Enabled", |
| "Disabled")}</literal>, <literal>${heating?string("on", |
| "off")}</literal>, etc.</para> |
| |
| <para>However, there are two cases where this gets |
| impractical:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>When printing boolean to generate computer language |
| output, and hence you want |
| <literal>true</literal>/<literal>false</literal>. In such case |
| use <literal>${<replaceable>someBoolean</replaceable><link |
| linkend="ref_builtin_c_boolean">?c</link>}</literal> (requires |
| FreeMarker 2.3.20). If you never generate for human |
| consumption, only for computer language output, you might want |
| to set <literal>boolean_format</literal> to |
| <literal>c</literal> (available since FreeMarker 2.3.29), and |
| then <literal>${<replaceable>aBoolean</replaceable>}</literal> |
| will behave as |
| <literal>${<replaceable>aBoolean</replaceable>?c}</literal>.</para> |
| |
| <para>Before 2.3.20, if you really can't upgrade FreeMarker, |
| try if |
| <literal>${<replaceable>someBoolean</replaceable>?string}</literal>. |
| By default that prints |
| <literal>true</literal>/<literal>false</literal>. Then somehow |
| try to ensure that <literal>boolean_format</literal> won't be |
| changed later by someone, breaking your output.</para> |
| </listitem> |
| |
| <listitem> |
| <para>When you have format most of the booleans on the same |
| way. In this case you can set the |
| <literal>boolean_format</literal> setting |
| (<literal>Configuration.setBooleanFormat</literal>) to reflect |
| that, and then since FreeMarker 2.3.20 you can just write |
| <literal>${<replaceable>someBoolean</replaceable>}</literal>. |
| (Note that this doesn't work for |
| <literal>true</literal>/<literal>false</literal> though - you |
| have to use <literal>?c</literal> there.)</para> |
| </listitem> |
| </itemizedlist> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_template_not_found"> |
| <question> |
| <para>FreeMarker can't find my templates |
| (<literal>TemplateNotFoundException</literal> or |
| <literal>FileNotFoundException</literal>, <quote>Template not |
| found</quote> error message)</para> |
| </question> |
| |
| <answer> |
| <para>First of all, you should know that FreeMarker doesn't load |
| templates from file system paths directly. Instead, it uses a |
| simple virtual file system that might reads non-filesystem |
| resources (templates from inside jar-s, from inside a database |
| table, etc.). What that virtual file is decided by a configuration |
| setting, |
| <literal>Configuration.setTemplateLoader(TemplateLoader)</literal>. |
| Even if the <literal>TemplateLoader</literal> your are using maps |
| to the file system, it will have a base directory that contains |
| all the templates, and that will be the root of your virtual file |
| system that you can't reach out from (i.e., absolute paths will be |
| still relative to the virtual file system root).</para> |
| |
| <para>Tips to solve the problem:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>If you are the one who configure FreeMarker, be sure |
| that you set a proper |
| <literal>TemplateLoader</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Otherwise see if the template-not-found error's message |
| contains the description of the |
| <literal>TemplateLoader</literal> used. If it doesn't, you are |
| using an old FreeMarker version, so update it. Getting |
| <literal>FileNotFoundException</literal> instead of |
| <literal>TemplateNotFoundException</literal> is also a sign of |
| that, and so you will get less helpful error messages. (If the |
| <literal>TemplateLoader</literal> in the error message is like |
| <literal>foo.SomeTemplateLoader@64f6106c</literal> and so |
| doesn't show some relevant parameters, you may should ask the |
| author to define a nicer |
| <literal>toString()</literal>.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>A frequent mistake is using a |
| <literal>FileTemplateLoader</literal> for a Servlet-based web |
| application, instead of a |
| <literal>WebappTemplateLoader</literal>. It may works in one |
| environment, but not in another, as the Servlet specification |
| makes no promises about your resources being accessible as |
| plain files, not even when the <literal>war</literal> file is |
| extracted.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Know that when you are including/importing a template |
| from another template, if you don't start the template name |
| with <literal>/</literal>, it will be interpreted relatively |
| to the directory of the including template. The error message |
| contains the full (resolved) name, so you should notice this |
| there.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Check that you aren't using <literal>\</literal> |
| (backslash) instead of <literal>/</literal> (slash). |
| (FreeMarker 2.3.22 and later will warn you about that in the |
| error message.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>As a last resort, turn on debug level logging (in the |
| logging framework that you are using) for the category |
| <literal>freemarker.cache</literal>, to see more of what's |
| going on.</para> |
| </listitem> |
| </itemizedlist> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_check_version"> |
| <question> |
| <para>The documentation writes about feature |
| <replaceable>X</replaceable>, but it seems that FreeMarker doesn't |
| know that, or it behaves in a different way as documented, or a |
| bug that was supposedly fixed is still present.</para> |
| </question> |
| |
| <answer> |
| <para>Are you sure that you are using the documentation written |
| for the same version of FreeMarker that you actually use? |
| Especially, note that our online documentation is for the latest |
| stable FreeMarker release. You may use an older release; update |
| it.</para> |
| |
| <para>Are you sure that the Java class loader finds the same |
| <literal>freemarker.jar</literal> that you expect to use? Maybe |
| there is an older version of <literal>freemarker.jar</literal> |
| around, which shadows the never. To check this, try to print the |
| version number in a template with <literal>${.version}</literal>. |
| (If it dies with <quote>Unknown built-in variable: version</quote> |
| error message, then you use a very, very old release.).</para> |
| |
| <para>If you suspect that the problem is that you have multiple |
| <literal>freemarker.jar</literal>-s, the typical culprit is that |
| some module has a Maven or Ivy dependency with the old |
| <literal>freemarker</literal> group ID, as opposed to the more |
| modern <literal>org.freemarker</literal> group ID. Because of the |
| different group ID-s these aren't seen as conflicting artifacts by |
| Maven or Ivy, and so both version gets in. In this case you have |
| to exclude the <literal>freemarker</literal> dependency.</para> |
| |
| <para>If you think that the documentation or FreeMarker is wrong, |
| please report it using the bug tracker, or the mailing list. Thank |
| you!</para> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_alternative_syntax"> |
| <question> |
| <para>The <literal><</literal> and <literal>></literal> of |
| FreeMarker tags confuses my editor or the XML parser. What to |
| do?</para> |
| </question> |
| |
| <answer> |
| <para>You can use <literal>[</literal> and <literal>]</literal> |
| instead of <literal><</literal> and <literal>></literal>; |
| see more about square bracket tag syntax <link |
| linkend="dgui_misc_alternativesyntax">here.</link> The comparison |
| operators, like <literal><</literal>, also have an alternative |
| syntax (<literal>lt</literal> and <literal>&lt;</literal> in |
| this case); see more about them <link |
| linkend="dgui_template_exp_comparison">here</link>. Also, the |
| <literal>&&</literal> operator (which is not well-format |
| HTML/XML) can be written as <literal>\and</literal> or |
| <literal>&amp;&amp;</literal> since 2.3.27.</para> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_alternative_syntax_interpolation"> |
| <question> |
| <para><literal>${<replaceable>...</replaceable>}</literal> and/or |
| <literal>#{<replaceable>...</replaceable>}</literal> is used in |
| the output I have to generate a lot, and FreeMarker tries to |
| resolve them. What to do?</para> |
| </question> |
| |
| <answer> |
| <para>You can escape them like |
| <literal>${'$'}{<replaceable>...</replaceable>}</literal>, however |
| that's impractical if you have to do that often. So starting from |
| FreeMarker 2.3.28 you can use |
| <literal>[=<replaceable>...</replaceable></literal><literal>]</literal> |
| instead; see more about the square bracket interpolation syntax |
| <link linkend="dgui_misc_alternativesyntax">here.</link> If you |
| are going to generate JSP files or even FreeMarker templates, this |
| is very useful.</para> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_legal_variable_names"> |
| <question> |
| <para>What are the legal variable names?</para> |
| |
| <indexterm> |
| <primary>variables</primary> |
| |
| <secondary>names</secondary> |
| </indexterm> |
| </question> |
| |
| <answer> |
| <para>FreeMarker has no limitations regarding the characters used |
| in variable names, nor regarding the length of the variable names, |
| but for your convenience try to chose variable names that can be |
| used with the simple variable reference expressions (see it <link |
| linkend="dgui_template_exp_var_toplevel">here</link>). If you have |
| to choose a more extreme variable name, that's not a big problem |
| either: <link linkend="faq_strange_variable_name">see |
| here</link>.</para> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_strange_variable_name"> |
| <question> |
| <para>How can I use variable names (macro name, parameter name) |
| that contain minus sign (<literal>-</literal>), colon |
| (<literal>:</literal>), dot (<literal>.</literal>), or or other |
| special characters?</para> |
| </question> |
| |
| <answer> |
| <para>If you have a variable with strange name like |
| <quote>foo-bar</quote>, FreeMarker will misunderstand what you |
| mean if you just use it like in <literal>${foo-bar}</literal>. In |
| this case, it will believe that you want to subtract the value of |
| <literal>bar</literal> from <literal>foo</literal>. This FAQ entry |
| explains how to handle situations like this.</para> |
| |
| <para>First of all it should be clear that these are just |
| syntactical problems, as otherwise FreeMarker has no limitations |
| regarding the characters used in variable names, nor regarding the |
| length of them.</para> |
| |
| <para>If the special character is one of minus sign |
| (<literal>-</literal>, UCS 0x2D) or dot (<literal>.</literal>, UCS |
| 0x2E) or colon (<literal>:</literal>, UCS 0x3A), then all you have |
| to do is putting a backslash (<literal>\</literal>) before these |
| characters, like in <literal>foo\-bar</literal> (since FreeMarker |
| 2.3.22). Then FreeMarker will know that you didn't mean the |
| operator with the same symbol. This works everywhere where you |
| specify unquoted identifiers, like for macro and function names, |
| parameter names, and all kind of variable references in general. |
| (Note that these escapes only work in identifiers, not in string |
| literals.)</para> |
| |
| <para>When the special character is not one of minus sign, dot, or |
| colon, then it gets trickier. Let's say the problematic variable |
| name is <quote>a+b</quote>. Then:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>If you want to read the variable: If it's a subvariable |
| of something, you can write |
| <literal>something["a+b"]</literal> (remember, |
| <literal>something.x</literal> is equivalent to |
| <literal>something["x"])</literal>. If it's a top-level |
| variable, those are accessible through the special hash |
| variable ,<literal>.vars</literal>, so you can write |
| <literal>.vars["a+b"]</literal>. Naturally, this trick works |
| with macro and function invocations too: |
| <literal><@.vars["a+b"]/></literal>, |
| <literal>.vars["a+b"](1, 2)</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If you want to create or modify the variable: All |
| directives that let you create or modify a variable (such as |
| <literal>assign</literal>, <literal>local</literal>, |
| <literal>global</literal>, <literal>macro</literal>, |
| <literal>function</literal>, etc.) allows the quotation of the |
| destination variable name. For example, <literal><#assign |
| foo = 1></literal> is the same as <literal><#assign |
| "foo" = 1></literal>. So you can write things like |
| <literal><#assign "a+b" = 1></literal> and |
| <literal><#macro "a+b"></literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Unfortunately, you can't use such a variable name (that |
| contains special characters other than <literal>-</literal>, |
| <literal>.</literal> and <literal>:</literal>) as macro |
| parameter name.</para> |
| </listitem> |
| </itemizedlist> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_jsp_custom_tag_syntax"> |
| <question> |
| <para>Why do I get "java.lang.IllegalArgumentException: argument |
| type mismatch" when I try to use <replaceable>X</replaceable> JSP |
| custom tag?</para> |
| </question> |
| |
| <answer> |
| <para>Fist of all, update FreeMarker, because 2.3.22 and later |
| gives a much more helpful error message, that pretty much answers |
| the question. Anyway, the reason is as follows. On JSP pages you |
| quote all parameter (attribute) values, it does not mater if the |
| type of the parameter is string or boolean or number. But since |
| custom tags are accessible in FTL templates as plain user-defined |
| FTL directives, you have to use the FTL syntax rules inside the |
| custom tags, not the JSP rules. Thus, according to FTL rules, you |
| must not quote boolean and numerical parameter values, or they are |
| interpreted as string values, and this will cause a type mismatch |
| error when FreeMarker tries to pass the value to the custom tag |
| that expects non-string value.</para> |
| |
| <para>For example, the <literal>flush</literal> parameter to |
| Struts Tiles <literal>insert</literal> tag is boolean. In JSP the |
| correct syntax was:</para> |
| |
| <programlisting role="template"><tiles:insert page="/layout.jsp" <emphasis>flush="true"</emphasis>/> |
| <replaceable>...</replaceable></programlisting> |
| |
| <para>but in FTL you should write:</para> |
| |
| <programlisting role="template"><@tiles.insert page="/layout.ftl" <emphasis>flush=true</emphasis>/> |
| <replaceable>...</replaceable></programlisting> |
| |
| <para>Also, for similar reasons, this is wrong:</para> |
| |
| <programlisting role="template"><tiles:insert page="/layout.jsp" <emphasis>flush="${needFlushing}"</emphasis>/> |
| <replaceable>...</replaceable></programlisting> |
| |
| <para>and you should write:</para> |
| |
| <programlisting role="template"><tiles:insert page="/layout.jsp" <emphasis>flush=needFlushing</emphasis>/> |
| <replaceable>...</replaceable></programlisting> |
| |
| <para>(Not <literal>flush=${needFlushing}</literal>!)</para> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_servlet_include"> |
| <question> |
| <para>How to include other resources in a way as |
| <literal>jsp:include</literal> does it?</para> |
| </question> |
| |
| <answer> |
| <para>Not with <literal><#include ...></literal>, as that |
| just includes another FreeMarker template without involving the |
| Servlet container.</para> |
| |
| <para>Since the inclusion method you look for is Servlet-related, |
| and pure FreeMarker is unaware of Servlets or even HTTP, it's the |
| Web Application Framework that decides if you can do this and if |
| so how. For example, in Struts 2 you can do this like this:</para> |
| |
| <programlisting role="template"><@s.include value="/WEB-INF/just-an-example.jspf" /></programlisting> |
| |
| <para>If the FreeMarker support of the Web Application Framework |
| is based on |
| <literal>freemarker.ext.servlet.FreemarkerServlet</literal> |
| (<literal>freemarker.ext.jakarta.servlet.FreemarkerServlet</literal>), |
| then you can also do this (since FreeMarker 2.3.15):</para> |
| |
| <programlisting role="template"><@include_page path="/WEB-INF/just-an-example.jspf" /></programlisting> |
| |
| <para>but if the Web Application Framework provides its own |
| solution, then you may prefer that, after all it may does |
| something special.</para> |
| |
| <para>For more information about <literal>include_page</literal> |
| <link linkend="pgui_misc_servlet_include">read |
| this...</link></para> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_parameter_unwrapping"> |
| <question> |
| <para>How can I get the parameters to my |
| plain-Java-method/<literal>TemplateMethodModelEx</literal>/<literal>TemplateTransformModel</literal>/<literal>TemplateDirectiveModel</literal> |
| implementation as plain |
| <literal>java.lang.*</literal>/<literal>java.util.*</literal> |
| objects?</para> |
| </question> |
| |
| <answer> |
| <para>Unfortunately, there is no simple general-purpose solution |
| for this problem. The problem is that FreeMarker object wrapping |
| is very flexible, which is good when you access variables from |
| templates, but makes unwrapping on the Java side a tricky |
| question. For example, it is possible to wrap a |
| non-<literal>java.util.Map</literal> object as |
| <literal>TemplateHashModel</literal> (FTL hash variable). But |
| then, it can't be unwrapped to <literal>java.util.Map</literal>, |
| since there is no wrapped <literal>java.util.Map</literal> around |
| at all.</para> |
| |
| <para>So what to do then? Basically there are two cases:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Directives and methods that are written for presentation |
| purposes (like kind of <quote>tools</quote> for helping |
| FreeMarker templates) should declare their arguments as |
| <literal>TemplateModel</literal>-s and the more specific sub |
| interfaces of that. After all, the object wrapping is about |
| transforming the data-model to something that serves the |
| purpose of the presentation layer, and these methods are part |
| of the presentation layer. If you still need a plain Java type |
| there, you may turn to the |
| <literal>ObjectWrapperAndUnwrapper</literal> interface of the |
| current <literal>ObjectWrapper</literal> (can be get with |
| <literal>Environment.getObjectWrapper()</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Methods that are not for presentation related tasks (but |
| for business logic and like) should be implemented as plain |
| Java methods, and should not use any FreeMarker specific |
| classes at all, since according the MVC paradigm they must be |
| independent of the presentation technology (FreeMarker). If |
| such a method is called from a template, then it is the |
| responsibility of the <link |
| linkend="pgui_datamodel_objectWrapper">object wrapper</link> |
| to ensure the conversion of the arguments to the proper type. |
| If you use the <link |
| linkend="pgui_datamodel_defaultObjectWrapper"><literal>DefaultObjectWrapper</literal></link> |
| or the <link |
| linkend="pgui_misc_beanwrapper"><literal>BeansWrapper</literal></link> |
| then this will happen automatically. For |
| <literal>DefaultObjectWrapper</literal>, this mechanism works |
| much better, if you <link |
| linkend="topic.defaultObjectWrapperIcI">set its |
| <literal>incompatibleImprovements</literal> to |
| 2.3.22</link>.</para> |
| </listitem> |
| </itemizedlist> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_nonstring_keys"> |
| <question> |
| <para>Why I can't use non-string key in the |
| <literal>myMap[myKey]</literal> expression? And what to do |
| now?</para> |
| |
| <indexterm> |
| <primary>hash</primary> |
| |
| <secondary>key type</secondary> |
| </indexterm> |
| </question> |
| |
| <answer> |
| <para>The <quote>hash</quote> type of the FreeMarker Template |
| Language (FTL) is not the same as Java's <literal>Map</literal>. |
| FTL's hash is an associative array too, but it uses string keys |
| exclusively. This is because it was introduced for sub variables |
| (as <literal>password</literal> in |
| <literal>user.password</literal>, which is the same as |
| <literal>user["password"]</literal>), and variable names are |
| strings.</para> |
| |
| <para>If you only need to list the key-value pairs of a |
| <literal>Map</literal>, you can just write something like |
| <literal><#list myMap as k, v>${k}: |
| ${v}</#list></literal> (see more about <link |
| linkend="ref.directive.list">the <literal>list directive</literal> |
| here</link>). This enumerates the <literal>Map</literal> entries, |
| and supports non-string keys. This requires FreeMarker 2.3.25 or |
| later. (If for some reason you can't upgrade to 2.3.25, you can |
| use the Java API of <literal>Map</literal> instead, like |
| <literal><#list myMap?api.entrySet() as kvp>${kvp.key}: |
| ${kvp.value}</#list></literal>.)</para> |
| |
| <para>If you need to do more than listing, you will have to turn |
| to the Java API of the <literal>Map</literal>. You can do it like |
| this: <literal>myMap?api.get(nonStringKey)</literal>. However, for |
| <literal>?api</literal> to be enabled, you may need to configure |
| FreeMarker a bit (<link linkend="ref_buitin_api_and_has_api">see |
| more here</link>).</para> |
| |
| <para>Note that as Java's <literal>Map</literal> is particular |
| about the exact class of the key, at least for numerical keys |
| calculated inside the templates you will have to cast them to the |
| proper Java type, otherwise the item will not be found. For |
| example if you use <literal>Integer</literal> keys in a Map, then |
| you should write <literal>${myMap.get(numKey?int)}</literal>. This |
| is because of FTL's deliberately simplified type system has only a |
| single numerical type, while Java distinguishes a lot of numerical |
| types. Note that the casting is not needed when the key value |
| comes directly from the data-model (i.e., you didn't modified its |
| value with arithmetical calculations in the template), including |
| the case when it's the return value of a method, and it was of the |
| proper class before wrapping, because then the result of the |
| unwrapping will be of the original type.</para> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_simple_map"> |
| <question> |
| <para>When I list the contents of a map (a hash) with |
| <literal>?keys</literal>/<literal>?values</literal>, I get the |
| <literal>java.util.Map</literal> methods mixed with the real map |
| entries. Of course, I only want to get the map entries.</para> |
| </question> |
| |
| <answer> |
| <para>Certainly you are using pure <literal>BeansWrapper</literal> |
| as your object wrapper (instead of the default, |
| <literal>DefaultObjectWrapper</literal>), or a custom subclass of |
| it, and the <literal>simpleMapWrapper</literal> property of that |
| is left to <literal>false</literal>. Unfortunately, that's the |
| default of <literal>BeansWrapper</literal> (for backward |
| compatibility), so you have to explicitly set it to |
| <literal>true</literal> where you instantiate it. Also, at least |
| since 2.3.22, applications should just use |
| <literal>DefaultObjectWrapper</literal> (with <link |
| linkend="topic.defaultObjectWrapperIcI">its |
| <literal>incompatibleImprovements</literal> set to at least |
| 2.3.22</link> - that's especially important if you are switching |
| from pure <literal>BeansWrapper</literal>), which never had this |
| problem.</para> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_modify_seq_and_map"> |
| <question> |
| <para>How can I modify sequences (lists) and hashes (maps) in |
| FreeMarker templates?</para> |
| |
| <indexterm> |
| <primary>modify hashes</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>modify sequences</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>sequence</primary> |
| |
| <secondary>modify</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>hash</primary> |
| |
| <secondary>modify</secondary> |
| </indexterm> |
| </question> |
| |
| <answer> |
| <para>First of all, you may don't want to modify the |
| sequence/hash, just concatenate (add) two or more of them, which |
| results in a new sequence/hash, rather than modifying an existing |
| one. In this case use the <link |
| linkend="dgui_template_exp_sequenceop_cat">sequence |
| concatenation</link> and <link |
| linkend="dgui_template_exp_hashop_cat">hash concatenation |
| operators</link>. Also, you may use the <link |
| linkend="dgui_template_exp_seqenceop_slice">subsequence |
| operator</link> instead of removing sequence items. However, be |
| aware of the performance implications: these operations are fast, |
| but the hashes/sequences that are the result of many subsequent |
| applications of these operations (i.e., when you use the result of |
| the operation as the input of yet another operation, and so on) |
| will be slow to read.</para> |
| |
| <para>Now if you still want to modify sequences/hashes, then read |
| on...</para> |
| |
| <para>The FreeMarkes Template Language doesn't support the |
| modification of sequences/hashes. It's for displaying already |
| calculated things, not for calculating data. Keep templates |
| simple. But don't give it up, you will see some advices and tricks |
| bellow.</para> |
| |
| <para>The best is if you can divide the work between the |
| data-model builder program and the template so that the template |
| doesn't need to modify sequences/hashes. Maybe if you rethink your |
| data-model, you will realize this is possible. But, seldom there |
| are cases where you need to modify sequences/hashes for some |
| complex but purely presentation related algorithms. It seldom |
| happens, so think twice whether that calculation (or parts of it) |
| rather belongs to the data-model domain than to the presentation |
| domain. Let's assume you are sure it belongs to the presentation |
| domain. For example, you want to display a keyword index on some |
| very smart way, whose algorithm need you to create and write some |
| sequence variables. Then you should do something like this (ugly |
| situations has ugly solutions...):</para> |
| |
| <programlisting role="template"><#assign caculatedResults = |
| 'com.example.foo.SmartKeywordIndexHelper'?new().calculate(keywords)> |
| <#-- some simple algorithms comes here, like: --> |
| <ul> |
| <#list caculatedResults as kw> |
| <li><a href="${kw.link}">${kw.word}</a> |
| </#list> |
| </ul></programlisting> |
| |
| <para>That is, you move out the complex part of the presentation |
| task from the template into Java code. Note that it doesn't affect |
| the data-model, so the presentation is still kept separated from |
| other the other application logic. Of course the drawback is that |
| for this the template author will need the help of a Java |
| programmer, but for complex algorithms that's probably needed |
| anyway.</para> |
| |
| <para>Now, if you still say you need to modify sequences/hashes |
| directly with the FreeMarker template, here are some solutions, |
| but please read the warning after them:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>You can access the Java API of a |
| <literal>java.util.Map</literal> with the help of the |
| <literal>api</literal> built-in, like |
| <literal>myMap?api.put(11, "eleven")</literal>. You will need |
| to get a <literal>Map</literal> from somewhere though (an FTL |
| hash literal like <literal>{}</literal> won't suffice, as it's |
| read only and doesn't support <literal>api</literal> either). |
| For example, you could expose a Java method or |
| <literal>TemplateMethodModelEx</literal> to the template that |
| returns a <literal>new LinkeHashMap()</literal>, so you can do |
| <literal><#assign myMap = |
| utils.newLinkedHashMap()></literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>You can write a <literal>TemplateMethodModelEx</literal> |
| and <literal>TemplateDirectiveModel</literal> implementation |
| that can modify certain types of sequences/hashes. Just |
| certain types, because |
| <literal>TemplateSequenceModel</literal> and |
| <literal>TemplateHashModel</literal> doesn't have methods for |
| modification, so you will need the sequence or hash to |
| implement some additional methods. An example of this solution |
| can be seen in FMPP. It allows you to do things like this |
| (<literal>pp</literal> stores the services provided by FMPP |
| for templates):</para> |
| |
| <programlisting role="template"><#assign a = pp.newWritableSequence()> |
| <@pp.add seq=a value="red" /></programlisting> |
| |
| <para>The <literal>pp.add</literal> directive works only with |
| sequences that were created with |
| <literal>pp.newWritableSequence()</literal>. So for example |
| the template author can't modify a sequence that comes from |
| the data-model with this.</para> |
| </listitem> |
| |
| <listitem> |
| <para>A sequence can have some methods/directives if you use a |
| customized wrapper (so you can write something like |
| <literal><@myList.append foo /></literal>).</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>But beware, these solutions have a problem: The <link |
| linkend="dgui_template_exp_sequenceop_cat">sequence |
| concatenation</link>, <link |
| linkend="dgui_template_exp_seqenceop_slice">sequence slice</link> |
| operator (like <literal>seq[5..10]</literal>) and |
| <literal>?reverse</literal> do not copy the original sequence, |
| just wraps it (for efficiency), so the resulting sequence will |
| change if the original sequence is changed later (an abnormal |
| aliasing effect). The same problem exists with the result of <link |
| linkend="dgui_template_exp_hashop_cat">hash concatenation</link>; |
| it just wraps the two hashes, so the resulting hash will magically |
| change if you modify the hashes you have added earlier. As a |
| work-around, after you did the above problematic operations, |
| either be sure you will not modify the objects that were used as |
| input, or create a copy of the result with a method provided by |
| the solution described in above two points (e.g. in FMPP you could |
| do <literal><#assign b = |
| pp.newWritableSequence(a[5..10])></literal> and |
| <literal><#assign c = pp.newWritableHash(hashA + |
| hashB)></literal>). Of course this is easy to miss... so again, |
| rather try to build the data-model so you will not need to modify |
| collections, or use a presentation task helper class as was shown |
| earlier.</para> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_null"> |
| <question> |
| <para>What about <literal>null</literal> and the FreeMarker |
| template language? <indexterm> |
| <primary>null</primary> |
| </indexterm></para> |
| </question> |
| |
| <answer> |
| <para>The FreeMarker template language doesn't know the Java |
| language <literal>null</literal> at all. It doesn't have |
| <literal>null</literal> keyword, and it can't test if something is |
| <literal>null</literal> or not. When it technically faces with a |
| <literal>null</literal>, it treats it exactly as a missing |
| variable. For example, both if <literal>x</literal> is |
| <literal>null</literal> in the data-model and if it's not present |
| at all, <literal>${x!'missing'}</literal> will print |
| <quote>missing</quote>, you can't tell the difference. Also, if |
| for example you want to test if a Java method has returned |
| <literal>null</literal>, just write something like |
| <literal><#if foo.bar()??></literal>.</para> |
| |
| <para>You may interested in the rationale behind this. From the |
| viewpoint of the presentation layer a <literal>null</literal> and |
| non-existent thing is almost always the same. The difference |
| between this two is usually just a technical detail, which is |
| rather the result of implementation details than of the |
| application logic. That you can't compare something to |
| <literal>null</literal> (unlike in Java); it doesn't make sense to |
| compare something with <literal>null</literal> in a template, |
| since the template language doesn't do identity comparison (like |
| the Java <literal>==</literal> operator when you compare two |
| objects) but the more common sense value comparison (like Java's |
| <literal>Object.equals(Object)</literal>; that doesn't work with |
| <literal>null</literal> either). And how could FreeMarker tell if |
| something concrete equals with something that is missing and thus |
| unknown? Or if two missing (unknown) things are equal? Of course |
| these questions can't be answered.</para> |
| |
| <para>There is at least one problem with this |
| <literal>null</literal>-unaware approach. When you call a Java |
| method from a template, you may want to pass a |
| <literal>null</literal> value as argument (since the method was |
| designed to be used in Java language, where the concept of |
| <literal>null</literal> is known). In this case you can exploit a |
| bug of FreeMarker (that we will not fix until we provide a correct |
| solution for passing <literal>null</literal> values to a method): |
| if you specify a missing variable as the argument, then it will |
| not cause an error, but a <literal>null</literal> will be passed |
| to the method instead. Like <literal>foo.bar(nullArg)</literal> |
| will call the <literal>bar</literal> method with |
| <literal>null</literal> as argument, assuming that there is no |
| variable exists with <quote>nullArg</quote> name.</para> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_capture"> |
| <question> |
| <para>How can I use the output of a directive (macro) in |
| expressions (as a parameter to another directive)?</para> |
| </question> |
| |
| <answer> |
| <para>Capture the output into a variable with the |
| <literal>assign</literal> or <literal>local</literal> directive. |
| For example:</para> |
| |
| <programlisting role="template"><#assign capturedOutput><@outputSomething /></#assign> |
| <@otherDirective someParam=capturedOutput /></programlisting> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_questionmark"> |
| <question> |
| <para>Why do I have <quote>?</quote>-s in the output instead of |
| character <replaceable>X</replaceable>?</para> |
| </question> |
| |
| <answer> |
| <para>This is because the character that you want to print can't |
| be represented with the <link |
| linkend="gloss.charset">charset</link> (encoding) used for the |
| output stream, so the Java platform (not FreeMarker) substitutes |
| the problematic character with question mark. In general you |
| should use the same charset for the output as for the template |
| (use the <literal>getEncoding()</literal> method of the template |
| object), or which is even safer, you should always use UTF-8 |
| charset for the output. The charset used for the output stream is |
| not decided by FreeMarker, but by you, when you create the |
| <literal>Writer</literal> that you pass to the |
| <literal>process</literal> method of the template.</para> |
| |
| <para>Example: Here I use UTF-8 charset in a servlet:</para> |
| |
| <programlisting role="unspecified">... |
| resp.setContentType("text/html; charset=utf-8"); |
| Writer out = resp.getWriter(); |
| ... |
| t.process(root, out); |
| ...</programlisting> |
| |
| <para>Note that the question marks (or other substitution |
| characters) may be produced outside FreeMarker, in which case the |
| above obviously will not help. For example a bad/missconfigured |
| database connection or JDBC driver may bring the text already with |
| substitution characters in it. HTML forms are another potential |
| source of encoding problems. It's a good idea to print the |
| numerical code of the characters of the string on various places, |
| to see where the problem occurs first.</para> |
| |
| <para>You can read more about charsets and FreeMarker <link |
| linkend="pgui_misc_charset">here...</link></para> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_retrieve_calculated_values"> |
| <question> |
| <para>How to retrieve values calculated in templates after |
| template execution done?</para> |
| </question> |
| |
| <answer> |
| <para>First of all, be sure your application is designed well: |
| templates should display data, and almost never calculate data. If |
| you are still sure you want to do it, read on...</para> |
| |
| <para>When you use <literal><#assign x = "foo"></literal>, |
| then you do not actually modify the data-model (since that is |
| read-only, see: <xref linkend="pgui_misc_multithreading"/>), but |
| create the <literal>x</literal> variable in the runtime <link |
| linkend="gloss.environment">environment</link> of the processing |
| (see <xref linkend="pgui_misc_var"/>). The problem is that this |
| runtime environment will be discarded when |
| <literal>Template.process</literal> returns, as it was created for |
| a single <literal>Template.process</literal> call:</para> |
| |
| <programlisting role="unspecified">// internally an Environment will be created, and then discarded |
| myTemplate.process(root, out);</programlisting> |
| |
| <para>To prevent this, you can do the below, which is equivalent |
| with the above, except that you have chance to return the |
| variables created in the template:</para> |
| |
| <programlisting role="unspecified">Environment env = myTemplate.createProcessingEnvironment(root, out); |
| env.process(); // process the template |
| TemplateModel x = env.getVariable("x"); // get variable x</programlisting> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_assign_to_dynamic_variable_name"> |
| <question> |
| <para>How to assign to (or <literal>#import</literal> into) a |
| dynamically constructed variable name (like to name that's stored |
| in another variable)?</para> |
| </question> |
| |
| <answer> |
| <para>If you really can't avoid doing that (you should, as it's |
| confusing), you can solve that with constructing the appropriate |
| FTL source code dynamically in a string, then using the <link |
| linkend="ref_builtin_interpret"><literal>interpret</literal> |
| built-in</link>. For example, if you want to assign to the |
| variable whose name is stored in the <literal>varName</literal> |
| variable:</para> |
| |
| <programlisting role="template"><@"<#assign ${varName}='example'>"?interpret /></programlisting> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_template_uploading_security"> |
| <question> |
| <indexterm> |
| <primary>security</primary> |
| |
| <secondary>user-provided templates</secondary> |
| </indexterm> |
| |
| <para>Can I allow users to upload templates and what are the |
| security implications?</para> |
| </question> |
| |
| <answer> |
| <para>In general you shouldn't allow that, unless those users are |
| application developers, system administrators, or other highly |
| trusted personnel. Consider templates as part of the source code |
| just like <literal>*.java</literal> files are. If you still want |
| to allow untrusted users to upload templates, here's what to |
| consider:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Data-model and wrapping |
| (<literal>Configuration.setObjectWrapper</literal>): The |
| data-model might gives access to the public Java API of some |
| objects that you have put into the data-model. By default, for |
| objects that aren't instances of the bunch of specially |
| handled types (<literal>String</literal>, |
| <literal>Number</literal>, <literal>Boolean</literal>, |
| <literal>Date</literal>, <literal>Map</literal>, |
| <literal>List</literal>, array, and a few others), their |
| public Java API will be exposed, including most methods |
| inherited from standard Java classes |
| (<literal>getClass()</literal>, etc.). To avoid that, you have |
| to construct the data-model so that it only exposes the |
| members that are really necessary for the template. One |
| possibility is using <literal>SimpleObjectWrapper</literal> |
| (via <literal>Configuration.setObjectWrapper</literal> or the |
| <literal>object_wrapper</literal> setting) and then create the |
| data-model purely from <literal>Map</literal>-s, |
| <literal>List</literal>-s, <literal>Array</literal>-s, |
| <literal>String</literal>-s, <literal>Number</literal>-s, |
| <literal>Boolean</literal>-s and <literal>Date</literal>-s. |
| But for many applications that's too restrictive, and instead |
| you have to create a |
| <literal>WhitelistMemberAccessPolicy</literal>, and create a |
| <literal>DefaultObjectWrapper</literal> (or other |
| <literal>BeansWrapper</literal> subclass that you would use) |
| that uses that. See the Java API documentation of |
| <literal>WhitelistMemberAccessPolicy</literal> for more. (Or, |
| you can roll your own <literal>MemberAccessPolicy</literal> |
| implementation, or even your own restrictive |
| <literal>ObjectWrapper</literal> implementation of |
| course.)</para> |
| |
| <para>Always expect that templates may get some objects that |
| you haven't put into the data-model yourself. Notably, |
| templates can always get a <literal>Locale</literal> object |
| with the <literal>.locale_object</literal> expression. Or the |
| web application framework you are using may exposes some |
| objects, like attributes from the Servlet scopes. Such objects |
| will be still wrapped with the |
| <literal>ObjectWrapper</literal> that you set in the |
| <literal>Configuration</literal>, and this is why it's |
| important to ensure safety on that level. Controlling what |
| objects the template will have access to is hard, but you can |
| control centrally what members of any object they have access |
| to.</para> |
| |
| <para>If you are creating <literal>TemplateModel</literal>-s |
| in custom code (instead of the |
| <literal>ObjectWrapper</literal> creating those), be sure that |
| you avoid deprecated container constructors like <literal>new |
| SimpleSequence()</literal>, as those will use the also |
| deprecated default object wrapper instance, which doesn't have |
| the same restrictions than the |
| <literal>ObjectWrapper</literal> you have set on the |
| <literal>Configuration</literal>.</para> |
| |
| <para>Also, don't forget about the <link |
| linkend="ref_buitin_api_and_has_api"><literal>?api</literal> |
| built-in</link>, if you have enabled it (it's disabled by |
| default). While the Java API of <literal>Map</literal>-s, |
| <literal>List</literal>-s and similar container-like objects |
| is not directly exposed by most |
| <literal>ObjectWrapper</literal>-s, so |
| <literal>someMap.someJavaMethod()</literal> won't work, using |
| <literal>?api</literal> the template author can still get to |
| the Java API-s of these objects, like |
| <literal>someMap?api.someJavaMethod()</literal>. But note that |
| the <literal>ObjectWrapper</literal> is still in control, as |
| it decides what objects support <literal>?api</literal>, and |
| what will <literal>?api</literal> expose for them (it usually |
| exposes the same as for a generic POJO). Members not allowed |
| by the <literal>MemberAccessPolicy</literal> also won't be |
| visible with <literal>?api</literal> (assuming you are using a |
| well behaving <literal>ObjectWrapper</literal>, like |
| <literal>DefaultObjectWrapper</literal>.)</para> |
| |
| <para>If you are using the default object wrapper class |
| (<literal>freemarker.template.DefaultObjectWrapper</literal>), |
| or a subclass of it, you should disable the XML (DOM) wrapping |
| feature of it, by setting its |
| <literal>DOMNodeSupport</literal> property to |
| <literal>false</literal>. The problem with the XML wrapping |
| feature, which wraps <literal>org.w3c.dom.Node</literal> |
| objects on special way to make them easier to work with in |
| templates, is that this facility by design lets template |
| authors evaluate arbitrary XPath expressions, and XPath can do |
| too much in certain setups. If you really need the XML |
| wrapping facility, review carefully what XPath expressions are |
| possible in your setup. Also, be sure you don't use the long |
| deprecated, and more dangerous |
| <literal>freemarker.ext.xml</literal> package, only |
| <literal>freemarker.ext.dom</literal>. Also, note that when |
| using the XML wrapping feature, not allowing |
| <literal>org.w3c.dom.Node</literal> methods in the |
| <literal>MemberAccessPolicy</literal> has no effect, since it |
| doesn't expose Java <literal>Node</literal> members to |
| templates directly.</para> |
| |
| <para>Last not least, some maybe aware of the historical |
| legacy that standard object wrappers filter out some well |
| known <quote>unsafe</quote> methods, like |
| <literal>System.exit</literal>. Do not ever rely on that, |
| since it only blocks the methods from a small predefined list. |
| The standard Java API is huge and ever growing, and then there |
| are the 3rd party libraries, and the API-s of your own |
| application. Clearly it's impossible to blacklist all the |
| problematic members in those.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Template-loader |
| (<literal>Configuration.setTemplateLoader</literal>): |
| Templates may load other templates by name (by path), like |
| <literal><#include "../secret.txt"></literal>. To avoid |
| loading sensitive data, you have to use a |
| <literal>TemplateLoader</literal> that double-checks that the |
| file to load is something that should be exposed. FreeMarker |
| tries to prevent the loading of files outside the template |
| root directory regardless of template loader, but depending on |
| the underlying storage mechanism, exploits may exist that |
| FreeMarker can't consider (like, just as an example, |
| <literal>~</literal> jumps to the current user's home |
| directory). Note that |
| <literal>freemarker.cache.FileTemplateLoader</literal> checks |
| the canonical paths, so that's maybe a good candidate for this |
| task, yet, adding a file extension check (file must be |
| <literal>*.ftl</literal>) is maybe a good idea.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>new</literal> built-in |
| (<literal>Configuration.setNewBuiltinClassResolver</literal>, |
| <literal>Environment.setNewBuiltinClassResolver</literal>): |
| It's used in templates like |
| <literal>"com.example.SomeClass"?new()</literal>, and is |
| important for FTL libraries that are partially implemented in |
| Java, but shouldn't be needed in normal templates. While |
| <literal>new</literal> will not instantiate classes that are |
| not <literal>TemplateModel</literal>-s, FreeMarker contains a |
| <literal>TemplateModel</literal> class that can be used to |
| create arbitrary Java objects. Other "dangerous" |
| <literal>TemplateModel</literal>-s can exist in you |
| class-path. Plus, even if a class doesn't implement |
| <literal>TemplateModel</literal>, its static initialization |
| will be run. To avoid these, you should use a |
| <literal>TemplateClassResolver</literal> that restricts the |
| accessible classes to the absolute minimum (possibly based on |
| which template asks for them), such as |
| <literal>TemplateClassResolver.ALLOWS_NOTHING_RESOLVER</literal>. |
| Do <emphasis>not</emphasis> use |
| <literal>TemplateClassResolver.SAFER_RESOLVER</literal>, it's |
| not restrictive enough for this purpose! Note that if, and |
| only if your <literal>ObjectWrapper</literal> is a |
| <literal>BeansWrapper</literal> or a subclass of it (typically |
| <literal>DefaultObjectWrapper</literal>), constructors not |
| allowed by the <literal>MemberAccessPolicy</literal> also |
| won't be accessible for <literal>?new</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Denial-of-Service (DoS) attacks: It's trivial to create |
| templates that run practically forever (with a loop), or |
| exhaust memory (by concatenating to a string in a loop). |
| FreeMarker can't enforce CPU or memory usage limits, so this |
| is something that has no solution on the |
| FreeMarker-level.</para> |
| </listitem> |
| </itemizedlist> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_implement_function_or_macro_in_java"> |
| <question> |
| <para>How to implement a function or macro in Java Language |
| instead of in the template language?</para> |
| </question> |
| |
| <answer> |
| <para>It's not possible (yet), but something very similar is |
| possible if you write a class that implements |
| <literal>freemarker.template.TemplateMethodModelEx</literal> or |
| <literal>freemarker.template.TemplateDirectiveModel</literal> |
| respectively, and then where you were write <literal><#function |
| my |
| <replaceable>...</replaceable>><replaceable>...</replaceable></#function></literal> |
| or <literal><#macro my |
| <replaceable>...</replaceable>><replaceable>...</replaceable></#macro></literal> |
| you write <literal><#assign my = "your.package.YourClass |
| "?</literal><link |
| linkend="ref_builtin_new"><literal>new</literal></link><literal>()></literal> |
| instead. Note that using the <literal>assign</literal> directive |
| for this works because functions (and methods) and macros are just |
| plain variables in FreeMarker. (For the same reason you could also |
| put <literal>TemplateMethodModelEx</literal> or |
| <literal>TemplateDirectiveModel</literal> instances into the |
| data-model before calling the template, or into the shared |
| variable map (see: |
| <literal>freemarker.template.Configuration.setSharedVariable(String, |
| TemplateModel)</literal>) when you initialize the |
| application.)</para> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_nice_error_page"> |
| <question> |
| <para><anchor xml:id="misc.faq.niceErrorPage"/> In my Servlet |
| based application, how do I show a nice error page instead of a |
| stack trace when error occurs during template processing?</para> |
| </question> |
| |
| <answer> |
| <para>First of all, use <literal>RETHROW_HANDLER</literal> instead |
| of the default <literal>DEBUG_HANDLER</literal> (for more |
| information about template exception handlers <link |
| linkend="pgui_config_errorhandling">read this...</link>). Now |
| FreeMarker will not print anything to the output when an error |
| occurs, so the control is in your hands. After you have caught the |
| exception of |
| <literal>Template.process(<replaceable>...</replaceable>)</literal> |
| basically you can follow two strategies:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Call <literal>httpResp.isCommitted()</literal>, and if |
| that returns <literal>false</literal>, then you call |
| <literal>httpResp.reset()</literal> and print a <quote>nice |
| error page</quote> for the visitor. If the return value was |
| <literal>true</literal>, then try to finish the page be |
| printing something that makes clear for the visitor that the |
| page generation was abruptly interrupted because of an error |
| on the Web server. You may have to print a lot of redundant |
| HTML end-tags and set colors and font size to ensure that the |
| error message will be actually readable in the browser window |
| (check the source code of the |
| <literal>HTML_DEBUG_HANDLER</literal> in |
| <literal>src\freemarker\template\TemplateException.java</literal> |
| to see an example).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Use full page buffering. This means that the |
| <literal>Writer</literal> doesn't send the output to the |
| client progressively, but buffers the whole page in the |
| memory. Since you provide the <literal>Writer</literal> |
| instance for the |
| <literal>Template.process(<replaceable>...</replaceable>)</literal> |
| method, this is your responsibility, FreeMarker has nothing to |
| do with it. For example, you may use a |
| <literal>StringWriter</literal>, and if |
| <literal>Template.process(<replaceable>...</replaceable>)</literal> |
| returns by throwing an exception, then ignore the content |
| accumulated by the <literal>StringWriter</literal>, and send |
| an error page instead, otherwise you print the content of |
| <literal>StringWriter</literal> to the output. With this |
| method you surely don't have to deal with partially sent |
| pages, but it can have negative performance implications |
| depending on the characteristic of the pages (for example, the |
| user will experience more response delay for a long page that |
| is generated slowly, also the server will consume more RAM). |
| Note that using a <literal>StringWriter</literal> is surely |
| not the most efficient solution, as it often reallocates its |
| buffer as the accumulated content grows.</para> |
| </listitem> |
| </itemizedlist> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry xml:id="faq_html_editor_mangles"> |
| <question> |
| <para>I'm using a visual HTML editor that mangles template tags. |
| Will you change the template language syntax to accommodate my |
| editor?</para> |
| </question> |
| |
| <answer> |
| <para>We won't change the standard version, because a lot of |
| templates depend on it.</para> |
| |
| <para>Our view is that the editors that break template code are |
| themselves broken. A good editor should ignore, not mangle, what |
| it doesn't understand.</para> |
| |
| <para>You maybe interested in that starting from FreeMarker 2.3.4 |
| you can use <literal>[</literal> and <literal>]</literal> instead |
| of <literal><</literal> and <literal>></literal>. For more |
| details <link linkend="dgui_misc_alternativesyntax">read |
| this...</link></para> |
| </answer> |
| </qandaentry> |
| </qandaset> |
| </appendix> |
| |
| <appendix xml:id="app_versions"> |
| <title>Version history</title> |
| |
| <section xml:id="versions_2_3_33"> |
| <title>2.3.33</title> |
| |
| <para>Release date: [TODO]</para> |
| |
| <para>Please note that with this version the minimum required Java |
| version was increased from Java 7 to Java 8. Also for the few who |
| relly on Servlet and/or JSP support, the minimum is now increased to |
| Servlet 3.0, and JSP 2.2 (which are still very old versions from |
| 2011).</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-183">FREEMARKER-183</link>: |
| If FreeMarker is configured like so, values in Java records can |
| now be referred like <literal>obj.price</literal>, instead of |
| like <literal>obj.price()</literal>. Furthermore, FreeMarker can |
| now be configured to allow this for all 0-argument |
| non-<literal>void</literal> methods. See more details in the |
| <link linkend="version_hisotry_freemarker_183_java_side">Changes |
| on the Java side</link> section below.</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://github.com/apache/freemarker/pull/87">GitHub |
| PR 87</link> Comparing strings is now way faster, if the <link |
| linkend="pgui_config_incompatible_improvements_how_to_set"><literal>incompatible_improvements</literal> |
| setting</link> is at least 2.3.33. If your template does lot of |
| string comparisons, this can mean very significant speedup. With |
| this enabled, we use a simpler way of comparing strings, and |
| because templates were only ever allowed equality comparisons |
| between strings (not less-than, or greater-than), it's very |
| unlikely to change the behavior of your templates. (Technically, |
| what changes is that instead of using Java's localized |
| <literal>Collator</literal>-s, we switch to a simple binary |
| comparison after UNICODE NFKC normalization. So, in theory it's |
| possible that for some locales two different but similarly |
| looking characters were treated as equal by the collator, but |
| will count as different now. But it's very unlikely that anyone |
| wanted to depend on such fragile logic anyway. Note again that |
| we still do UNICODE normalization, so combining characters won't |
| break your comparison.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>When concatenating many sequences (like of Java |
| <literal>List</literal>-s) with the <literal>+</literal> |
| operator, the resulting sequence is now much less slow to read. |
| (Background: the <literal>+</literal> operator, when applied on |
| two sequences, produces a result sequence that just view, not a |
| copy of the original sequences. Thus is very fast to add |
| together long sequences. But, if you concatenate many, like |
| hundreds, of sequences, reading the sequence back will become |
| expensive. It was always like that, so it's still not |
| recommended to concatenate more then a few tens of sequences. |
| But if that recommendation is not kept, now the slowdown can be |
| way less punishing.)</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Iteration (like listing) is now reasonably fast, and |
| need not be concerned about. The speed of fetching the next |
| item is now mostly independent of the number of sequences |
| concatenated, while earlier it has become slower as that |
| number grew. By iteration we mean going through all the |
| items, strictly in order, without using an index explicitly. |
| Examples of iteration are <literal><#list |
| <replaceable>concatedSeq</replaceable> as |
| <replaceable>...</replaceable>></literal>, and |
| <literal><replaceable>concatedSeq</replaceable>?join(', |
| ')</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Accessing items by index, like |
| <literal><replaceable>concatedSeq</replaceable>[i]</literal>, |
| is now much faster than before, but still can be slow if you |
| had concatenated a lot of sequences. Item access speed is |
| now roughly O(N), where N is number of concatenated |
| sequences (not the number of items!), so traversing the |
| whole sequence by index is O(N²).</para> |
| </listitem> |
| |
| <listitem> |
| <para>In previous versions |
| <literal><replaceable>concatedSeq</replaceable>?size</literal> |
| could cause stack overflow if it |
| <literal><replaceable>concatedSeq</replaceable></literal> |
| was concatenated together from thousands of sequences. Now |
| the stack usage is constant and negligible.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-219">FREEMARKER-219</link>: |
| The <link linkend="ref_builtin_truncate"><quote>truncate</quote> |
| family of built-ins</link>, as in |
| <literal>maybeLong?truncate(10, '')</literal>, if the terminator |
| string is set to 0 length, now it will not add a space before |
| the terminator string when the cut happened exactly after the |
| end of a word. (Note that if you are using something like |
| <literal>maybeLong?truncate_c(10, '')</literal>, then certainly |
| what you really want is <literal>maybeLong[0 ..* 10]</literal>, |
| as that doesn't do trimming at the cut.)</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://github.com/apache/freemarker/pull/89">GitHub |
| PR 89</link>: Added <literal>TemplateProcessingTracer</literal> |
| mechanism, that can be used to monitor coverage, and performance |
| <emphasis>inside</emphasis> templates as they are being |
| processed. For example, you could construct a heat map for how |
| often the different parts run, or finding the performance hot |
| spots. (There can be other creative uses, like watching for a |
| variable to have a certain value.) Use |
| <literal>Environment.setTemplateProcessingTracer(TemplateProcessingTracer)</literal> |
| to enable this kind of monitoring. (See the API docs for |
| more.)</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section xml:id="version_hisotry_freemarker_183_java_side"> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-183">FREEMARKER-183</link>: |
| Better support for Java records, if you set the <link |
| linkend="pgui_config_incompatible_improvements_how_to_set"><literal>incompatible_improvements</literal> |
| setting</link> to 2.3.33 or higher (or if you create your own |
| <literal>ObjectWrapper</literal>, then set its |
| <literal>incompatible_improvements</literal>, or just its |
| <literal>recordZeroArgumentNonVoidMethodPolicy</literal> |
| property to <literal>BOTH_PROPERTY_AND_METHOD</literal>). If in |
| a Java record you have something like <literal>int |
| price()</literal>, earlier you could only read the value in |
| templates as <literal>obj.price()</literal>. With this |
| improvement <literal>obj.price</literal> will do the same (and |
| similarly, <literal>obj["price"]()</literal>, and |
| <literal>obj["price"]</literal> will do the same). This has |
| always worked for JavaBeans properties, like <literal>int |
| getPrice()</literal> could always be used in templates as |
| <literal>obj.price</literal>, in additionally to as |
| <literal>obj.getPrice()</literal>. Now this also works for Java |
| records, as there we simply treat all methods that has 0 |
| arguments, and non-<literal>void</literal> return type as if it |
| was a JavaBean property read method. Except, here the name of |
| the method is exactly the same as the name of the faked |
| JavaBeans property (<literal>price</literal>), while with real |
| JavaBeans the read method name typically would be |
| <literal>getPrice</literal>, and the property name would be |
| <literal>price</literal> (so we have two separate names). There |
| are some strange technical tricks involved for the same name to |
| be usable in both ways, but as far as most users care, it just |
| works.</para> |
| |
| <para>Some more technical changes:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added two new settings to |
| <literal>BeansWrapper</literal>, and therefore |
| <literal>DefaultObjectWrapper</literal>: |
| <literal>recordZeroArgumentNonVoidMethodPolicy</literal>, |
| and |
| <literal>nonRecordZeroArgumentNonVoidMethodPolicy</literal>. |
| Each has enum type |
| <literal>freemarker.ext.beans.ZeroArgumentNonVoidMethodPolicy</literal>, |
| that can be <literal>METHOD_ONLY</literal>, |
| <literal>PROPERTY_ONLY</literal>, or |
| <literal>BOTH_PROPERTY_AND_METHOD</literal>. |
| Therefore:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Note that with |
| <literal>nonRecordZeroArgumentNonVoidMethodPolicy</literal> |
| you can set similar behavior to non-records. That is, |
| you can call 0 argument non-void methods without |
| <literal>()</literal>, if you want. It's only meant to |
| be used for methods that are mere value readers, and has |
| no side effect.</para> |
| </listitem> |
| |
| <listitem> |
| <para>For records, you can enforce proper style with |
| setting |
| <literal>recordZeroArgumentNonVoidMethodPolicy</literal> |
| to <literal>PROPERTY_ONLY</literal>. The default with |
| <literal>incompatible_improvements</literal> 2.3.33 is |
| more lenient, as there using <literal>()</literal> is |
| allowed (for backward compatibility, and because people |
| often just use the Java syntax).</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Added new interface, |
| <literal>freemarker.template.MethodCallAwareTemplateHashModel</literal>, |
| which adds <literal>getBeforeMethodCall(String |
| key)</literal>. If you have something like |
| <literal>obj.price()</literal> in a template, where |
| <literal>obj</literal> (after wrapping) implements that |
| interface, then |
| <literal>getBeforeMethodCall("price")</literal> called |
| instead of |
| <literal>TemplateHashModel.get("price")</literal>. This is |
| needed for |
| <literal>ZeroArgumentNonVoidMethodPolicy.BOTH_PROPERTY_AND_METHOD</literal> |
| to work.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added <literal>GenericObjectModel</literal>, which |
| extends <literal>StringModel</literal> with implementing |
| <literal>MethodCallAwareTemplateHashModel</literal>, and has |
| a more telling name. <literal>BeansWrapper</literal>, and |
| therefore <literal>DefaultObjectWrapper</literal> now |
| creates <literal>GenericObjectModel</literal>-s instead of |
| <literal>StringModel</literal>-s. This is like so regardless |
| of any setting, like regardless of |
| <literal>incompatible_improvements</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>You shouldn't override |
| <literal>BeanModel.get(String)</literal> anymore, but |
| <literal>BeanModel.get(String, boolean)</literal>. If you |
| have overridden <literal>get</literal>, then see in the |
| Javadoc for more.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://github.com/apache/freemarker/pull/88">GitHub |
| PR 88</link>: Added a new possible value for the |
| <literal>auto_escaping_policy</literal> configuration setting, |
| <literal>force</literal> |
| (<literal>Configuration.FORCE_AUTO_ESCAPING_POLICY</literal>). |
| This policy is to always require auto-escaping, to avoid |
| accidents where because of misconfiguration, or a mistake of the |
| template author it's disabled. With this policy, using output |
| formats that don't support escaping will not be allowed. Using |
| built-ins, and directives that disable auto-escaping (like |
| <literal>?no_esc</literal>) will also be errors (on parse-time). |
| Note that if markup (like HTML) comers from the data model, then |
| with this policy you will have to ensure that they come as |
| <literal>TemplateMarkupOutputModel</literal>-s (which won't be |
| auto-escaped even with this policy), not as |
| <literal>String</literal>-s, because the template authors can't |
| disable escaping for the value anymore.</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-214">FREEMARKER-214</link>, |
| <link |
| xlink:href="https://github.com/apache/freemarker/pull/90">GitHub |
| PR 90</link>: Update JavaCC (used for generating the template |
| parser) from 6.1.2 to 7.0.12, to avoid creating new |
| <literal>LookAheadSuccess</literal> with stack trace instance |
| for each <literal>FMParser</literal> instance.</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-218">FREEMARKER-218</link>: |
| Servlet, and JSP support classes now has a Jakarta variant in |
| the new <literal>freemarker.ext.jakarta.jsp</literal> and |
| <literal>freemarker.ext.jakarta.servlet</literal> packages. |
| These are the slightly modified copies of |
| <literal>freemarker.ext.servlet</literal>, |
| <literal>freemarker.ext.jsp</literal> (which are also present in |
| the same FreeMarker jar), that depend on the Jakarata API-s |
| (<literal>jakarta.servlet</literal>, |
| <literal>jakarta.servlet.jsp</literal>, |
| <literal>jakarta.el</literal>, etc.), instead of the tradition |
| <literal>javax</literal> Serlvet/JSP/EL API-s. There's also |
| <literal>freemarker.ext.jakarta.servlet.WebappTemplateLoader</literal>, |
| which is the Jakarta equivalent of |
| <literal>freemarker.cache.WebappTemplateLoader</literal>. (Note |
| that Jakarta packages/classes are not visible in the FreeMarker |
| source code, as they are generated during build from the |
| pre-Jakarta classes.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>When <literal>FreemarkerServlet</literal> was used with |
| the <literal>TemplateExceptionHandler.DEBUG_HANDLER</literal> or |
| <literal>HTML_DEBUG_HANDLER</literal>, on Jetty the response web |
| page was possibly empty or partial, as the Jetty has abruptly |
| closed the connection after we flushed the HTTP response with |
| status code 200, and yet thrown an exception. Now in this |
| situation we only log the exception, but don't throw it. |
| (Production system should always use |
| <literal>RETHROW_HANDLER</literal>, and this change has no |
| effect there.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>When concatenating sequences (like Java |
| <literal>List</literal>-s) with the <literal>+</literal> |
| operation in templates, the resulting |
| <literal>TemplateSequenceModel</literal> now also implements |
| <literal>TemplateCollectionModelEx</literal> (with is similar to |
| Java's <literal>Iterable</literal>). It's because using that is |
| much more efficient then indexed access, if the sequence was |
| concatenated together from a lot of sequences.</para> |
| </listitem> |
| |
| <listitem> |
| <para>We don't generate RMIC stub classes for |
| <literal>freemarker.debug.impl.Rmi*Impl</literal> classes |
| anymore. Almost nobody uses that API, but if you do, you |
| certainly already rely on dynamic stubs anyway. (The |
| <literal>rmic</literal> tool used to generate the stub classes |
| was removed from the JDK, starting with JDK 15.)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>Configuration.getVersion().getBuildDate()</literal> |
| will now always return <literal>null</literal>, as we don't |
| store the build date anymore, to make the build reproducible. |
| For same reason, <literal>META-INF/MANIFEST.FM</literal> now |
| will not store any timestamps, nor information about the build |
| environment.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Build changes (in case you build FreeMarker itself, not |
| just depend on it):</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-204">FREEMARKER-204</link>, |
| <link |
| xlink:href="https://github.com/apache/freemarker/pull/79">GitHub |
| PR 79</link>: Switched from Ant, to Gradle. IDE setup now |
| involves no lengthy manual adjustments, assuming it's fairly |
| recent IDE with decent Gradle support. There's on |
| <literal>build.properties</literal> to set up either, but |
| you need to ensure that you have both JDK 8, and JDK 16m and |
| that Gradle finds them. See the <literal>README.md</literal> |
| for more instructions. (Gradle itself is self-installing, of |
| course.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>JavaDoc is now generated with JDK 16 (so now we have |
| search on it)</para> |
| </listitem> |
| |
| <listitem> |
| <para>The build is now reproducible (see <link |
| xlink:href="https://reproducible-builds.org">reproducible-builds.org</link>). |
| However, therefore it doesn't contain any build timestamps |
| anymore.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Minimum requirements were increased:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Java 8 (or higher)</para> |
| </listitem> |
| |
| <listitem> |
| <para>If Servlet-related features are used, Servlet 3.0 (or |
| higher)</para> |
| </listitem> |
| |
| <listitem> |
| <para>If JSP-related features are used, JSP 2.2 (or |
| higher)</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_32"> |
| <title>2.3.32</title> |
| |
| <para>Release date: 2023-01-12</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Improved outputting values for computer/parser consumption |
| (such as for generating JSON, JavaScript values, values encoded |
| into URL-s):</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added new configuration setting, <link |
| linkend="gloss.c_format"><literal>c_format</literal></link> |
| (also settable via the <link |
| linkend="ref.directive.setting"><literal>setting</literal> |
| directive</link>). This specifies what syntax to use when |
| formatting values for computer consumption/parser, like |
| <literal>"JSON"</literal>. Most prominently, this affects |
| the <link linkend="ref_builtin_c"><literal>c</literal> |
| built-in</link>, hence the name. See valid setting values, |
| and their meaning here: <xref |
| linkend="dgui_misc_computer_vs_human_format"/>.</para> |
| |
| <para>If you set the <link |
| linkend="pgui_config_incompatible_improvements_how_to_set"><literal>incompatible_improvements</literal> |
| setting</link> to 2.3.32, the default of |
| <literal>c_format</literal> changes from |
| <literal>"legacy"</literal> to <literal>"JavaScript or |
| JSON"</literal>, which is a format that most targets can |
| parse (because we just format simple values, not lists and |
| maps). With lower |
| <literal>incompatible_improvements</literal>, the default |
| value is <literal>"legacy"</literal> that emulates the old |
| behavior of <literal>?c</literal> (where you can lose |
| numerical precision, etc.), so it's recommended to set it to |
| something else.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><link |
| linkend="ref_builtin_c">?c</link></literal> now formats |
| string values to string literals (with quotation marks and |
| escaping), according the language specified in the <link |
| linkend="gloss.c_format"><literal>c_format</literal> |
| setting</link>, such as <literal>JSON</literal>, |
| <literal>Java</literal>, etc. Earlier, <literal>?c</literal> |
| only allowed numbers, and booleans.</para> |
| |
| <para>To generate JSON, you can now write a piece of |
| template like this:</para> |
| |
| <programlisting role="template">"fullName": ${user.fullName?c},</programlisting> |
| |
| <para>Then the output will be like:</para> |
| |
| <programlisting role="output">"fullName": "John Doe",</programlisting> |
| |
| <para>Note that the quotation marks were added by |
| <literal>?c</literal>, and weren't typed into the |
| template.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added <link linkend="ref_builtin_cn">?cn</link>, which |
| is like <literal><link |
| linkend="ref_builtin_c">?c</link></literal>, except if the |
| value is <literal>null</literal>/missing, it will output a |
| <literal>null</literal> literal, according the language |
| specified in the new <link |
| linkend="gloss.c_format"><literal>c_format</literal> |
| setting</link>.</para> |
| |
| <para>Let's say, in the previous example |
| <literal>user.fullName</literal> is expected to be |
| <literal>null</literal> sometimes. Then you can just use |
| <literal>?cn</literal> instead if |
| <literal>?c</literal>:</para> |
| |
| <programlisting role="template">"fullName": ${user.fullName?cn},</programlisting> |
| |
| <para>If said variable is <literal>null</literal>, the |
| output will be like this (otherwise it will be a quoted |
| string like earlier):</para> |
| |
| <programlisting role="output">"fullName": null,</programlisting> |
| |
| <para>Note that with this approach you don't complicate the |
| template anymore to avoid printing quotation marks. Of |
| course, <literal>?cn</literal> works on numerical and |
| boolean values as well (and of course those won't be quoted, |
| only strings).</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>c_format</literal>-s other than |
| <literal>"legacy"</literal> use slightly different number |
| formatting than <literal>?c</literal> did in earlier |
| versions. The change affects some non-whole numbers, and |
| whole numbers with over 100 digits. The goal of this change |
| is to make the formatting lossless, and also to avoiding |
| huge output with exponents of high magnitude. See details at |
| the documentation of the <link |
| linkend="ref_builtin_c"><literal>c</literal> |
| built-in</link>.</para> |
| |
| <para>Setting the <link |
| linkend="pgui_config_incompatible_improvements_how_to_set"><literal>incompatible_improvements</literal> |
| setting</link> to 2.3.32 will change the default of |
| <literal>c_format</literal> for <literal>"legacy"</literal> |
| to <literal>"JavaScript or JSON"</literal>, and therefore |
| changes number formatting too.</para> |
| |
| <para>Of course, all this only affects number formatting |
| done with <literal>?c</literal>, <literal>?cn</literal>, and |
| with <literal>"c"</literal> (or |
| <literal>"computer"</literal>) |
| <literal>number_format</literal>, and not number formatting |
| in general.</para> |
| </listitem> |
| |
| <listitem> |
| <para>For consistency, when setting the |
| <literal>number_format</literal> setting (also when |
| formatting with |
| <literal>?string(<replaceable>format</replaceable>)</literal>), |
| now <literal>"c"</literal> can be used instead of |
| <quote>computer</quote>. Both has the same effect on |
| formatting, but <literal>"c"</literal> is preferred from now |
| on.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-208">FREEMARKER-208</link>: |
| Added <link |
| linkend="ref_builtin_c_lower_case"><literal>?c_lower_case</literal></link>, |
| and <link |
| linkend="ref_builtin_c_upper_case"><literal>?c_upper_case</literal></link>, |
| which are the non-localized (computer language) variants of |
| <literal>?lower_case</literal>, and |
| <literal>?upper_case</literal>. The primary problem people run |
| into with the localized versions is that with Turkish locale the |
| letter <literal>i</literal>, and <literal>I</literal> has |
| different conversions than in most languages, which causes |
| problem if the conversion was for computer consumption (for |
| technical purposes), and not for humans.</para> |
| </listitem> |
| |
| <listitem> |
| <para>In <literal>freemarker.ext.xml</literal>, which is the |
| old, long deprecated XML wrapper, that almost nobody uses |
| anymore (the commonly used one is |
| <literal>freemarker.ext.dom</literal>), the |
| <literal>_registerNamespace</literal> key now works, doing what |
| the documentation always stated. Before this fix it just behaved |
| as if it was the name of an element you are looking for.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added <literal>Configurable.setCFormat(CFormat)</literal>, |
| with the usual accompanying setting API methods/constants. See |
| the <literal>c_format</literal>-, and the |
| <literal>?c</literal>-related changes earlier in the FTL |
| section.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>Environment.getCTemplateNumberFormat()</literal> that |
| returns a |
| <literal>freemarker.core.TemplateNumberFormat</literal>, and |
| deprecated <literal>getCNumberFormat()</literal> that returns a |
| <literal>java.text.NumberFormat</literal>. The behavior defined |
| in the <literal>CFormat</literal> (see earlier) is only |
| reflected exactly by the return value of the new method. The |
| deprecated method returns a format that's a best effort |
| approximation.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>freemarker.core.MarkupOutputFormat.outputForeign(MO2 |
| mo, Writer out)</literal> method, which for a |
| <literal>MarkupOutputFormat</literal> where |
| <literal>isOutputFormatMixingAllowed()</literal> returns |
| <literal>true</literal>, allows full control over how to print a |
| different markup into it. This can check what other markup is |
| allowed, and do conversion if necessary. (<link |
| xlink:href="https://github.com/apache/freemarker/pull/83">GitHub |
| PR 83</link>)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Fixed performance bug with XML processing |
| (<literal>freemarker.ext.dom</literal>) when converting an XML |
| element that contains lots of text nodes (instead of a single |
| big text node) to a string. (<link |
| xlink:href="https://github.com/apache/freemarker/pull/82">GitHub |
| PR 82</link>)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Improved <literal>StringUtil.jsStringEnc</literal> and |
| <literal>javaSctringEnc</literal> to support quoting. Also |
| <literal>jsStringEnc</literal> now have a mode that targets both |
| JavaScript and JSON, and doesn't give up apostrophe |
| escaping.</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-198">FREEMARKER-198</link>: |
| Fixed possible deadlock when the |
| <literal>Configuration</literal>, and |
| <literal>DefaultObjectWrapper</literal> class |
| <emphasis>static</emphasis> initialization is triggered in |
| different threads around the same time. (In the very unlikely |
| case your application can run into this, this will hang the code |
| that initializes FreeMarker before it has processed any |
| templates, and it can't happen anymore if any template |
| processing managed to start.)</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-190">FREEMARKER-190</link>: |
| Updated dom4j version used during FreeMarker project compilation |
| from 1.3 to 2.1.3. Users can still use FreeMarker with dom4j 1.3 |
| (mostly just luck, but it works). FreeMarker's dom4j support is |
| long deprecated anyway, and almost nobody uses it anyway. We |
| were forced to do this change because old dom4j versions have |
| security vulnerabilities, and although FreeMarker is not |
| affected by them (like we do not pull in dom4j as dependency |
| into the projects of our users), we were flagged as vulnerable |
| at certain places for merely supporting 1.3.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Slightly improved |
| <literal>DefaultMemberAccessPolicy-rules</literal> (used by |
| default), and <literal>unsafeMethods.properties</literal> (long |
| deprecated, not used by default). Note that no matter how much |
| we tweak these, they will never provide proper security if you |
| have untrusted templates! See <link |
| linkend="faq_template_uploading_security">this in the |
| FAQ</link>!</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_31"> |
| <title>2.3.31</title> |
| |
| <para>Release date: 2021-02-16</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added <literal>?eval_json</literal> to evaluate JSON given |
| as flat string. This was added as <literal>?eval</literal> is |
| routinely misused for the same purpose, which not only doesn't |
| work for all JSON-s, but can be a security problem. <link |
| linkend="ref_builtin_eval_json">See more here...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new special variable, <literal>time_zone</literal> |
| (referred like <literal>.time_zone</literal>, like all special |
| variables), to retrieve the current value of the |
| <literal>time_zone</literal> setting as a string.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Allowed escaping <literal>#</literal> with backlash in |
| identifier names (not in string), as it used to occur in |
| database column names. Like if you have a column name like |
| <literal>#users</literal>, you can refer to it as |
| <literal>row.\#users</literal>. (Alternatively, |
| <literal>row['#users']</literal> always worked, but is often |
| less convenient.)</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/projects/FREEMARKER/issues/FREEMARKER-169">FREEMARKER-169</link>: |
| Fixed bug that made <literal>?c</literal> and |
| <quote>computer</quote> number format inconsistent. If <link |
| linkend="pgui_config_incompatible_improvements_how_to_set"><literal>incomplatible_improvements</literal></link> |
| is set to 2.3.31 (or higher), when you set the |
| <literal>number_format</literal> setting to |
| <literal>computer</literal> (or you call |
| <literal>Environment.getCNumberFormat()</literal>), the format |
| now matches the behavior of <literal>?c</literal>, when |
| formatting infinite (positive and negative), and NaN. Matching |
| the behavior of <literal>?c</literal> was always the intent, but |
| before this incompatible improvement, the |
| <literal>computer</literal> format always behaved like |
| <literal>?c</literal> before incompatible improvements 2.3.21, |
| where instead of <quote>INF</quote>, and <quote>NaN</quote>, the |
| results used Unicode characters U+221E, and U+FFFD.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Fixed bug where <literal>.globals</literal> weren't seen |
| as namesapce, so something like <literal><#assign |
| <replaceable>name</replaceable> = |
| <replaceable>value</replaceable> in .globals></literal> |
| failed (although you should use <literal><#global |
| <replaceable>name</replaceable> = |
| <replaceable>value</replaceable>></literal> instead |
| anyway).</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>More helpful parser error messages for nesting problems |
| (caused by missed or malformed end-tags usually).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added <literal>DOMNodeSupport</literal> and |
| <literal>JythonSupport</literal> <literal>boolean</literal> |
| properties to <literal>DefaultObjectWrapper</literal>. This |
| allows disabling the special wrapping of DOM nodes and Jython |
| classes. This might be desirable <link |
| linkend="faq_template_uploading_security">for security |
| reasons</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-145">FREEMARKER-145</link>: |
| Fixed bug where methods with "overloaded" return type may become |
| inaccessible on Java 9+, if some overriding subclasses are not |
| public. (This is because |
| <literal>java.beans.Introspector</literal> behavior has changed |
| with Java 9.)</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-133">FREEMARKER-133</link>: |
| Fixed bug where FreeMarker sometimes tries to expose public |
| methods that are defined or overridden in a non-public class, if |
| the non-public class was then extended by a public class. |
| Calling such method just ends up with |
| <literal>IllegalAccessException</literal>, but they shouldn't be |
| exposed on the first place. Furthermore, such a wrong method |
| sometimes replaces the good version of the method, which would |
| be callable. When this glitch happens is somewhat unpredictable, |
| as it also depends on what methods |
| <literal>java.beans.Introspector</literal> exposes (which at |
| very least can depend on the Java version), and in what |
| order.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Fixed bug where OSGi |
| <literal>Bundle-RequiredExecutionEnvironment</literal> in |
| <literal>META-INF/MANIFEST.FM</literal> has incorrectly |
| contained JavaSE-1.6, J2SE-1.5</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-159">FREEMARKER-159</link>: |
| Set <literal>Automatic-Module-Name</literal> to |
| <literal>freemarker</literal> in |
| <literal>META-INF/MANIFEST.FM</literal>. In most cases this was |
| the deduced Java 9 module name earlier, but that was fragile, as |
| Java has deduced it from the jar file name.</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-165">FREEMARKER-165</link>: |
| Fixed bug where where if the namespace expression in a block |
| assignment (like <literal><#assign |
| <replaceable>x</replaceable> in |
| <replaceable>someNamespace</replaceable>><replaceable>...</replaceable></#assign></literal>) |
| refers to a missing variable, or has the wrong type, FreeMarker |
| has thrown <literal>NullPointerException</literal> or |
| <literal>ClassCastException</literal>, instead of |
| <literal>InvalidReferenceException</literal> and |
| <literal>NonNamespaceException</literal> with proper helpful |
| message.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Build related changes:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Simplified the way Apache Ivy is used in our Ant |
| build. It's now used on the standard way, there's no |
| <literal>ant update-deps</literal> anymore.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Test suite is now ran on ARM (64 bit) as well on CI |
| (Travis).</para> |
| </listitem> |
| |
| <listitem> |
| <para>FreeMarker Manual and web site now works much better |
| on mobile, because of developments in the Docgen |
| project.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Docgen is now a Maven project, and so a plain Maven |
| dependency of the other projects (although, it's still only |
| in the Apache Snapshot Repository, not in Central yet). With |
| this we could get rid of our Ivy repository.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_30"> |
| <title>2.3.30</title> |
| |
| <para>Release date: 2020-03-05</para> |
| |
| <para>Please note that with this version the minimum required Java |
| version was increased from Java 5 to Java 7.</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-107">FREEMARKER-107</link>: |
| Added |
| <literal>?<replaceable>with_args</replaceable>(dynamicArguments)</literal> |
| and |
| <literal>?<replaceable>with_args_last</replaceable>(dynamicArguments)</literal> |
| to add parameters dynamically to directive (like macro), |
| function and method calls. Actually, this built-in returns a |
| directive or macro or function that has different parameter |
| defaults. <link linkend="ref_builtin_with_args">See more |
| here...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-107">FREEMARKER-107</link>: |
| Added new special variable, <link |
| linkend="specvar.args"><literal>.args</literal></link>. This |
| evaluates to a hash in macros, and to a sequence in functions, |
| which contains all the arguments. This is useful for operations |
| that act on all the arguments uniformly, like for example to |
| pass the arguments to <link |
| linkend="ref_builtin_with_args"><literal>?with_args(<replaceable>...</replaceable>)</literal></link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref.directive.macro">Macro catch-all |
| parameters</link> (aka. varargs parameters), when capture |
| arguments passed by name (as opposed to by position), now keep |
| the original order of arguments. Earlier the order wasn't |
| predictable.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: In <literal><#escape |
| <replaceable>placeholder</replaceable> as |
| <replaceable>escExpression</replaceable>></literal>, the |
| <literal><replaceable>placeholder</replaceable></literal> wasn't |
| substituted inside lambda expressions inside |
| <literal><replaceable>escExpression</replaceable></literal>. |
| Fortunately it's very unlikely that anyone wanted to use lambdas |
| there (given the few built-ins that accept lambdas).</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The minimum required Java version was increased from Java |
| 5 to Java 7.</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-124">FREEMARKER-124</link>: |
| Made the default filtering of class members more restrictive |
| (when you are using <literal>BeansWrapper</literal>, or its |
| subclasses like <literal>DefaultObjectWrapper</literal>). This |
| is not strictly backward compatible, but unlikely to break any |
| real-world applications; see |
| <literal>src/main/resources/freemarker/ext/beans/DefaultMemberAccessPolicy-rules</literal> |
| to see what was changed. This change was made for security |
| reasons, but the default behavior will never be safe enough if |
| untrusted users will edit templates; see <link |
| linkend="faq_template_uploading_security">in the FAQ</link>. In |
| the unlikely case this change breaks your application, then you |
| can still use the old behavior by setting the |
| <literal>memberAccessPolicy</literal> property of the object |
| wrapper to |
| <literal>LegacyDefaultMemberAccessPolicy.INSTANCE</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>freemarker.ext.beans.MemberAccessPolicy</literal> |
| interface, and the <literal>memberAccessPolicy</literal> |
| property to <literal>BeansWrapper</literal>, and subclasses like |
| <literal>DefaultObjectWrapper</literal>. This allows users to |
| implement their own program logic to decide what members of |
| classes will be exposed to the templates. See See the <olink |
| targetdoc="api">FreeMarker Java API documentation</olink> for |
| more details.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>freemarker.ext.beans.WhitelistMemberAccessPolicy</literal>, |
| which is a <literal>MemberAccessPolicy</literal> for use cases |
| where you want to allow editing templates to users who shouldn't |
| have the same rights as the developers (the same rights as the |
| Java application). Earlier, the only out of the box solution for |
| that was <literal>SimpleObjectWrapper</literal>, but that's too |
| restrictive for most applications where FreeMarker is used. |
| <literal>WhitelistMemberAccessPolicy</literal> works with |
| <literal>DefaultObjectWrapper</literal> (or any other |
| <literal>BeansWrapper</literal>), allowing you to use all |
| features of it, but it will only allow accessing members that |
| were explicitly listed by the developers, or was annotated with |
| <literal>@TemplateAccessible</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-125">FREEMARKER-125</link>: |
| FreeMarker now picks up <literal>DecimalFormatSymbols</literal> |
| provided by the <literal>DecimalFormatSymbolsProvider</literal> |
| SPI. This is useful if you need to change the decimal format |
| symbols provided for a locale by Java.</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-120">FREEMARKER-120</link>: |
| <literal>BeansWrapper</literal> (and it's subclasses like |
| <literal>DefaultObjectWrapper</literal>) now has two protected |
| methods that can be overridden to monitor the accessing of |
| members: <literal>invokeMethod</literal> and |
| <literal>readField</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Setting <literal>incompatibleImprovements</literal> to the |
| instance returned by |
| <literal>Configuration.getVersion()</literal> will now be logged |
| as an error, but for backward compatibility it will still work. |
| This applies to said setting of |
| <literal>Configuration</literal>, |
| <literal>DefaultObjectWrapper</literal>, and |
| <literal>BeansWrapper</literal>. The typical bad pattern is |
| this: <literal>new |
| Configuration(Configuration.getVersion())</literal>. Doing that |
| defeats the purpose of |
| <literal>incompatibleImprovements</literal>, and makes upgrading |
| FreeMarker a potentially breaking change. Furthermore, doing |
| this probably won't be allowed starting from 2.4.0, and will |
| throw exception. So if above mistake is present in your |
| application, it should be fixed by setting |
| <literal>incompatibleImprovements</literal> to the highest |
| concrete version that's known to be compatible with the |
| application.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>Environment.getDataModelOrSharedVariable(String)</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: AST traversal API now can properly traverse the |
| inside of lambda expressions (such as the parameter list)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added a new <literal>SimpleHash</literal> constructor, |
| where the caller can provide the <literal>Map</literal> instance |
| used as the backing storage, thus allows controlling the |
| ordering, and other technical aspects (like the initial |
| capacity) of it.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_29"> |
| <title>2.3.29</title> |
| |
| <para>Release date: 2019-08-17</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added new built-ins: <link |
| linkend="ref_builtin_filter"><literal>?filter(<replaceable>predicate</replaceable>)</literal></link>, |
| <link |
| linkend="ref_builtin_map"><literal>?map(<replaceable>mapper</replaceable>)</literal></link>, |
| <link |
| linkend="ref_builtin_take_while"><literal>?take_while(<replaceable>predicate</replaceable>)</literal></link>, |
| <link |
| linkend="ref_builtin_drop_while"><literal>?drop_while(<replaceable>predicate</replaceable>)</literal></link>. |
| These allow using lambda expressions, like |
| <literal>users?filter(user -> user.superuser)</literal> or |
| <literal>users?map(user -> user.name)</literal>, or accept a |
| function/method as parameter. Lambda expressions are also new in |
| this release, but they can only be used in said built-ins, so |
| they aren't like in Java for example, and also, unlike the |
| similar Java methods, these built-ins aren't lazy in general, |
| only in specific cases (see more <link |
| linkend="topic.filterLazyEval">here</link>). The main goal of |
| adding these built-ins was to allow conditionally skipping |
| elements in the <literal>list</literal> directive without nested |
| <literal>if</literal>-s that interfere with the <link |
| linkend="ref.directive.sep"><literal>sep</literal> |
| directive</link>, and the <link |
| linkend="ref_builtins_loop_var">loop variable built-ins</link> |
| (see examples <link |
| linkend="ref_list_skipping">here</link>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new built-ins for truncating text. |
| <literal><replaceable>string</replaceable>?truncate(<replaceable>length</replaceable>)</literal> |
| truncates the text to the given length, and by default adds |
| <literal>[...]</literal> at the end if truncation has happened. |
| Truncation happens at word boundaries, unless the result is too |
| short that way, in which case it falls back to truncation mid |
| word. There's also <literal>?truncate_w</literal> to force Word |
| Boundary truncation, and <literal>?truncate_c</literal> (for |
| Character Boundary) that doesn't care about word boundaries. The |
| truncation algorithm is pluggable in the FreeMarker |
| configuration. See <link linkend="ref_builtin_truncate">the |
| reference</link> for more details.</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref_builtin_sequence"><literal>?sequence</literal></link> |
| now collaborates with |
| <literal><replaceable>seq</replaceable>?size</literal>, |
| <literal><replaceable>seq</replaceable>[<replaceable>index</replaceable>]</literal>, |
| <literal><replaceable>seq</replaceable>[<replaceable>range</replaceable>]</literal>, |
| and with some other built-ins (<literal>filter</literal>, |
| <literal>map</literal>, <literal>join</literal>, etc.) to spare |
| collecting all the elements into the memory when possible. For |
| example <literal>anIterator?sequence[1]</literal> will now just |
| fetch the first 2 items, while earlier it has built a sequence |
| that contains all the elements, only to get the 2nd element from |
| that. Or, <literal>anIterator?sequence?size</literal> will now |
| just count the elements, without collecting them into the |
| memory. See <link |
| linkend="ref_builtin_sequence_optimizations">the |
| reference</link> for more details.</para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="topic.extendedJavaDecimalFormat">Extended |
| decimal format</link> parameter <quote>multiplier</quote> was |
| incorrectly written as <quote>multipier</quote>. Now both words |
| are recognized.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>?min</literal> and <literal>?max</literal> will |
| now immediately stop with error when applied on a right |
| unbounded numerical range (like <literal>1..</literal>), as that |
| would run forever anyway.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-109">FREEMARKER-109</link>: |
| In JSP TLD-s, line breaks inside function parameter lists have |
| caused <literal>IllegalArgumentException</literal> |
| <quote>Invalid function signature</quote>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-104">FREEMARKER-104</link>: |
| More helpful log and error messages (especially, no |
| <literal>NullPointerException</literal> cause exception logged |
| during FreeMarker XPath support initialization) if no XPath |
| implementation is available because Java 9 modules don't allow |
| accessing the internal Xalan that's stored under |
| <literal>com.sun</literal> packages. (The messages now recommend |
| adding Apache Xalan or Jaxen as dependency if you need XPath |
| support.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>boolean_format</literal> configuration |
| setting now can be set to <literal>"c"</literal>. Then |
| <literal>${<replaceable>aBoolean</replaceable>}</literal> will |
| behave as |
| <literal>${<replaceable>aBoolean</replaceable>?c}</literal>. |
| This should only be used if you are generating output for |
| non-human (computer) consumption only. If your output has pieces |
| for human audience too, it's still recommended to use |
| <literal>${<replaceable>aBoolean</replaceable>?c}</literal> |
| where <literal>true</literal>/<literal>false</literal> output is |
| needed, and either not set the <literal>boolean_format</literal> |
| at all, or set it to something that's appropriate for everyday |
| users (like <literal>"yes,no"</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>New configuration setting, |
| <literal>fallback_on_null_loop_variable</literal>: Specifies the |
| behavior when reading a loop variable (like <literal>i</literal> |
| in <literal><#list items as i></literal>, or in |
| <literal><@myMacro items; i></literal>) that's |
| <literal>null</literal> (missing); if <literal>true</literal>, |
| FreeMarker will look for a variable with the same name in higher |
| variable scopes, or if <literal>false</literal> the variable |
| will be simply <literal>null</literal> (missing). For backward |
| compatibility the default is <literal>true</literal>. The |
| recommended value for new projects is <literal>false</literal>, |
| as otherwise adding new variables to higher scopes (typically to |
| the data-model) can unintentionally change the behavior of |
| templates.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If the result of |
| <literal><replaceable>seq</replaceable>?size</literal> is |
| compared to an integer <emphasis>literal</emphasis> in a |
| template, like in <literal><replaceable>seq</replaceable>?size |
| != 0</literal>, or <literal><replaceable>seq</replaceable>?size |
| < 1</literal>, and to decide the answer it's enough to know |
| if <literal><replaceable>seq</replaceable></literal> is empty or |
| not (i.e., the exact size isn't needed), and |
| <literal><replaceable>seq</replaceable></literal> implements |
| <literal>TemplateCollectionModelEx</literal>, FreeMarker will |
| call <literal>TemplateCollectionModelEx.isEmpty()</literal> |
| instead of <literal>size()</literal>. Furthermore, if |
| <literal><replaceable>seq</replaceable></literal> is the result |
| of <literal>?filter</literal>, or of a similar built-ins that |
| can provide lazily generated result, it will do counting to |
| figure out the size (rather than constructing the whole sequence |
| in memory), and will limit how far it counts based on what |
| literal the result of <literal>?size</literal> is compared |
| with.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>TemplateModelUtils.wrapAsHashUnion(ObjectWrapper, |
| List<?>)</literal> and |
| <literal>wrapAsHashUnion(ObjectWrapper, Object...)</literal>, |
| which is useful when you want to compose the data-model from |
| multiple objects in a way so that their entries |
| (<literal>Map</literal> key-value pairs, bean properties, etc.) |
| appear together on the top level of the data-model.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>HTMLOutputFormat</literal>, |
| <literal>XMLOutputFormat</literal>, |
| <literal>XHTMLOutputFormat</literal> aren't final classes |
| anymore, furthermore <literal>XHTMLOutputFormat</literal> now |
| extends <literal>XMLOutputFormat</literal>. Same applies to the |
| respective <literal>TemplateOutputModel</literal>-s |
| (<literal>TemplateHTMLOutputModel</literal> is not final |
| anymore, etc.). This allows defining new custom markup output |
| format classes that will work with program logic that's only |
| prepared for the standard markup output formats, because |
| <literal>instanceof |
| <replaceable>SomeStandardOutputFromat</replaceable></literal> |
| will return <literal>true</literal> for them.</para> |
| </listitem> |
| |
| <listitem> |
| <para>When configuring FreeMarker with string values (like with |
| a <literal>.properties</literal> file), in the settings that |
| support the <quote>object builder</quote> syntax, now you can |
| create a <literal>TemplateMarkupOutputModel</literal> value with |
| the new <literal>markup</literal> function, like |
| <literal>markup(HTMLOutputFormat(), |
| "<p>Example</p>")</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>BeansWrapper.clearClassIntrospecitonCache</literal> |
| was deprecated as there's a typo in the method name; use |
| <literal>clearClassIntrospectionCache</literal> instead.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_28"> |
| <title>2.3.28</title> |
| |
| <para>Release date: 2018-04-04</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added new <link linkend="ref_specvar">special |
| variable</link>, <literal>get_optional_template</literal> (<link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-84">FREEMARKER-84</link>). |
| It can be used when you need to include or import a template |
| that's possibly missing, and you need to handle that case on |
| some special way. <link |
| linkend="ref_specvar_get_optional_template">See the details |
| here...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new <link linkend="ref_specvar">special |
| variable</link>, <literal>caller_template_name</literal> (<link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-83">FREEMARKER-83</link>), |
| which returns the name (path) of the template from which the |
| current macro or function was called. It's mostly useful if you |
| want to resolve paths relative to the caller template.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new built-in, |
| <literal><replaceable>templateName</replaceable>?absolute_template_name</literal> |
| or |
| <literal><replaceable>templateName</replaceable>?absolute_template_name(<replaceable>baseName</replaceable>)</literal>, |
| which can be used to convert a relative template name to an |
| absolute template name. <link |
| linkend="ref_builtin_absolute_template_name">See more |
| here...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new built-ins: |
| <literal><replaceable>sequence</replaceable>?min</literal> and |
| <literal><replaceable>sequence</replaceable>?max</literal> |
| (<link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-86">FREEMARKER-86</link>), |
| which return the smallest and greatest item from a list of |
| numbers or date/time/date-times. <link |
| linkend="ref_builtin_min_max">See more here...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>The template language can now be configured to use |
| <literal>[=<replaceable>expression</replaceable>]</literal> |
| instead of |
| <literal>${<replaceable>expression</replaceable>}</literal> and |
| <literal>#{<replaceable>expression</replaceable>}</literal>, |
| which is very useful if you have a lot of |
| <literal>${<replaceable>...</replaceable>}</literal> or |
| <literal>#{<replaceable>...</replaceable>}</literal> in the text |
| that you are generating, and so they should be static text. See |
| <link linkend="dgui_misc_alternativesyntax_interpolation">more |
| about the square bracket interpolation syntax here.</link> The |
| template language can also be configured to only use |
| <literal>${<replaceable>expression</replaceable>}</literal>, and |
| treat |
| <literal>#{<replaceable>expression</replaceable>}</literal> as |
| static text. (See the <literal>interpolation_syntax</literal> |
| configuration setting, or the |
| <literal>Configuration.setInterpolationSyntax(int)</literal> |
| method.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>In string literals, <literal>\=</literal> is now a valid |
| escape sequence, resulting in a <literal>=</literal>. This is |
| useful when you are using the new |
| <literal>[=<replaceable>exp</replaceable>]</literal> |
| interpolation syntax, which can be escaped in a string literal |
| like <literal>"Literal [\=x]"</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed (<link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-83">FREEMARKER-83</link>); |
| this fix is only active when <link |
| linkend="pgui_config_incompatible_improvements_how_to_set"><literal>incomplatible_improvements</literal></link> |
| is set to 2.3.28 (or higher). When calling a macro or function |
| (things defined in a template, not directly in Java) and the |
| argument list contains |
| <literal>.current_template_name</literal>, now it will correctly |
| evaluate to the template that contains the call, rather than to |
| the template that contains the macro or function definition. (Of |
| course, the parameter default value expression is still |
| evaluated in the context of the called macro or |
| function.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: When |
| <literal><replaceable>string</replaceable>?split(<replaceable>separator</replaceable>)</literal> |
| is called with <literal>""</literal> as the argument, the string |
| will be split to characters now. Earlier it has thrown an |
| <literal>IllegalArgumentException</literal> (unless the |
| <literal>r</literal> flag was specified).</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added new <literal>ParserConfiguration</literal> (such as |
| <literal>Configuration</literal> and |
| <literal>TemplateConfiguration</literal>) setting, |
| <literal>interpolation_syntax</literal>. It has 3 possible |
| values:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>legacy</literal> (the default): |
| Interpolations look like |
| <literal>${<replaceable>...</replaceable>}</literal> or |
| <literal>#{<replaceable>...</replaceable>}</literal>. Note |
| that <literal>#{<replaceable>...</replaceable>}</literal> is |
| deprecated for a long time now.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>dollar</literal>: Interpolations look like |
| <literal>${<replaceable>...</replaceable>}</literal>. With |
| this syntax, |
| <literal>#{<replaceable>...</replaceable>}</literal> will be |
| just static text.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>square_bracket</literal>: Interpolations look |
| like <literal>[=<replaceable>...</replaceable>]</literal>. |
| With this syntax |
| <literal>${<replaceable>...</replaceable>}</literal> and |
| <literal>#{<replaceable>...</replaceable>}</literal> will be |
| just static text. So it's useful if you generate output in a |
| format where those (typically |
| <literal>${<replaceable>...</replaceable>}</literal>) are |
| already used, such as to generate JSP pages, or to generate |
| FreeMarker templates that use the default syntax.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>When specifying the <literal>output_format</literal> |
| configuration setting with |
| <literal>String</literal>-<literal>String</literal> key-value |
| pairs (like with <literal>Configuration.setSetting(String, |
| String)</literal> or in a <literal>.properties</literal> file), |
| it's now possible to specify the standard output formats by |
| short name (like <literal>output_format=HTML</literal>) rather |
| than by class name. (Custom formats still has to be referred by |
| class name, as FreeMarker can't discover what their names are, |
| since it's not aware of the custom classes.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added a new |
| <literal>Configuration.removeTemplateFromCache</literal> |
| overload that has a <literal>Object |
| customLookupCondition</literal> parameter. This is useful to |
| manually evacuate a template from the cache that was get with a |
| non-<literal>null</literal> custom lookup condition.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new property to |
| <literal>BeansWrapper.MethodAppearanceDecision</literal>: |
| <literal>replaceExistingProperty</literal>. This is useful when |
| a method like <literal>size()</literal> is exposed as a JavaBean |
| property via |
| <literal>MethodAppearanceDecision.exposeAsProperty</literal>, |
| but there's also a <quote>real</quote> JavaBean property (like |
| <literal>getSize()</literal>) with identical name. By default |
| the real property isn't replaced, but now with |
| <literal>replaceExistingProperty</literal> it can be.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>DirectiveCallPlace</literal> now has a |
| <literal>Template getTemplate()</literal> method, so you can |
| query if from which template was your |
| <literal>TemplateDirectiveModel</literal> called. (This has |
| similar role as <literal>.caller_template_name</literal> for |
| macros/functions.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>Environment.rootBasedToAbsoluteTemplateName(String)</literal>, |
| which converts the root based names typically used for the |
| FreeMarker Java API-s (such as |
| <literal>Configuration.getTemplate(name)</literal>) to an |
| absolute path, which can be safely passed to |
| <literal><#include |
| <replaceable>path</replaceable>></literal> and such, as it |
| won't be misinterpreted to be relative to the directory of the |
| template.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Fixes in exception handling when calling JSP tags:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bug fixed (<link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-88">FREEMARKER-88</link>): |
| If a <literal>TemplateException</literal> that's not a |
| <literal>TemplateModelExceptoin</literal> has occurred in |
| the body (nested content) of a JSP |
| <literal>SimpleTag</literal> (typically, an |
| <literal>InvalidReferenceException</literal>), that has |
| caused a <literal>ClassCastException</literal> in the |
| exception handling code, thus the template processing has |
| thrown that instead of the original exception.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: For JSP Tag based custom tags, if an |
| exception has occurred in the body (nested content), an |
| <literal>IndexOutOfBoundsException</literal> might have |
| occurred, replacing the original exception.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Wrapping of |
| non-<literal>TemplateModelException</literal> |
| <literal>TemplateException</literal>-s (typically |
| <literal>InvalidReferenceException</literal>-s) into |
| <literal>TemplateModelException</literal>-s is now avoided |
| when the <literal>TemplateException</literal> occurs in the |
| body of a JSP tag.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>The default arithmetic engine |
| (<literal>ArithmeticEngine.BIGDECIMAL_ENGINE</literal>) can now |
| compare infinite (both positive and negative) to any other |
| standard numerical type. Earlier, since |
| <literal>BigDecimal</literal> can't represent infinite, it was |
| only working in certain special cases. Also there were some |
| performance optimizations to slightly decrease the impact and |
| number of conversions to <literal>BigDecimal</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Avoided possible performance bottleneck when executing |
| templates on many threads, caused by that |
| <literal>java.beans.PropertyDescriptor.getReadMethod()</literal> |
| is synchronized (<link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-80">FREEMARKER-80</link>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>TemplateModelUtils.getKeyValuePairIterator(TemplateHashModelEx)</literal> |
| static utility class, which can be used to get a |
| <literal>TemplateHashModelEx2.KeyValuePairIterator</literal> |
| even for a non-<literal>TemplateHashModelEx2</literal> object. |
| This simplifies Java code that iterates through key-value |
| pairs.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>freemarker.template.utility.DeepUnwrap</literal> |
| (a rarely used utility) now utilizes when the unwrapped |
| <literal>TemplateModel</literal> implements |
| <literal>TemplateHashModelEx2.getKeyValuePairIterator()</literal>, |
| and thus can unwrap such a hash value even if it has non-string |
| keys. Also, it nows keeps the iteration order of the hashes, as |
| it unwraps into a <literal>LinkedHashMap</literal> instead of |
| into a plain <literal>HashMap</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>freemarker.ext.beans.HashAdapter.size()</literal> |
| was overridden for better performance.</para> |
| </listitem> |
| |
| <listitem> |
| <para>When the <link |
| linkend="pgui_config_incompatible_improvements_how_to_set"><literal>incompatible_improvements</literal> |
| setting</link> is set to 2.3.28 (or greater): Fixed legacy |
| parser glitch where a tag can be closed with an illegal |
| <literal>]</literal> (when it's not part of an expression) |
| despite that the tag syntax is set to angle brackets. For |
| example <literal><#if x]</literal> worked just like |
| <literal><#if x></literal>. Note that this legacy glitch |
| didn't affect the legal usage of <literal>]</literal>, like |
| <literal><#if x[0]></literal> has always worked |
| correctly.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Fixed parser bug that disallowed using |
| <literal>></literal> as the top-level expression inside an |
| interpolation (<literal>${...}</literal>). It had the same |
| reason why <literal><#if x > y></literal> doesn't work |
| as naively expected, but there's no real ambiguity in |
| <literal>${x > y}</literal>, so now it's allowed. Note that |
| <literal>${(x > y)?c}</literal> and <literal>${(x > |
| y)?string('y', 'n')}</literal>, which are how booleans are |
| commonly printed, have always worked, as the |
| <literal>></literal> operation is not on the top-level inside |
| the interpolation.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Fixed incorrect listing of valid |
| <literal>roundingMode</literal>-s in <link |
| linkend="topic.extendedJavaDecimalFormat">extended Java decimal |
| format</link> parsing error message</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Other changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>FreeMarker has graduated from the Apache Incubator (as of |
| 2018-03-21), and now is a normal top-level project at Apache. |
| Therefore, the version number doesn't contain |
| <quote>-incubating</quote> anymore.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_27"> |
| <title>2.3.27 (incubating at Apache)</title> |
| |
| <para>Release date: 2017-11-03</para> |
| |
| <para><emphasis role="bold">This is a stable, final |
| release.</emphasis> The <quote>incubating</quote> suffix is required |
| by the Apache Software Foundation until the project becomes a fully |
| accepted (graduated) Apache project.</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>New directive: <literal>continue</literal> (<link |
| xlink:href="https://sourceforge.net/p/freemarker/feature-requests/79/">sf.net |
| #79</link>, <link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-37">FREEMARKER-37</link>). |
| This can be used inside the <literal>list</literal> directive to |
| skip to the next iteration (similarly as in Java). <link |
| linkend="ref.directive.list.continue">See more...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Added alternative syntaxes for the |
| <literal>&&</literal> (logical <quote>and</quote>) |
| operator: <literal>\and</literal> and |
| <literal>&amp;&amp;</literal>. These are to work around |
| issues in applications where the template must be valid XML |
| (<literal>&&</literal> is not valid XML/HTML, at most |
| places), or where the template entered is stored after XML or |
| HTML escaping. Note that lonely <literal>&amp;</literal>, |
| and <literal>and</literal> without <literal>\</literal> is not |
| recognized for backward compatibility.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-in, <literal>sequence</literal> (<link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-73">FREEMARKER-73</link>). |
| This can be used to work around situations where a listable |
| value lacks some features that you need in the template (like it |
| can't be listed twice, it can't tell its size, etc.), and you |
| can't modify the data-model to fix the problem. <link |
| linkend="ref_builtin_sequence">See more...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed (<link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-70">FREEMARKER-70</link>): |
| The usage of loop variable built-ins, like |
| <literal><replaceable>loopVar</replaceable>?index</literal>, was |
| disallowed by the parser inside interpolations that are inside a |
| string literal expression (as in <literal><#list 1..3 as |
| loopVar>${'${loopVar?index}'}</#list></literal>), |
| saying that there's no loop variable in scope with |
| <literal><replaceable>loopVar</replaceable></literal> |
| name.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: Comments were not allowed by the parser between |
| the <literal>switch</literal> tag and the first |
| <literal>case</literal> tag.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed (<link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-71">FREEMARKER-71</link>): |
| When using |
| <literal><replaceable>exp</replaceable>?eval</literal>, if the |
| expression inside the evaluated string throws an exception, the |
| cause exception of that exception was lost.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added new configuration setting (<link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-48">FREEMARKER-48</link>), |
| <literal>wrap_unchecked_exceptions</literal> |
| (<literal>Configurable.setWrapUncheckedExceptions(boolean)</literal>). |
| When this is <literal>true</literal>, unchecked exceptions |
| thrown during evaluating an expression or during executing a |
| custom directive will be wrapped into a |
| <literal>TemplateException</literal>-s. The advantage of that is |
| that thus the exception will include the location in the |
| template (not just the Java stack trace), and the |
| <literal>TemplateExceptionHandler</literal> will be invoked for |
| it as well. When this setting is <literal>false</literal> (which |
| is the default for backward compatibility), the the unchecked |
| exception will bubble up and thrown by |
| <literal>Template.process</literal>, just as in earlier |
| versions. (Note that plain Java methods called from templates |
| have always wrapped the thrown exception into |
| <literal>TemplateException</literal>, regardless of this |
| setting.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new configuration setting, |
| <literal>attempt_exception_reporter</literal> |
| (<literal>Configurable.setAttemptExceptionReporter(AttemptExceptionReporter)</literal>), |
| to allow the customization of how the exceptions handled (and |
| thus suppressed) by the <link |
| linkend="ref.directive.attempt"><literal>attempt</literal> |
| directive</link> are reported. The default |
| <literal>AttemptExceptionReporter</literal> logs the exception |
| as an error, just as it was in earlier versions, though now the |
| error message will indicate that the exception was thrown inside |
| an <literal>attempt</literal> directive block.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new <literal>BeansWrapper</literal> setting, |
| <literal>preferIndexedReadMethod</literal>. This was added to |
| address a Java 8 compatibility problem; see the bug fix entry |
| below for more information.</para> |
| </listitem> |
| |
| <listitem> |
| <para>When <link |
| linkend="pgui_config_incompatible_improvements_how_to_set"><literal>incomplatible_improvements</literal></link> |
| is set to 2.3.27 (or higher), the following unchecked exceptions |
| (but not their subclasses) will be wrapped into |
| <literal>TemplateException</literal>-s when thrown during |
| evaluating expressions or calling directives: |
| <literal>NullPointerException</literal>, |
| <literal>ClassCastException</literal>, |
| <literal>IndexOutOfBoundsException</literal>, and |
| <literal>InvocationTargetException</literal>. The goal of this |
| is the same as of setting the |
| <literal>wrap_unchecked_exceptions</literal> setting to |
| <literal>true</literal> (see that earlier), but this is more |
| backward compatible, as it avoids wrapping unchecked exceptions |
| that some application is likely to catch specifically (like |
| application-specific unchecked exceptions). (This is related to |
| <link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-48">FREEMARKER-48</link>.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: Starting from Java 8, when the same JavaBeans |
| property has both non-indexed read method (like |
| <literal>String[] getFoos()</literal>) and indexed read method |
| (like <literal>String getFoos(int index)</literal>), |
| <literal>BeansWrapper</literal> and |
| <literal>DefaultObjectWrapper</literal> have mistakenly used the |
| indexed read method to access the property. This is a problem |
| because then the array size was unknown, and thus the property |
| has suddenly become unlistable on Java 8 (that is, |
| <literal><#list myObject.foos as foo></literal> fails). To |
| enable the fix (where it will use the non-indexed read method), |
| you should increase the value of the |
| <literal>incompatibleImprovements</literal> constructor argument |
| of the used <literal>DefaultObjectWrapper</literal> or |
| <literal>BeansWrapper</literal> to 2.3.27. Note that if you |
| leave the <literal>object_wrapper</literal> setting of the |
| <literal>Configuration</literal> on its default, it's enough to |
| increase the <link |
| linkend="pgui_config_incompatible_improvements_how_to_set"><literal>incompatibleImprovements</literal> |
| setting</link> of the <literal>Configuration</literal> to |
| 2.3.27, as that's inherited by the default |
| <literal>object_wrapper</literal>. In case increasing the |
| <literal>incompatibleImprovements</literal> is not an option |
| (because of the other changes it brings), you can instead set |
| the <literal>preferIndexedReadMethod</literal> property of the |
| object wrapper to <literal>false</literal>. Note that this bug |
| haven't surfaced before Java 8, as then |
| <literal>java.beans.Inrospector</literal> has only exposed the |
| non-indexed method when both kind of read method was |
| present.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed (affects Java 8 and later): Regardless of the |
| value of the <literal>preferIndexedReadMethod</literal> setting |
| (see previous point), if one of the indexed read method and the |
| non-indexed read method is inaccessible (i.e., it's declared in |
| a non-public type, and wasn't inherited by a public type), while |
| the other read method is accessible, we will use the accessible |
| one. Earlier, if there was an indexed read method but it was |
| inaccessible, we have given up, and that bean property wasn't |
| visible. Such properties will now be visible again, just as |
| before Java 8. (Before Java 8 |
| <literal>java.beans.Inrospector</literal> has only exposed the |
| non-indexed read method in this case, so we didn't have this |
| problem.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: On OpenJDK 9 (but not on earlier versions, nor |
| on Oracle Java 9 (tested with <quote>build 9+181</quote>)), when |
| you try to use the DOM-based XML support |
| (<literal>freemarker.ext.dom.NodeModel</literal>), unless you |
| happen to have Apache Xalan in the class path, the |
| <literal>NodeModel</literal> constructor will fail with |
| <literal>IllegalAccessError</literal> because <quote>java.xml |
| does not export com.sun.org.apache.xml.internal.utils</quote>. |
| Note that while the exception is not thrown anymore in 2.3.27, |
| FreeMarker can't use the XPath support included in OpenJDK 9, |
| and so templates that try to use XPath expressions (like |
| <literal>doc['//foo']</literal>) will still fail, <link |
| linkend="xgui_imperative_learn_xpath">unless 3rd party XPath |
| support is present</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: When the |
| <literal>TemplateExceptionHandler</literal> suppresses (i.e., |
| doesn't re-throw) an exception, the <link |
| linkend="ref.directive.attempt"><literal>attempt</literal> |
| directive</link> won't log it anymore. (To be precise, the |
| <literal>AttemptExceptionReporter</literal> won't be invoked for |
| it anymore; the default one logs as error.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed (part of <link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-48">FREEMARKER-48</link>): |
| When an arithmetic exception has occurred in an expression |
| (typically division by zero), the template processing has thrown |
| the <literal>ArithmeticException</literal> as is, without |
| packaging it into a <literal>TemplateException</literal>. Thus, |
| the error location in the template wasn't visible in the |
| exception.</para> |
| </listitem> |
| |
| <listitem> |
| <para>When logging error due to an error in an <link |
| linkend="ref.directive.attempt"><literal>attempt</literal> |
| directive</link> block, the log message now indicates that the |
| error was inside an <literal>attempt</literal> block.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed (<link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-52">FREEMARKER-52</link>): |
| When setting the <literal>output_format</literal> from |
| <literal>Properties</literal> or the <literal>setSetting(String, |
| String)</literal> API, the <literal>XHTMLOutputFormat</literal> |
| abbreviation wasn't recognized (for example in a |
| <literal>.properties</literal> file, |
| <literal>output_format=XHTMLOutputFormat</literal> didn't work, |
| only |
| <literal>output_format=freemarker.core.XHTMLOutputFormat()</literal> |
| did).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: When setting the |
| <literal>new_builtin_resolver</literal> from |
| <literal>Properties</literal> or the <literal>setSetting(String, |
| String)</literal> API, it didn't recognize the camel case form |
| of the <literal>allowed_classes</literal> and |
| <literal>trusted_templates</literal> keywords, and throw |
| exception for them. Now <literal>allowedClasses</literal> and |
| <literal>trustedTemplates</literal> can be used as well.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: JSP support haven't tried using the thread |
| context class-loader to load the TLD, instead, it has only used |
| the defining class loader of the FreeMarker classes. This can |
| cause problem in the rare case where |
| <literal>freemarker.jar</literal> is installed on higher scope |
| than the web application (like on the Servlet container level), |
| but the web application contains the TLD.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>Constants.EMPTY_HASH</literal> and |
| <literal>GeneralPurposeNothing</literal> (the value of |
| <literal>missingVar!</literal>) now implements |
| <literal>TemplateHashModelEx2</literal>. Earlier they were only |
| a <literal>TemplateHashModelEx</literal>-s.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>Constants.EMPTY_KEY_VALUE_PAIR_ITERATOR</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Somewhat less synchronization when accessing JavaBean |
| properties (<link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-80">FREEMARKER-80</link>). |
| The problem was that the |
| <literal>java.beans.PropertyDescriptor.getReadMethod</literal> |
| method is synchronized, and |
| <literal>freemarer.ext.beans.BeanModel</literal> has called it |
| each time a property was read. Now that method is only called |
| when the class is first introspected.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Improved/fixed <literal>TemplateTransformModel</literal> |
| behavior (this is a legacy interface that's not used much in |
| user code):</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>Writer |
| TemplateTransformModel.getWriter(Writer out, Map |
| args)</literal> can now return the <literal>out</literal> |
| parameter as is, as FreeMarker now recognizes that it's the |
| same object and so won't call <literal>close()</literal> on |
| it after the end tag.</para> |
| </listitem> |
| |
| <listitem> |
| <para>When <link |
| linkend="pgui_config_incompatible_improvements_how_to_set"><literal>incomplatible_improvements</literal></link> |
| is set to 2.3.27 (or higher), and the returned |
| <literal>Writer</literal> implements |
| <literal>TransformControl</literal>, exceptions that are |
| used internally for flow control (for |
| <literal><#return></literal>, |
| <literal><#break></literal>, etc.) won't be passed to |
| <literal>TransformControl.onError(Throwable)</literal> |
| anymore. Earlier, if <literal>onError</literal> didn't |
| rethrow the exception (though almost all implementation |
| does), you couldn't use said directives inside the |
| transformed block.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Added workaround against <quote>IllegalStateException: zip |
| file closed</quote> and <quote>ZipException: ZipFile |
| closed</quote> issues (caused by bugs outside of FreeMarker) |
| when loading resources included in the FreeMarker jar (see |
| <literal>freemarker.template.utility.ClassUtil.loadProperties</literal>).</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_26"> |
| <title>2.3.26 (incubating at Apache)</title> |
| |
| <para>Release date: 2017-03-25</para> |
| |
| <para><emphasis role="bold">This is a stable, final |
| release.</emphasis> The <quote>incubating</quote> suffix is required |
| by the Apache Software Foundation until the project becomes a fully |
| accepted (graduated) Apache project.</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added |
| <literal><replaceable>node</replaceable>?next_sibling</literal> |
| and |
| <literal><replaceable>node</replaceable>?previous_sibling</literal> |
| to move sideways in a node trees (<link |
| linkend="ref_builtin_next_sibling">see reference...</link>). |
| This works with XML DOM nodes, or with any custom |
| <literal>TemplateNodeModelEx</literal> implementations.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new <literal>@@</literal> keys to XML DOM models: |
| <literal>@@next_sibling_element</literal>, |
| <literal>@@previous_sibling_element</literal>. These get the |
| sibling node if that's an element, with the extra that they |
| silently skip any whitespace text and comment and processing |
| instruction between them. (See more about <literal>@@</literal> |
| keys <link |
| linkend="xgui_imperative_formal">here...</link>)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed (<link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-42">FREEMARKER-42</link>): |
| <literal>?first</literal> now works with FTL collections (things |
| that can be listed but doesn't support getting items by index), |
| not only with sequences. The practical importance of this is |
| that <literal>?first</literal> now always works on Java |
| <literal>Set</literal>-s (which is useful for |
| <literal>Set</literal>-s with well defined ordering), while |
| earlier it has failed depending on the |
| <literal>object_wrapper</literal> configuration setting.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-24">FREEMARKER-24</link>: |
| Added workaround (not enabled by default) to expose Java 8 |
| default methods (and the bean properties they define) to |
| templates, despite that |
| <literal>java.beans.Introspector</literal> (the official |
| JavaBeans introspector) ignores them, at least as of JRE |
| 1.8.0_66. To enable this workaround, either increase the value |
| of the <literal>incompatibleImprovements</literal> constructor |
| argument of <literal>DefaultObjectWrapper</literal> or |
| <literal>BeansWrapper</literal> the used to 2.3.26, or set its |
| <literal>treatDefaultMethodsAsBeanMembers</literal> setting to |
| <literal>true</literal>. Note that if you leave the |
| <literal>object_wrapper</literal> setting of the |
| <literal>Configuration</literal> on its default, it's enough to |
| increase the <literal>incompatibleImprovements</literal> setting |
| of the <literal>Configuration</literal> to 2.3.26, as that's |
| inherited by the default |
| <literal>object_wrapper</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added the |
| <literal>freemarker.template.TemplateNodeModelEx</literal> |
| interface which extends the <literal>TemplateNodeModel</literal> |
| instance with two methods, <literal>TemplateNodeModelEx |
| getNextSibling()</literal> and <literal>TemplateNodeModelEx |
| getPreviousSibling()</literal> methods. This is required by |
| <literal><replaceable>node</replaceable>?next_sibling</literal> |
| and |
| <literal><replaceable>node</replaceable>?previous_sibling</literal> |
| in the templates. This new interface is already implemented by |
| the standard W3C DOM node wrapper of FreeMarker.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Made <literal>+</literal> operator when adding two hashes |
| significantly faster (be removing the overhead caused be |
| throwing and then catching an exception).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Better error messages when someone tries to get an invalid |
| <literal>@@<replaceable>...</replaceable></literal> subvariable |
| of an XML DOM node. (Now it's not issued by the XPath |
| implementation, which just sees it as a syntactical |
| error.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>Configuration.is<replaceable>Xxx</replaceable>ExplictlySet</literal> |
| and |
| <literal>Configuration.unset<replaceable>Xxx</replaceable></literal> |
| methods for the Configuration settings: |
| <literal>locale</literal>, <literal>time_zone</literal>, |
| <literal>default_encoding</literal>. (This can be utilized in |
| frameworks to detect if the application has missed setting |
| these. The backward compatible default values are often |
| unwanted, as they are the default locale, time zone and file |
| encoding of the Java environment.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>locale</literal> and |
| <literal>default_encoding</literal> configuration settings now |
| supports the special <literal>"JVM default"</literal> value when |
| set from Java <literal>.properties</literal> file, or via |
| <literal>Configuration.setSettings(Properties)</literal>, or via |
| the <literal>#setting</literal> directive. Earlier only the |
| <literal>time_zone</literal> setting has supported this |
| value.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: The OSGi |
| <literal>Bundle-RequiredExecutionEnvironment</literal> entry in |
| <literal>META-INF/MANIFEST.MF</literal> has incorrectly stated |
| that the minimum required version is |
| <literal>J2SE-1.4</literal>, while it's in fact |
| <literal>J2SE-1.5</literal>. Also the highest utilized version |
| was raised to <literal>JavaSE-1.8</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: If <link |
| linkend="pgui_config_incompatible_improvements_how_to_set">the |
| <literal>incompatible_improvements</literal> setting</link> is |
| set to 2.3.26 (or higher), |
| <literal><replaceable>exp</replaceable>?interpret</literal> |
| always gets the parser-related settings from the template that |
| it's called from. Earlier, sometimes it got those from the |
| topmost (main) template instead. Similarly, the generated name |
| of the template that <literal>?interpret</literal> creates will |
| always refer to the template where's it's called from.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <literal>MultiTemplateLoader</literal>, when |
| it's in sticky mode (the default), and the |
| <literal>TemplateLoader</literal> that was successfully used for |
| a given name last time doesn't find the template now (let's call |
| it the sticked <literal>TemplateLoader</literal>), and thus |
| <literal>MultiTemplateLoader</literal> falls back to trying all |
| the <literal>TemplateLoader</literal>-s in order, will now skip |
| the sticked <literal>TemplateLoader</literal>, as that was |
| already attempted in the same |
| <literal>MultiTemplateLoader.findTemplateSource</literal> |
| invocation.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: |
| <literal>NodeModel.mergeAdjacentText(Node)</literal> didn't |
| merged all adjacent text nodes, only pairs of adjacent text |
| nodes. (Luckily this method is hardly ever used, and the more |
| often used <literal>NodeModel.simplify(Node)</literal> was |
| working correctly.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Performance improvements in the static utility methods of |
| <literal>NodeModel</literal>: <literal>simplify(Node)</literal>, |
| <literal>mergeAdjacentText(Node)</literal>, |
| <literal>removeComments(Node)</literal>, |
| <literal>removePIs(Node)</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added warning to the JavaDoc of |
| <literal>NodeModel.parse</literal> methods to inform users about |
| the possibility of XML External Entity (XXE) attacks if the |
| source XML (not a template) comes from untrusted source. This is |
| just an XML fact (i.e., that in an XML you can have external |
| entities and they can be exploited), and has no much to do with |
| FreeMarker. Also note that FreeMarker itself never calls |
| <literal>NodeModel.parse</literal>; these are merely convenience |
| methods that some applications directly call themselves to |
| create a <literal>NodeModel</literal> from an XML file. As this |
| method encapsulates the call to the platform XML parser, we |
| thought it's better to point this risk out.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>DefaultObjectWrapper</literal>, only with its |
| <literal>incompatible_improvements</literal> set to 2.3.26 |
| (<link linkend="topic.defaultObjectWrapperIcI">see how |
| here...</link>), wraps |
| <literal>java.util.Enumeration</literal>-s into |
| <literal>freemarker.template.DefaultEnumerationAdapter</literal> |
| (a new class) instead of into |
| <literal>freemarker.ext.beans.EnumerationModel</literal> (as far |
| as <literal>useAdaptersForContainers</literal> is |
| <literal>true</literal>, which is the default). This adapter is |
| cleaner than <literal>EnumerationModel</literal> as it only |
| implements the minimally required FTL type, which avoids some |
| ambiguous situations. (Note that Java API methods aren't exposed |
| anymore as subvariables; if you really need them, you can use |
| <literal>?api</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>DefaultIteratorAdapter</literal> now supports |
| <literal>?api</literal>. It was an oversight that it |
| didn't.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>Configuration.setSetting(String, |
| String)</literal> and <literal>setSettings</literal> now allows |
| <literal>null</literal> value for |
| <literal>template_loader</literal> (because |
| <literal>Configuration.setTemplateLoader(null)</literal> is also |
| allowed for a while.).</para> |
| </listitem> |
| |
| <listitem> |
| <para>The |
| <literal>freemarker.template.TemplateCollectionModelEx</literal> |
| interface and is not experimental anymore, so now it has |
| backward compatibility guarantees. Note that the |
| <literal>TemplateCollectionModelEx.contains(TemplateModel)</literal> |
| method was removed from it.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>freemarker.template.DefaultNonListCollectionAdapter</literal> |
| class is not experimental anymore, so now it has backward |
| compatibility guarantees.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>BeansWrapperConfiguration.classIntrospectorFactory</literal> |
| is not a protected field anymore, but a private one. Especially |
| as the class of that field |
| (<literal>ClassIntrospectorBuilder</literal>) was package |
| private, it's pretty much sure that nobody depends on this |
| field.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Various smaller code cleanups.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Other changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-17">FREEMARKER-17</link>: |
| Removed the Servlet- and JSP-related <literal>*.dtd</literal> |
| files to simplify licensing. We can operate without them as |
| before, as validation with them was disabled earlier too. At |
| this point, everything in the source code of the FreeMarker |
| engine, and everything in the produced |
| <literal>freemarker.jar</literal> was created inside the |
| FreeMarker project.</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-27">FREEMARKER-27</link>: |
| Moved some content from the <literal>NOTICES</literal> files |
| over to the <literal>LICENSE</literal> file, to follow the |
| Apache Incubator guidelines closer.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Various smaller JavaDoc improvements.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_25"> |
| <title>2.3.25 (incubating at Apache)</title> |
| |
| <para>Release date: 2016-06-26</para> |
| |
| <para><emphasis role="bold">This is a stable, final |
| release.</emphasis> The <quote>incubating</quote> suffix is required |
| by the Apache Software Foundation until the project becomes a fully |
| accepted (graduated) Apache project.</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Extended the <link |
| linkend="ref.directive.list"><literal>list</literal> |
| directive</link> to support listing hashes (such as |
| <literal>Map</literal>-s), like <literal><#list map as k, |
| v>${k}: ${v}</#list></literal>, where |
| <literal>k</literal> and <literal>v</literal> are the key and |
| value in the key-value pairs of the hash.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added the <literal>TemplateModelHashEx2</literal> |
| interface that extends <literal>TemplateModelHashEx</literal> |
| with a method for listing the content of the key-value pairs of |
| the hash. (This is utilized by the new hash listing capability |
| of the <link |
| linkend="ref.directive.list"><literal>list</literal> |
| directive</link>, but it's not required by it if all keys are |
| strings.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Lazy imports: With the new boolean settings, |
| <literal>lazy_imports</literal> and |
| <literal>lazy_auto_imports</literal>, you can make imports (as |
| in <literal><#import "lib/utils.ftl" as u></literal>) |
| and/or auto-imports to be lazy. When the import is lazy, the |
| namespace variable (<literal>u</literal> in this example) will |
| be created immediately, just like before, but the imported |
| template will be loaded and processed only when (and if ever) |
| the content of the imported namespace is accessed. The main |
| application of this is with auto-imports, where you don't want |
| the overhead of importing templates that aren't actually used in |
| a template. (Also, a new |
| <literal>Environment.importLib</literal> method overload was |
| added, where you can specify if you want a lazy or an eager |
| import.) These new settings can be set on |
| <literal>Configuration</literal>, <literal>Template</literal> |
| (<literal>TemplateConfiguration</literal>) and |
| <literal>Environment</literal> level.</para> |
| </listitem> |
| |
| <listitem> |
| <para>It's now possible to set the |
| <literal>auto_import</literal> and |
| <literal>auto_include</literal> settings on a per template basis |
| (like templates with a certain name pattern has different |
| auto-imports). This is now possible as these settings were moved |
| from the <literal>Configuration</literal> level down to the more |
| generic <literal>Configurable</literal> level, and so are |
| inherited by <literal>TemplateConfiguration</literal> and |
| <literal>Environment</literal> too.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New <literal>Configuration</literal> (and |
| <literal>TemplateConfiguration</literal>) setting, |
| <literal>tab_size</literal>. This only influences how the column |
| number reported in error messages is calculated (and the column |
| number available with other API-s). It doesn't influence the |
| output of the templates. Defaults to 8.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new setting to |
| <literal>DefaultObjectWrapper</literal> (and to |
| <literal>DefaultObjectWrapperBuilder</literal>): |
| <literal>iterableSupport</literal>. This fixes the issue when |
| you couldn't use <literal>#list</literal> (or |
| <literal>?has_next</literal>, etc.) on a value that only |
| implements Java 5 <literal>java.lang.Iterable</literal> (not to |
| be confused with <literal>Iterator</literal>), but not |
| <literal>Collection</literal>. This is not enabled by default as |
| it's not compatible with some existing templates, most often |
| because they have used |
| <literal>someIterable.iterator()</literal> in the template as a |
| workaround. When this is enabled, the |
| <literal>Iterable</literal> object won't be seen as a generic |
| Java object by FreeMarker anymore, and thus just like with |
| <literal>Collection</literal>-s, its API won't be exposed to the |
| templates (except through <literal>?api</literal>, of |
| course).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>Configurable.getCustomNumberFormatsWithoutFallback</literal> |
| and |
| <literal>Configurable.getCustomDateFormatsWithoutFallback</literal> |
| methods to make it easier for custom code to investigate the |
| custom formal setting <literal>Map</literal> hierarchy.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed (<link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-18">FREEMARKER-18</link>): |
| If you had a JSP custom tag and an EL function defined in the |
| same TLD with the same name, the EL function has overwritten the |
| custom tag. This is a bug introduced in 2.3.23, when EL function |
| support was added. JSP allows a custom tag and an EL function in |
| the same TLD to have the same name. In such case now we combine |
| the two into a single value that is both callable as an user |
| defined directive (<literal><@my.foo...></literal>) and as |
| a function (<literal>my.f(...)</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed (<link |
| xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-19">FREEMARKER-19</link>): |
| The column numbers calculated by the parser has assumed tab size |
| 1 since 2.3.25 (an unwanted side effect of updating JavaCC), |
| while before it has assumed tab size 8. The default was restored |
| to 8. This bug has affected the column numbers in error |
| messages. It also broke the output of some rarely used AIP-s, |
| namely <literal>Template.getSource(beginCol, beginLine, endCol, |
| endLine)</literal>, |
| <literal>TemplateObject.getSource()</literal> and through that |
| <literal>TemplateObject.toString()</literal>, if the first or |
| last line has contain tab characters.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: There was a regression with 2.3.24, where |
| <literal>Configuration.setAutoImports()</literal> haven't |
| removed auto-imports added earlier. (Though it's unlikely that |
| an application uses that method and also adds auto-imports |
| earlier.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: |
| <literal>TemplateConfiguration.apply(Template)</literal> didn't |
| merge the <literal>customDateFormats</literal> and |
| <literal>customNumberFormats</literal> <literal>Map</literal>-s |
| when they were set both in the <literal>Template</literal> and |
| in the applied <literal>TemplateConfiguration</literal>, instead |
| it just kept the value in the <literal>Template</literal> (just |
| like with atomic setting values). Note that it was unlikely to |
| run into this bug, as usually you (or FreeMarker) create a |
| single merged <literal>TemplateConfiguration</literal> with |
| <literal>TemplateConfiguration.merge(TemplateConfiguration)</literal> |
| and then apply it on a fresh template.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Removed FindBugs <literal>@SuppressFBWarnings</literal> |
| annotations from the binary (<literal>freemarker.jar</literal>), |
| as they have caused warnings like this when compiling dependant |
| project with Gradle: <quote>warning: Cannot find annotation |
| method 'value()' in type 'SuppressFBWarnings'</quote></para> |
| </listitem> |
| |
| <listitem> |
| <para>The Maven source artifact now contains the JavaCC |
| generated java files and <literal>FTL.jj</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_24"> |
| <title>2.3.24 (incubating at Apache)</title> |
| |
| <para>Release date: 2016-03-28</para> |
| |
| <para><emphasis role="bold">This is a stable, final |
| release.</emphasis> The <quote>incubating</quote> suffix is required |
| by the Apache Software Foundation until the project becomes a fully |
| accepted (graduated) Apache project. See disclaimer below.</para> |
| |
| <section> |
| <title>Legal changes</title> |
| |
| <para>The owner of FreeMarker is now the Apache Software Foundation. |
| The license is still Apache License Version 2.0, just like earlier, |
| but the owner is different. The official full product name has |
| changed to Apache FreeMarker.</para> |
| </section> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The most important new feature of this release is the |
| <link linkend="dgui_misc_autoescaping">auto-escaping and output |
| formats mechanism</link>, which deprecates escaping with the |
| <link linkend="ref_directive_escape"><literal>escape</literal> |
| directive</link>. These are the changes related to this new |
| mechanism (see earlier link for a guide):</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>New <literal>ftl</literal> header options, |
| <literal>ouput_format</literal> and |
| <literal>auto_esc</literal> to override the |
| <literal>output_format</literal> and |
| <literal>auto_escaping</literal> settings of the template, |
| like <literal><#ftl |
| output_format='HTML'</literal><literal> |
| auto_esc=false></literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-in: <link |
| linkend="ref_builtin_no_esc"><literal>no_esc</literal></link>. |
| Used to prevent auto-escaping, like |
| <literal>${descriptionInHtml?no_esc}</literal>. This doesn't |
| work with <literal><#escape |
| <replaceable>...</replaceable>></literal>, only with the |
| new auto-escaping mechanism.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New FTL type, <quote>markup output</quote>. This is |
| somewhat similar to string, but values of this type aren't |
| auto-escaped by the new escaping mechanism, because they are |
| known to already hold markup. (For example, |
| <literal>?esc</literal> and <literal>?no_esc</literal> |
| returns a value of this type, hence their results are |
| protected from double-escaping problems.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-in: <link |
| linkend="ref_builtin_esc"><literal>esc</literal></link>. |
| Used for escaping with the current output format when |
| auto-escaping is disabled.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-in: <literal>markup_string</literal>. This |
| returns the markup of a <link |
| linkend="dgui_misc_autoescaping_movalues">markup output |
| value</link> as string.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-in: <literal>is_markup_output</literal>, |
| returns <literal>true</literal> if the value is of type |
| <quote>markup output</quote>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New directive: <literal>outputformat</literal>, used |
| to change the output format for a section of a template, |
| like <literal><#outputformat |
| "XML"><replaceable>...</replaceable></#outputformat></literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>New directives: <literal>noautoesc</literal> and |
| <literal>autoesc</literal>, used to turn auto-escaping off |
| and on for a section of a template, like |
| <literal><#noautoesc><replaceable>...</replaceable></#noautoesc></literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-in variable, |
| <literal>.output_format</literal>, returns the current |
| output format at the place of invocation.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-in variable, <literal>.auto_esc</literal>, |
| returns the boolean that tells if auto-escaping is active at |
| the place of invocation.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Block assignments, like <literal><#assign |
| <replaceable>captured</replaceable>><replaceable>...</replaceable></#assign></literal>, |
| when the current <literal>output_format</literal> is some |
| kind of markup (like HTML), will store the captured output |
| not with string type, but with <quote>markup output</quote> |
| type. Thus |
| <literal>${<replaceable>captured</replaceable>}</literal> |
| will not get unwanted escaping.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>+</literal> operator (concatenation) |
| works with the new <quote>markup output</quote> type as |
| well. Like <literal>someMarkup + somePlainText</literal> |
| will result in markup where <literal>somePlainText</literal> |
| is escaped automatically before it's appended to the |
| markup.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>has_content</literal> built-in now |
| supports <quote>markup output</quote> values, considering 0 |
| length markup as empty.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>You can now define custom number and date/time/datetime |
| formatters. These are defined by the programmers (and thus can |
| implement any kind of exotic formatting rules) when configuring |
| FreeMarker, and can be referred with strings starting with |
| <literal>"@"</literal>, like in <literal><#setting |
| number_format='@foo'></literal>, or |
| <literal>${n?string.@foo_params}</literal>, |
| <literal><#setting number_format='@foo params'></literal>, |
| or <literal>${n?string.@foo}</literal>, |
| <literal>${n?string.@foo_params}</literal>. For backward |
| compatibility, the initial <literal>@</literal> only has this |
| special meaning if either you have any custom formats or <link |
| linkend="pgui_config_incompatible_improvements">the |
| <literal>incompatible_improvements</literal> setting</link> is |
| at lest 2.3.24.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Everywhere where Java <literal>DecimalFormat</literal> |
| patterns are used (like in <literal>?string('0.##')</literal> or |
| <literal><#setting number_format="0.##"></literal>), now |
| it's possible to specify options like rounding mode or the |
| symbols used, with a FreeMarker-specific <link |
| linkend="topic.extendedJavaDecimalFormat">extension to the |
| <literal>DecimalFormat</literal> pattern syntax</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new special variable: |
| <literal>.incompatible_improvements</literal>, which returns the |
| <link |
| linkend="pgui_config_incompatible_improvements"><literal>incompatible_improvements</literal> |
| setting</link> of the current FreeMarker configuration, as a |
| string.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>?date</literal>, <literal>?time</literal> and |
| <literal>?datetime</literal> now can be called as 0 argument |
| method, like <literal>?date()</literal>, etc., which returns the |
| exact object that <literal>TemplateDateFormat.parse</literal> |
| returns, instead of the tricky multi-type object that just using |
| <literal>?date</literal> returns. Because custom |
| <literal>TemplateDateFormat</literal> implementations may return |
| custom <literal>TemplateDateModel</literal> implementations, |
| keeping the exact class can be important in some |
| applications.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><@</literal> and <literal></@</literal> is |
| now allowed in string literals that contain |
| <literal>${<replaceable>exp</replaceable>}</literal>, and will |
| be part of the literal as is. Earlier it was a syntactical |
| error.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: With |
| <literal>incompatible_improvements</literal> set to 2.3.24 |
| (<link linkend="topic.defaultObjectWrapperIcI">see how |
| here...</link>), |
| <literal><replaceable>m</replaceable>?is_sequence</literal> |
| doesn't return <literal>true</literal> for Java methods wrapped |
| by <literal>BeansWrapper</literal> and its subclasses (most |
| notably <literal>DefaultObjectWrapper</literal>) anymore, as |
| they only implement the |
| <literal>[<replaceable>index</replaceable>]</literal> operator, |
| but not <literal>?size</literal>, which causes |
| <literal><#list <replaceable>...</replaceable>></literal> |
| to fail, among others.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para><emphasis role="strong">Attention!</emphasis> FreeMarker |
| now requires at least Java 1.5 (aka. Java 5). 2.3.24 has only |
| required Java 1.4. (Reason: Without this, new public API-s |
| couldn't use generics, which affect negatively the majority of |
| users, while old installations that are still using 1.4 are |
| unlikely to update FreeMarker anyway.)</para> |
| </listitem> |
| |
| <listitem> |
| <para><emphasis role="strong">Attention!</emphasis> FreeMarker's |
| JSP support (if it's used) now requires at least JSP 2.0. |
| Earlier it only required JSP 1.1. (Reason: The |
| <literal>jsp-api</literal> dependency for JSP 1.x, which was |
| needed for building, can't be legally present in the Maven |
| Central Repository, nor be provided by freemarker.org.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new configuration setting: |
| <literal>template_configurations</literal>. This allows |
| overriding the settings coming from the shared |
| <literal>Configuration</literal> object for individual |
| templates, based on template name patterns. <link |
| linkend="pgui_config_templateconfigurations">See more |
| here...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Related to the <link linkend="dgui_misc_autoescaping">new |
| auto-escaping mechanism</link>:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>As FTL has now a new type, <quote>markup |
| output</quote>, there's also a corresponding new model |
| interface, <literal>TemplateMarkupOutputModel</literal>. |
| This also means that you can prevent the auto-escaping of |
| values coming from the data-model by returning a |
| <literal>TemplateMarkupOutputModel</literal> instead of a |
| <literal>String</literal>. Like the template author can just |
| write <literal>${messages.foo}</literal>, and it will be |
| auto-escaped or not depending on if the message is known to |
| be markup or not.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new configuration setting: |
| <literal>recognize_standard_file_extensions</literal>. When |
| <literal>true</literal>, templates whose source name ends |
| with <literal>".ftlh"</literal> will get |
| <literal>HTML</literal> <literal>output_format</literal>, |
| and those whose name ends with <literal>".ftlx"</literal> |
| get <literal>XML</literal> <literal>output_format</literal>, |
| in both cases with auto-escaping on. If <link |
| linkend="pgui_config_incompatible_improvements_how_to_set">the |
| <literal>incompatible_improvements</literal> setting</link> |
| is set to 2.3.24 (or higher) then this setting defaults to |
| <literal>true</literal>. Otherwise it's default is |
| <literal>false</literal>, but enabling it is highly |
| recommended.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new configuration setting: |
| <literal>output_format</literal>. This specifies the <link |
| linkend="dgui_misc_autoescaping_outputformat">output |
| format</link> object to use (such as |
| <literal>HTMLOutputFormat.INSTANCE</literal>, |
| <literal>XMLOutputFormat.INSTANCE</literal>, etc.) that |
| governs auto-escaping. The output format can be different |
| for different templates, using the |
| <literal>template_configurations</literal> setting (<link |
| linkend="pgui_config_outputformatsautoesc">see here |
| how...</link>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new configuration setting: |
| <literal>registered_custom_output_formats</literal>. With |
| this you can add new <literal>OutputFormat</literal>-s that |
| templates can refer to by name (like in <literal><#ftl |
| output_format="foo"></literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new configuration setting: |
| <literal>auto_escaping_policy</literal>. This decides when |
| auto-escaping should be enabled depending on the current |
| output format.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Changes related to the custom number and |
| date/time/datetime formating feature:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added new classes for implementing custom formatters: |
| <literal>freemarker.core.TemplateNumberFormat</literal>, |
| <literal>TemplateNumberFormatFactory</literal>, |
| <literal>TemplateDateFormat</literal>, |
| <literal>TemplateDateFormatFactory</literal>, also the |
| exceptions these can throw. These allow implementing any |
| kind of formatting rule that's doable in Java (i.e., they |
| aren't restricted to any <literal>java.text</literal> |
| formatters). Furthermore these formatters get the |
| <literal>TemplateModel</literal> instead of a the bare |
| <literal>java.lang.Number</literal> or |
| <literal>java.util.Date</literal>, which lets you use the |
| extra application-specific meta information that you may |
| pack into the <literal>TemplateModel</literal>-s, such as |
| physical unit, preferred precision, and so on.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added <literal>custom_number_formats</literal> and |
| <literal>custom_date_formats</literal> settings |
| (<literal>Configurable.setCustomNumberFormats(Map<String, |
| TemplateNumberFormatFactory>)</literal> and |
| <literal>Configurable.setCustomDateFormats(Map<String, |
| TemplateDateFormatFactory>)</literal>) with which you can |
| register your own formats. These formats can be referred |
| from everywhere where you can use a string to define a |
| format, with a format string like <literal>"@foo"</literal> |
| or <literal>"@foo params"</literal>, where |
| <literal>"foo"</literal> is the key in the |
| <literal>Map<String, ...></literal> parameter of the |
| earlier shown methods, and the parameters (if any) are |
| interpreted by the |
| <literal>Template<replaceable>Xxx</replaceable>FormatFactory</literal> |
| implementation that you provide. Like, you can issue |
| <literal>cfg.setNumberFormat("@foo params")</literal>, or |
| <literal><#setting number_format='@foo |
| params'></literal>, or |
| <literal>${n?string.@foo_params}</literal>, similarly as you |
| can issue <literal>cfg.setNumberFormat("0.##")</literal>, |
| etc. For backward compatibility, the initial |
| <literal>@</literal> only has this special meaning if either |
| you have any custom formats or <link |
| linkend="pgui_config_incompatible_improvements">the |
| <literal>incompatible_improvements</literal> setting</link> |
| is at least 2.3.24. Note that the |
| <literal>custom_number_formats</literal> and |
| <literal>custom_date_formats</literal> settings can be set |
| per-template (via the new |
| <literal>template_configurations</literal> settings) or |
| per-<literal>Environment</literal> too, thus |
| <literal>@foo</literal> can mean something different in |
| different templates.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new <literal>Environment</literal> methods |
| returning <literal>TemplateNumberFormat</literal> and |
| <literal>TemplateDateFormat</literal> objects. See the |
| <literal>getTemplateNumberFormat(<replaceable>...</replaceable>)</literal> |
| and |
| <literal>getTemplateDateFormat(<replaceable>...</replaceable>)</literal> |
| variations in the API.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>freemarker.core.AliasTemplateNumberFormatFactory</literal> |
| and <literal>AliasTemplateDateFormatFactory</literal>, which |
| can be used to create custom formats that are aliases to |
| other formats. For example, instead of writing |
| <literal>${n?string["0.00"]}</literal> again and again, you |
| can define the custom format <literal>"price"</literal> as |
| the alias to the format string <literal>"0.00"</literal> in |
| the configuration, and then use |
| <literal>${n?string.@price}</literal>. Thus, you can control |
| at a central place how prices look. Furthermore, the alias |
| can chose a different target format string depending on the |
| current locale; this is especially useful for dates, where |
| conventions can significantly differ in different |
| countries.</para> |
| </listitem> |
| |
| <listitem> |
| <para>It's now possible to have HTML or other markup in |
| number and date/time/datetime formatting results, like |
| <literal>1.23*10<sup>6</sup></literal>, which |
| won't be accidentally auto-escaped, as FreeMarker knows that |
| it's already HTML. This is done by returning a |
| <literal>TemplateMarkupOutputModel</literal> instead of a |
| <literal>String</literal>; see the new auto-escaping |
| mechanism earlier. Note that no out-of-the-box format |
| utilizes this (at the moment), but you could write such |
| custom format.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The internal format object caching architecture has |
| been reworked, so that it can handle custom formats too. |
| This reworking also fixes some bottlenecks under highly |
| concurrent load, and some (otherwise unlikely) memory leak |
| possibilities.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>In the <literal>number_format</literal> configuration |
| setting, when it holds a Java <literal>DecimalFormat</literal> |
| pattern (like <literal>"0.##"</literal>), it's now possible to |
| specify options like rounding mode or the symbols used, with a |
| FreeMarker-specific <link |
| linkend="topic.extendedJavaDecimalFormat">extension to the |
| pattern syntax</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New <literal>FreemarkerServlet</literal> init-params (see |
| <link |
| xlink:href="https://freemarker.apache.org/docs/api/freemarker/ext/servlet/FreemarkerServlet.html">the |
| <literal>FreemarkerSerlvet</literal> API documentation</link> |
| for details):</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>OverrideResponseContentType</literal>: |
| Specifies when should we override the |
| <literal>contentType</literal> that's already set (i.e., |
| non-<literal>null</literal>) in the |
| <literal>HttpServletResponse</literal>. Earlier, we have |
| always set it, and that's still the default behavior. But |
| now that this init-param exists, you can change that |
| behavior, so that the <literal>contentType</literal> you |
| have specified before forwarding to |
| <literal>FreemarkerServlet</literal> matters.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>OverrideResponseLocale</literal>: Specifies |
| if we should override the <literal>locale</literal> that's |
| already set (i.e., non-<literal>null</literal>) in the |
| <literal>HttpServletResponse</literal>. Earlier, we have |
| always set it, but now this behavior can be changed so that |
| we only set it if it wasn't already set.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>ResponseCharacterEncoding</literal>: |
| Deprecates the old (and quirky) logic of specifying the |
| output charset, which is putting it into the |
| <literal>ContentType</literal> init-param after the MIME |
| type, otherwise falling back to the template file charset. |
| The possible values are <literal>legacy</literal> (the |
| default for backward compatibility), |
| <literal>fromTemplate</literal> (which is |
| <literal>legacy</literal> without quirks, and is aware of |
| the <literal>outputEncoding</literal> setting), |
| <literal>doNotSet</literal> (keeps what the caller has |
| already set in the <literal>ServletRespone</literal>) and |
| <literal>force</literal> followed by a charset name (forces |
| a specific output charset).</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>freemarker.cache.ByteArrayTemplateLoader</literal>, |
| which is similar to <literal>StringTemplateLoader</literal>, but |
| stores the templates as <literal>byte[]</literal>-s instead of |
| as <literal>String</literal>-s.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Upgraded JavaCC (used during build to generate the FTL |
| parser) from 3.2 to 6.1.2.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added <literal>Configurable.getSettingNames(boolean |
| camelCase)</literal>, which returns the set of valid setting |
| names. This can be useful for auto-completion and such.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Fixes and improvements in the <quote>object |
| builder</quote> mini-language used for configuring FreeMarker |
| from <literal>java.util.Properties</literal> or other |
| string-only sources (not used in templates). This is |
| <emphasis>not to be confused with the template language |
| syntax</emphasis>, which has nothing to do with the |
| <quote>object builder</quote> syntax we are writing about here. |
| The improvements are:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bug fixed: For nested builder expressions, the |
| top-level result class restriction were applied |
| accidentally.</para> |
| </listitem> |
| |
| <listitem> |
| <para>When resolving an expression like |
| <literal>com.example.Foo()</literal>, if there's a builder |
| class (<literal>com.example.FooBuilder</literal>), the |
| non-builder class (<literal>com.example.Foo</literal>) need |
| not exist anymore. After all, |
| <literal>FooBuilder.build()</literal> instantiates from any |
| class it wants to anyway.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>TimeZone</literal> objects can be created |
| like <literal>TimeZone("UTC")</literal>, despite that |
| there's no a such constructor.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added support for creating lists with <literal>[ |
| <replaceable>item1</replaceable>, |
| <replaceable>item2</replaceable>, |
| <replaceable>...</replaceable> |
| <replaceable>itemN</replaceable> ]</literal> syntax.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added support for creating maps with <literal>{ |
| <replaceable>key1</replaceable>: |
| <replaceable>value1</replaceable>, |
| <replaceable>key2</replaceable>: |
| <replaceable>value2</replaceable>, |
| <replaceable>...</replaceable> |
| <replaceable>keyN</replaceable>: |
| <replaceable>valueN</replaceable> }</literal> syntax.</para> |
| </listitem> |
| |
| <listitem> |
| <para>A number without decimal point will now be parsed to |
| <literal>Integer</literal>, <literal>Long</literal>, or |
| <literal>BigInteger</literal>, depending on the size of the |
| number. Earlier all numbers were parsed to |
| <literal>BigDecimal</literal>-s, but that had little |
| importance before lists and maps were added, as the number |
| was converted to the constructor or setter parameter type |
| anyway.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Number literals can have Java type suffixes |
| (<literal>f</literal>, <literal>d</literal>, |
| <literal>l</literal>), plus <literal>bd</literal> for |
| <literal>BigDecimal</literal> and <literal>bi</literal> for |
| <literal>BigInteger</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Public static fields can be referred, like |
| <literal>com.example.MyClass.MY_CONSTANT</literal> or |
| <literal>Configuration.AUTO_DETECT_TAG_SYNTAX</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Decreased the stack usage of template execution, which can |
| have importance if you have very very deeply nested |
| templates.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>MultiTemplateLoader.setSticky(boolean)</literal> and |
| <literal>MultiTemplateLoader.isSticky()</literal>, with which |
| you can disable the default behavior, where once a template was |
| found in a child <literal>TemplateLoader</literal>, it will be |
| searched there first next time (typically, when the template |
| update delay is expired). With the <literal>sticky</literal> |
| property set to <literal>false</literal>, the child |
| <literal>TemplateLoader</literal>-s will be always searched in |
| the order as they were added to the |
| <literal>MultiTemplateLoader</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>StringTemplateLoader.removeTemplate(String)</literal> |
| method.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed, only with |
| <literal>incompatible_improvements</literal> set to 2.3.24 |
| (<link linkend="topic.defaultObjectWrapperIcI">see how |
| here...</link>): Expressions inside interpolations that were |
| inside <emphasis>string literal expressions</emphasis> (not |
| <literal>${<replaceable>...</replaceable>}</literal>-s in |
| general), like in <literal><#assign s="Hello |
| ${name}!"></literal>, always used |
| <literal>incompatibleImprovements</literal> 0 (2.3.0 in effect). |
| This means that expressions inside string literals had missed |
| the <literal>?html</literal>, |
| <literal>?iso_<replaceable>...</replaceable></literal>, |
| <literal>?is_enumerable</literal>, <literal>?c</literal>, etc. |
| fixes/improvements.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="https://sourceforge.net/p/freemarker/bugs/439/">439</link>]: |
| <literal>FileTemplateLoader</literal> with |
| <literal>emulateCaseSensitiveFileSystem</literal> set to |
| <literal>true</literal> (used for development) wasn't properly |
| synchronized, leading to random |
| <literal>NullPointerException</literal>-s or other |
| misbehavior.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: It wasn't well defined when a Java |
| <literal>Iterator</literal> counts as empty. Depending on what |
| <literal>ObjectWrapper</literal> you are using, one of these |
| fixes apply:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>DefaultObjectWrapper</literal> (fix is always |
| active): Operations on the <literal>Iterator</literal> that |
| only check if it's empty without reading an element from it, |
| such as <literal>?has_content</literal>, won't cause a later |
| iteration (or further emptiness check) to fail anymore. |
| Earlier, in certain situations, the second operation has |
| failed saying that the iterator <quote>can be listed only |
| once</quote>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>BeansWrapper</literal> (when it's not |
| extended by <literal>DefaultObjectWrapper</literal>), if |
| it's <literal>incompatibleImprovements</literal> property is |
| set to 2.3.24 (or higher): <literal>Iterator</literal>-s |
| were always said to be non-empty when using |
| <literal>?has_content</literal> and such (i.e., operators |
| that check emptiness without reading any elements). Now an |
| <literal>Iterator</literal> counts as empty exactly if it |
| has no elements left. (Note that this bug has never affected |
| basic functionality, like <literal><#list |
| ...></literal>.)</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: The (rarely used) cause exception of |
| <literal>ParseException</literal>-s wasn't set</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: When the |
| <literal>incomaptible_improvements</literal> setting of an |
| existing <literal>Configuration</literal> was changed, the |
| template cache sometimes wasn't recreated, hence old templates |
| could survive.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed, with |
| <literal>incompatible_improvements</literal> set to 2.3.24 |
| (<link linkend="topic.defaultObjectWrapperIcI">see how |
| here...</link>): The <literal>#import</literal> directive meant |
| to copy the library variable into a global variable if it's |
| executed in the main namespace, but that haven't happened when |
| the imported template was already imported earlier in another |
| namespace.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Fixes in the XML processing feature |
| (<literal>freemarker.ext.dom</literal>):</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bug fixed: XPath queries that has only contained |
| characters that are valid in XML element names and has also |
| contained <literal>::</literal> (which is valid in names in |
| namespace-unware documents), like |
| <literal>e['following-sibling::foo']</literal>, were |
| interpreted as literal element names (giving 0 hits) rather |
| than as XPath expressions. Note that there were no such |
| problem with <literal>e['following-sibling::*']</literal> |
| for example, as it's not a valid XML element name according |
| the XML specification. This fix can actually break |
| applications that has processed namespace unaware XML that |
| use <literal>::</literal> as part of element or attribute |
| names, but such an application is highly unlikely, unlike |
| running into the fixed problem. (Unfortunately, using |
| <literal>incompatible_improvements</literal> wasn't |
| technically possible here.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: The <literal>@@qname</literal> of elements |
| that belong to the XML namespace declared as the default via |
| <literal><#ftl ns_prefixes={'D':'...', ... |
| }></literal> no longer starts with <literal>D:</literal>, |
| instead they just start with no name space prefix.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: In the markup returned by the |
| <literal>@@markup</literal> key, when there were multiple |
| namespaces for which there was no prefix associated with via |
| <literal><#ftl |
| ns_prefixes=<replaceable>...</replaceable>></literal>, |
| all those namespaces were assigned to the same |
| auto-generated <literal>xmlns</literal> prefix (usually |
| <quote>a</quote>). Now they will get <quote>a</quote>, |
| <quote>b</quote>, <quote>c</quote>, etc. prefixes.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>JSP TLD loading now quotes the location of |
| <literal>jar</literal>-s (and other <literal>zip</literal>-s) |
| which can't be loaded due to zip format errors in the error |
| message.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added an overload to |
| <literal>Configuration.getSupportedBuiltInNames</literal> and |
| <literal>Configuration.getSupportedBuiltInDirectiveNames</literal> |
| that has a <literal>namingConvention</literal> parameter. This |
| is useful for tooling as since 2.3.23 we support both camel case |
| naming convention (like |
| <literal><replaceable>s</replaceable>?upperCase</literal>) and |
| the legacy one (like |
| <literal><replaceable>s</replaceable>?upper_case</literal>). |
| Furthermore the old 0 argument overload will now utilize |
| <literal>Configuration.getNamingConvention()</literal> to only |
| return the relevant names if it's not |
| <literal>AUTO_DETECT_NAMING_CONVENTION</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Internal reworking to simplify the AST (the |
| <literal>TemplateElement</literal> structure). The related |
| technically public API was marked as internal for a good while. |
| For those who still use that API, the visible change is that |
| <literal>TemplateElement</literal>-s now almost never has a |
| <literal>MixedContent</literal> parent, instead, the parent is |
| directly whatever element the child element indeed belongs under |
| when you look at the source code (like the enclosing |
| <literal>#list</literal> for example, while earlier you often |
| had to go through a <literal>MixedContent</literal> first whose |
| parent was the <literal>#list</literal>). Note that when you |
| have moved downwards, i.e., towards the child elements, these |
| <literal>MixedContent</literal> parents weren't visible and were |
| silently skipped, so the tree traversal API was inconsistent. |
| Now it's consistent.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Due to the above change again, the return type of |
| <literal>freemarker.core.DebugBreak.accept()</literal> and |
| <literal>freemarker.core.TextBlock.accept()</literal> has |
| changed from <literal>void</literal> to |
| <literal>TemplateElement[]</literal>. This again is highly |
| unlikely to affect anyone, and these meant to be internal API-s |
| anyway, but as these two <literal>accept</literal> methods has |
| wider than package visibility for historical reasons, we mention |
| this change.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The non-public AST API of |
| <literal>freemarker.core.StringLiteral</literal>-s has been |
| changed. In principle it doesn't mater as it isn't a public API, |
| but some might used these regardless to introspect templates. |
| Earlier it had an <quote>embedded template</quote> parameter |
| inside, now it has 0 (for purely static string literals), one or |
| more <quote>value part</quote>-s, which are |
| <literal>String</literal>-s and |
| <literal>Interpolation</literal>-s.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Internal code cleanup: Mostly for consistent source code |
| formatting, also many parser construction/setup cleanup</para> |
| </listitem> |
| |
| <listitem> |
| <para>Source code changes to conform to Apache source release |
| policy, such as adding copyright headers and getting rid of test |
| <literal>jar</literal>-s committed into the source code. Eclipse |
| project files were also removed, instead the |
| <literal>README</literal> describes how to set up the |
| project.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Build script and distribution artifact changes to conform |
| to Apache release policy, most notably it produces separate |
| source and binary releases.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes compared to 2.3.24 Release Candidate 1</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added |
| <literal>MultiTemplateLoader.setSticky(boolean)</literal> and |
| <literal>MultiTemplateLoader.isSticky()</literal>, with which |
| you can disable the default behavior, where once a template was |
| found in a child <literal>TemplateLoader</literal>, it will be |
| searched there first next time (typically, when the template |
| update delay is expired). With the <literal>sticky</literal> |
| property set to <literal>false</literal>, the child |
| <literal>TemplateLoader</literal>-s will be always searched in |
| the order as they were added to the |
| <literal>MultiTemplateLoader</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>StringTemplateLoader.removeTemplate(String)</literal> |
| method.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Source code changes to conform to Apache release policy |
| and recommendations:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>No more binary test <literal>jar</literal>-s committed |
| into the source code (instead, they are generated |
| on-the-fly)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Eclipse project files were removed, instead, the |
| <literal>README</literal> describes how to set up the |
| project.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_23"> |
| <title>2.3.23</title> |
| |
| <para>Date of release: 2015-07-05</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Listing (<literal>#list</literal>) has received some |
| specialized convenience features that target typical tasks |
| people do again and again in templates.</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>New <literal>list</literal> directive child |
| directives. There are <literal>else</literal> and |
| <literal>items</literal> to deal with special cases with |
| 0-length lists, and <literal>sep</literal> for inserting |
| separators between items. For more details, see the <link |
| linkend="ref_directive_list"><literal>list</literal> |
| directive in the Reference</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><link linkend="ref_builtins_loop_var">New built-ins |
| that act on loop variables</link>: |
| <literal><replaceable>var</replaceable>?index</literal> |
| (deprecates |
| <literal><replaceable>var</replaceable>_index</literal>), |
| <literal><replaceable>var</replaceable>?counter</literal> |
| (1-based index), |
| <literal><replaceable>var</replaceable>?has_next</literal> |
| (deprecates |
| <literal><replaceable>var</replaceable>_has_next</literal>), |
| <literal><replaceable>var</replaceable>?is_first</literal>, |
| <literal><replaceable>var</replaceable>?is_last</literal>, |
| <literal><replaceable>var</replaceable>?item_parity</literal> |
| (returns <literal>"odd"</literal> or |
| <literal>"even"</literal>), |
| <literal><replaceable>var</replaceable>?item_parity_cap</literal>, |
| <literal><replaceable>var</replaceable>?item_cycle</literal><literal>(<replaceable>...</replaceable>)</literal>, |
| etc.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Added convenience assignment operators, which can be used |
| in assignment directives (<literal>#assign</literal>, |
| <literal>#global</literal> and <literal>#local</literal> |
| currently) only:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>++</literal> and <literal>--</literal>: For |
| example, <literal><#assign counter++></literal> is |
| equivalent to <literal><#assign counter = counter + |
| 1></literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>+=</literal>, <literal>-=</literal>, |
| <literal>*=</literal>, <literal>/=</literal> and |
| <literal>%=</literal>: For example, <literal><#assign |
| counter += 2></literal> is equivalent to |
| <literal><#assign counter = counter + |
| 2></literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Added the <literal>then</literal> built-in, which can be |
| used like a ternary operator: |
| <literal><replaceable>someBoolean</replaceable>?then(<replaceable>whenTrue</replaceable>, |
| <replaceable>whenFalse</replaceable>)</literal>. Just like with |
| the ternary operator of most other languages, only one of the |
| parameter expressions will be evaluated. <link |
| linkend="ref_builtin_then">More details...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Added the <literal>switch</literal> built-in, which can be |
| used like an in-line (expression) switch-case-default statement: |
| <literal><replaceable>someValue</replaceable>?switch(<replaceable>case1</replaceable>, |
| <replaceable>result1</replaceable>, |
| <replaceable>case2</replaceable>, |
| <replaceable>result2</replaceable>, ... |
| <replaceable>caseN</replaceable>, |
| <replaceable>resultN</replaceable>, |
| <replaceable>defaultResult</replaceable>)</literal>, where |
| <literal><replaceable>defaultResult</replaceable></literal> can |
| be omitted (then it will be error if none of the cases matches). |
| <link linkend="ref_builtin_switch">More details...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Added camel case support for the identifiers that are part |
| of the template language (user defined names aren't affected). |
| For example, now |
| <literal><#noEscape>${x?upperCase}</#noEscape></literal> |
| or <literal><#setting numberFormat="0.0"></literal> or |
| <literal><#ftl stripText=true></literal> are valid. |
| However, within the same template, FreeMarker will require you |
| to use the same naming convention consistently for all |
| identifiers that are part of the template language. It's also |
| possible to enforce the same naming convention on all templates |
| from Java via |
| <literal>Configuration.setNamingConvention(int)</literal>. It's |
| certain that camel case will be the recommended convention |
| starting from some future version, because the Java API-s users |
| call from templates use that too.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new <link linkend="ref_specvar">special |
| variables</link>, <literal>.current_template_name</literal> and |
| <literal>.main_template_name</literal>. These deprecate |
| <literal>.template_name</literal>, which was always broken when |
| it comes to macro calls. The new |
| <literal>.current_template_name</literal> always returns the |
| name of the template that contains the reference to the special |
| variable, and <literal>.main_template_name</literal> always |
| returns the name of the topmost template.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Smaller error message improvements. Like, added tip in the |
| error message for the frequent issue when |
| <literal><replaceable>someMap</replaceable>[<replaceable>someNumber</replaceable>]</literal> |
| complains that |
| <literal><replaceable>someMap</replaceable></literal> is not a |
| sequence nor is coercible to string.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed, activated with setting |
| <literal>incompatible_improvements</literal> to 2.3.23: There's |
| a long existing parse-time rule that says that |
| <literal>#break</literal>, in the FTL source code itself, must |
| occur nested inside a breakable directive, such as |
| <literal>#list</literal> or <literal>#switch</literal>. This |
| check could be circumvented with <literal>#macro</literal> or |
| <literal>#function</literal>, like this: <literal><#list 1..1 |
| as x><#macro |
| callMeLater><#break></#macro></#list><@callMeLater |
| /></literal>. After activating this fix, this will be caught |
| as parse time error.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added |
| <literal>Configuration.setNamingConvention(int)</literal>. By |
| default FreeMarker will auto-detect the naming convention |
| (legacy VS camel case) used for the identifiers that are part of |
| the template language, for each template independently. This |
| setting lets you enforce a naming convention instead.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>Configuration</literal> (and in fact any |
| <literal>Configurable</literal>) setting names now can be |
| written with camel case as well. For example, if you are |
| configuring FreeMarker from properties file, you can have |
| <literal>defaultEncoding=utf-8</literal> instead of |
| <literal>default_encoding=utf-8</literal>. You can use the two |
| naming conventions (camel case, and tradition snake case) mixed, |
| and <literal>Configuration.setNamingConvention(int)</literal> |
| does not influence this behavior.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>Configuration.setTemplateUpdateDelayMilliseconds(long)</literal> |
| and |
| <literal>Configuration.getTemplateUpdateDelayMilliseconds()</literal>. |
| This deprecates <literal>setTemplateUpdateDelay(int)</literal>, |
| which uses seconds resolution, hence going against Java |
| conventions and often leading to misunderstandings. (Also that |
| couldn't have a getter pair.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>template_update_delay</literal> setting, when |
| specified as a string (as inside |
| <literal>java.util.Properties</literal>), supports time units, |
| like in <literal>template_update_delay=500 ms</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added <literal>Environment.getCurrentTemplate()</literal> |
| method, which return the currently executed template (as opposed |
| to the main template).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>WebappTemplateLoader.setAttemptFileAccess(boolean)</literal>, |
| which can be used to disable the legacy trick where we try to |
| load templates through direct file access, so that template |
| updating works without restarting. Disabling URL connection |
| caches |
| (<literal>someURLBasedTemplateLoader.setURLConnectionUsesCaches(false)</literal>, |
| which is also the default since |
| <literal>incompatible_improvements</literal> 2.3.21) probably |
| solves that on modern Servlet containers.</para> |
| </listitem> |
| |
| <listitem> |
| <para>In the <literal>FreemarkerServlet</literal> |
| <literal>TemplatePath</literal> init-param, paths (like |
| <literal>/templates</literal>) can have a |
| <literal>?settings(<replaceable>...</replaceable>)</literal> |
| postfix, with which you can set the JavaBean properties of the |
| resulting <literal>TemplateLoader</literal>. For example: |
| <literal><param-value>/templates?settings(attemptFileAccess=false, |
| URLConnectionUsesCaches=false)</param-value></literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>FileTemplateLoader.setEmulateCaseSensitiveFileSystem(boolean)</literal>. |
| This is handy when you are developing on Windows but will deploy |
| to a platform with case sensitive file system. The default is |
| <literal>false</literal>, and <literal>true</literal> is only |
| meant for development, not for production installations. The |
| default can be overridden by setting the |
| <literal>org.freemarker.emulateCaseSensitiveFileSystem</literal> |
| system property to <literal>true</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="https://sourceforge.net/p/freemarker/bugs/424">424</link>]: |
| <literal>WebappTemplateLoader</literal> didn't find templates |
| that are stored in |
| <literal>WEB-INF/lib/*.jar/META-INF/resources</literal>. Files |
| under that directory are visible as |
| <literal>ServletContext</literal> resources since Servlet 3.0, |
| yet <literal>WebappTemplateLoader</literal> has usually failed |
| to see them because of some internal tricks.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: If a template <quote>file</quote> was |
| successfully opened for reading, but then there was an |
| <literal>IOException</literal> during reading its content, the |
| parser (JavaCC) acted like if the template <quote>file</quote> |
| was ended there, and the exception was suppressed. It's actually |
| a JavaCC quirk that affects many other JavaCC-based languages |
| too, but now FreeMarker has added a workaround in the |
| <literal>Template</literal> constructor, and so now an exception |
| will be thrown as expected.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: |
| <literal>InvalidReferenceException.FAST_INSTANCE</literal> could |
| accidentally store reference to an |
| <literal>Environment</literal> instance, which hence was never |
| garbage collected.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="https://sourceforge.net/p/freemarker/bugs/426/">426</link>]: |
| When setting <literal>incompatible_improvements</literal> to |
| 2.3.22, the special variable reference |
| <literal>.template_name</literal> in templates always returns |
| the name of the main (topmost) template, due to an oversight in |
| 2.3.22. Setting <literal>incompatible_improvements</literal> to |
| 2.3.23 restores the old, backward compatible behavior. (Note |
| that the old behavior that we emulate is itself broken, as it |
| doesn't work well with macro calls; you should use |
| <literal>.current_template_name</literal> or |
| <literal>.main_template_name</literal> instead.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="https://sourceforge.net/p/freemarker/bugs/53/">53</link>]: |
| Template parsing was abnormally slow for templates with very |
| high number AST (abstract syntax tree) nodes on the same |
| hierarchy level.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: When the template was concurrently replaced on |
| the backing store during its first loading was still ongoing, |
| the older version of the template could get into the cache with |
| the time stamp of the new version, hence it wasn't reloaded |
| after the configured update delay.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: The <literal>log_template_exceptions</literal> |
| setting (added in 2.3.22) couldn't be set through the |
| <literal>Configurable.setSetting(String, String)</literal> |
| API.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: |
| <literal>StringUtil.FTLStringLiteralEnc</literal> has escaped |
| <literal>$</literal> (hence generating an illegal escape) and |
| haven't escaped <literal>{</literal> after <literal>$</literal> |
| and <literal>#</literal>. While this function is only used for |
| generating error messages by FreeMarker, it's a public methods |
| so anyone could use it.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugs fixed: Various canonical form glitches (they only |
| affect error messages as far as FreeMarker is concerned).</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Other changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Modernized Manual and site design with improved |
| functionality (always visible navigation tree, search inside the |
| Manual, etc.), thanks to Evangelia Dendramis. (Also now the Site |
| uses the same format and HTML generator as the Manual.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Many smaller Manual and site content |
| updates/improvements.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Notes</title> |
| |
| <para>Changes compared to 2.3.23 RC1:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>.current_name_name</literal> and |
| <literal>.main_template_name</literal> is now missing |
| (<literal>null</literal>) instead of <literal>""</literal> if |
| the template has no name</para> |
| </listitem> |
| |
| <listitem> |
| <para>Some minor error message improvements</para> |
| </listitem> |
| |
| <listitem> |
| <para>Documentation refinements</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_22"> |
| <title>2.3.22</title> |
| |
| <para>Date of release: 2015-03-01</para> |
| |
| <para>Note that since 2.3.22 is designed to be fully backward |
| compatible with the previous 2.3.x releases, <emphasis>some of the |
| improvements and fixes described below are only activated when you |
| specifically ask for 2.3.22 <quote>incompatible |
| improvements</quote></emphasis> (it's always clearly indicated), |
| because they could, with very small chance, break existing |
| applications. For actively maintained applications it's probably |
| better to allow them. See <link |
| linkend="pgui_config_incompatible_improvements_how_to_set">how to set |
| <quote>incomplatible improvements</quote> here</link>.</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>New built-ins: <literal>api</literal> and |
| <literal>has_api</literal>. |
| <literal><replaceable>value</replaceable>?api</literal> provides |
| access to the API (usually, the Java API) of |
| <literal><replaceable>value</replaceable></literal>, like |
| <literal><replaceable>value</replaceable>?api.<replaceable>someJavaMethod()</replaceable></literal> |
| or |
| <literal><replaceable>value</replaceable>?api.<replaceable>someBeanProperty</replaceable></literal>), |
| if the value itself supports exposing its API. This meant to be |
| used rarely, when you need to call a Java method of an object, |
| but the by-design simplistic view of the value that FreeMarker |
| exposes to the templates hides that, and there's no equivalent |
| built-in either. For example, when you put a |
| <literal>Map</literal> into the data-model (and you are using |
| the default object wrapper), <literal>myMap.myMethod()</literal> |
| in a template basically translates to <literal>((Method) |
| myMap.get("myMethod")).invoke(...)</literal> in Java, thus you |
| can't call <literal>myMethod</literal>. If, however, you write |
| <literal>myMap?api.myMethod()</literal> instead, that means |
| <literal>myMap.myMethod()</literal> in Java. Similarly, |
| <literal>myMap?api.myProperty</literal> translates to |
| <literal>myMap.getMyProperty()</literal> in Java, instead of to |
| <literal>myMap.get("myProperty")</literal>.</para> |
| |
| <para><emphasis>If you can, rely on the capabilities of the FTL |
| types and the related built-ins as far as possible. Using |
| <literal>?api</literal> is only the last |
| resort.</emphasis></para> |
| |
| <para>Using <literal>?api</literal> also happens to offer a |
| workaround for the lack of non-<literal>String</literal> |
| <literal>Map</literal> key support in FTL's |
| <literal>[]</literal> operator (as in |
| <literal>myMap[key]</literal>), because now you can write |
| <literal>myMap?api.get(nonStringKey)</literal>.</para> |
| |
| <para><literal>?api</literal> is not enabled by default and |
| isn't available for all values. <link |
| linkend="ref_buitin_api_and_has_api">See more |
| here...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Identifiers (like <literal>someVariable</literal>) can now |
| contain minus (<literal>-</literal>), dot |
| (<literal>.</literal>), and colon (<literal>:</literal>) at any |
| position, but those characters <emphasis>must be escaped with a |
| preceding backslash</emphasis> (<literal>\</literal>), or else |
| they would be interpreted as operators. For example, to read the |
| variable whose name is <quote>data-id</quote>, the correct |
| expression is <literal>data\-id</literal>, as |
| <literal>data-id</literal> would be interpreted as <quote>data |
| minus id</quote>. This also works for named macro parameters, |
| which is useful when you want to accept arbitrary HTML |
| attributes in a catch-all parameter, like in <literal><@box |
| class="someCssClass" data\-id=product.id /></literal>. (When |
| you enumerate the catch-all parameter names inside the macro, |
| the key string you get is <literal>"data-id"</literal> without |
| <literal>\</literal> of course.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added <literal>?lower_abc</literal> and |
| <literal>?upper_abc</literal>. This converts |
| <literal>1</literal>, <literal>2</literal>, |
| <literal>3</literal>, etc., to the string |
| <literal>"a"</literal>, <literal>"b"</literal>, |
| <literal>"c"</literal>, etc. (or for <literal>"A"</literal>, |
| <literal>"B"</literal>, <literal>"C"</literal>, etc.). When |
| reaching <literal>"z"</literal>, it continues like |
| <literal>"aa"</literal>, <literal>"ab"</literal>, etc. This is |
| the same logic that you can see in column labels in spreadsheet |
| applications (like Excel or Calc). <link |
| linkend="ref_builtin_lower_abc">More details...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Added <literal>?keep_before_last</literal> and |
| <literal>?keep_after_last</literal>. Example: |
| <literal>"foo.bar.txt"?keep_before_last(".")</literal> returns |
| <literal>"foo.bar"</literal>, |
| <literal>"foo.bar.txt"?keep_after_last(".")</literal> returns |
| <literal>"txt"</literal>. (These work like |
| <literal>?keep_before</literal> and |
| <literal>?keep_after</literal>, but those look for the first |
| occurrence of the separator.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added many missing UNICODE letters and digits to the set |
| of legal identifier characters, like Korean letters (bug fixed: |
| [<link |
| xlink:href="https://sourceforge.net/p/freemarker/bugs/129/">129</link>])</para> |
| </listitem> |
| |
| <listitem> |
| <para>Error message quality improvements:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Several improvements when calling custom JSP tags; see |
| them in its own section later.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: When localized lookup or template |
| acquisition has kicked in, error messages have still quoted |
| the name used for requesting the template, rather that the |
| actual template source name (like <literal>foo.ftl</literal> |
| instead of <literal>foo_en.ftl</literal>, when the template |
| was get as <literal>foo.ftl</literal>, but behind the scenes |
| was loaded from <literal>foo_en.ftl</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para><quote>Template not found</quote> errors are now more |
| detailed, giving hints about accidentally using |
| <literal>\</literal> instead of <literal>/</literal>, or |
| backing out of the <literal>TemplateLoader</literal>'s root |
| directory.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>#setting</literal> directive gives more |
| helpful error message when the setting name is not |
| recognized, and lists the allowed setting names or a |
| correction suggestion.</para> |
| </listitem> |
| |
| <listitem> |
| <para>When a bad special variable name |
| (<literal>.<replaceable>name</replaceable></literal>) is |
| encountered, the list of available names is shown in the |
| error message.</para> |
| </listitem> |
| |
| <listitem> |
| <para>When <literal>Map.get</literal> or |
| <literal>Map.containsKey</literal> of a wrapped |
| <literal>Map</literal> throws a |
| <literal>ClassCastException</literal> or |
| <literal>NullPointerException</literal>, the error will |
| point to the causing FTL expression (with some explanation), |
| rather than bubbling up as low level runtime error.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Object wrapping improvements:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>DefaultObjectWrapper</literal>, only with its |
| <literal>incompatible_improvements</literal> set to 2.3.22 |
| (<link linkend="topic.defaultObjectWrapperIcI">see how |
| here...</link>), or more precisely, with its new |
| <literal>useAdaptersForContainers</literal> setting set to |
| <literal>true</literal> (which defaults to |
| <literal>true</literal> when |
| <literal>incompatible_improvements</literal> is set to |
| 2.3.22): It doesn't copy <literal>Map</literal>-s, |
| <literal>List</literal>-s, and arrays anymore when wrapping |
| them into <literal>TemplateModel</literal>-s (which is the |
| interface through with templates access all values), just |
| wraps them into thin <literal>TemplateModel</literal> |
| adapters, that will reach the original object for all |
| operations. The wrapped values will be instances of the new |
| <literal>DefaultMapAdapter</literal>, |
| <literal>DefaultListAdapter</literal> and |
| <literal>DefaultArrayAdapter</literal> classes, instead of |
| the legacy (copying) <literal>SimpleHash</literal> and |
| <literal>SimpleSequence</literal> classes. (Note that many |
| projects use pure <literal>BeansWrapper</literal> instead of |
| <literal>DefaultObjectWrapper</literal>, which has always |
| used the adapter approach, albeit a different implementation |
| of it. As the shortcomings of |
| <literal>DefaultObjectWrapper</literal> are fixed now, it's |
| always recommended over <literal>BeansWrapper</literal>, as |
| <literal>BeansWrapper</literal> gives quite confusing |
| multi-typed values and is substantially slower.)</para> |
| |
| <para>While keeping backward compatibility as much as |
| possible was an important factor in this change, this is a |
| quite deep change, so you may want to <link |
| linkend="topic.defaultObjectWrapperSwitchToAdapters">review |
| the consequences and reasons here...</link> (But again, this |
| change is <emphasis>not</emphasis> active by default, so |
| merely updating FreeMarker wont risk the stability of |
| existing applications)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added <literal>TemplateMethodModelEx |
| BeansWrapper.wrap(Object object, Method method)</literal> |
| for wrapping methods without wrapping their parent object |
| and without going through overloaded method selection on |
| invocation time.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="http://sourceforge.net/p/freemarker/bugs/372/">372</link>]: |
| <literal>ClassCastException</literal> when a |
| <literal>SortedMap</literal> (typically, a |
| <literal>TreeMap</literal>) is wrapped with |
| <literal>DefaultObjectWrapper</literal> and then a 1 |
| character long string is get from it that doesn't exist. To |
| fix the issue, if the wrapped <literal>Map</literal> is a |
| <literal>SortedMap</literal> and it's wrapped by |
| <literal>DefaultObjectWrapper</literal>, it won't try to |
| fall back to a <literal>Character</literal> key after with |
| the <literal>String</literal> key has got |
| <literal>null</literal>. (This change should be backward |
| compatible, because when a <literal>SortedMap</literal> has |
| <literal>Character</literal> keys, the initial attempt with |
| <literal>String</literal> key causes |
| <literal>ClassCastException</literal>, thus, such |
| <literal>SortedMap</literal>-s were never usable as FTL |
| hashes.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="http://sourceforge.net/p/freemarker/bugs/368/">368</link>]: |
| Only with <literal>incompatible_improvements</literal> set |
| to 2.3.22 or with its new |
| <literal>useAdaptersForContainers</literal> setting set to |
| <literal>true</literal>: Key order and other behavioral |
| peculiarities of <quote>custom</quote> |
| <literal>Map</literal> types isn't lost anymore. The same |
| stands for <literal>List</literal>-s too.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new setting, |
| <literal>forceLegacyNonListCollections</literal>. This only |
| matters when <literal>useAdaptersForContainers</literal> is |
| <literal>true</literal>. Then, unless you set this to |
| <literal>true</literal>, |
| <literal>java.util.Collection</literal>-s that aren't |
| <literal>List</literal>-s (like <literal>Set</literal>-s) |
| will continue using <literal>SimpleSequence</literal> (i.e., |
| the copying approach) instead of the adapter approach. The |
| default is <literal>false</literal>, at least until |
| <literal>incompatible_improvements</literal> 2.4.0, because |
| <literal>SimpleSequence</literal> gave indexed access to |
| these non-<literal>List</literal>-s, like in |
| <literal>mySet[2]</literal>, which is strange but some |
| existing templates may utilize this, even if only |
| accidentally. With |
| <literal>forceLegacyNonListCollections</literal> set to |
| <literal>false</literal>, indexed access won't be possible |
| for <literal>Set</literal>-s and such anymore (nor will |
| <literal>?first</literal> and <literal>?last</literal> work, |
| but <literal>?size</literal> will still do), so you may want |
| to retest old templates. On the other hand, you get the |
| advantages of the adapter approach. Hence, in new projects |
| it's highly recommended to set |
| <literal>forceLegacyNonListCollections</literal> to |
| <literal>false</literal>. (The adapter approach is |
| implemented by |
| <literal>DefaultNonListCollectionAdapter</literal>.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new, <emphasis>experimental</emphasis> FTL type |
| interface, |
| <literal>freemarker.template.TemplateCollectionModelEx</literal>, |
| which adds the <literal>size()</literal>, |
| <literal>isEmpty()</literal>, and <literal>boolean |
| contains(TemplateModel)</literal> methods to the |
| <literal>TemplateCollectionModel</literal> interface. This |
| was added because when wrapping |
| <literal>java.util.Collections</literal> these extra |
| capabilities area available anyway, but FTL couldn't tap on |
| them till now. While the exact interface details are marked |
| as experimental, the feature itself is already utilized for |
| <literal>?size</literal> when setting the |
| <literal>forceLegacyNonListCollections</literal> property of |
| <literal>DefaultObjectWrapper</literal> to |
| <literal>false</literal> (see earlier).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new <emphasis>experimental</emphasis> interface, |
| <literal>freemarker.template.ObjectWrapperAndUnwrapper</literal>. |
| This extends <literal>ObjectWrapper</literal> with |
| unwrapping functionality. This functionality has already |
| existed for a long time in <literal>BeansWrapper</literal> |
| and its subclasses, like in |
| <literal>DefaultObjectWrapper</literal>, but it wasn't |
| <quote>factored out</quote> into its own published interface |
| that other <literal>ObjectWrapper</literal>-s could |
| implement. This is useful for |
| <literal>TemplateModel</literal> implementations that don't |
| want to require a <literal>BeansWrapper</literal> (or its |
| subclass), only the availability of the unwrapping |
| functionality.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new <emphasis>experimental</emphasis> interfaces |
| to implement <literal>?api</literal> (see it in the FTL |
| section): <literal>TemplateModelWithAPISupport</literal>, |
| <literal>ObjectAPIWrapper</literal>, |
| <literal>RichObjectWrapper</literal>. Note that while the |
| interfaces are experimental, <literal>?api</literal> itself |
| isn't.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para><literal>FreemarkerServlet</literal> improvements:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>FreemarkerServlet</literal> now supports |
| custom JSP EL functions (defined in TLD-s with |
| <literal>function</literal> XML elements). Earlier it has |
| ignored them. The custom EL function can be called like a |
| Java method, for example: <literal><#assign |
| u=JspTaglibs["/WEB-INF/utils.tld"]> ... |
| ${u.truncate(title, 25)}</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: Error message was unhelpful when there was |
| a type mismatch between the actual and the expected type of |
| a custom tag parameter. This was a very frequent problem of |
| users who call JSP taglibs from FTL (the typical |
| "java.lang.IllegalArgumentException: argument type |
| mismatch", without any FTL context). Now it's a proper error |
| with explanation, solution tip, and FTL error |
| position/quotation.</para> |
| </listitem> |
| |
| <listitem> |
| <para>RFE resolved [<link |
| xlink:href="https://sourceforge.net/p/freemarker/feature-requests/113/">113</link>] |
| [<link |
| xlink:href="https://sourceforge.net/p/freemarker/feature-requests/114/">114</link>]: |
| <literal>FreemarkerServlet</literal> can now discover |
| <literal>META-INF/**/*.tld</literal>-s that are visible for |
| the class loader but aren't in |
| <literal>WEB-INF/lib/*.jar</literal>-s. For this feature to |
| be active, you must setup the extra TLD lookup with the |
| <literal>MetaInfTldSources</literal> and/or |
| <literal>ClasspathTlds</literal> |
| <literal>FreemarkerServlet</literal> init-params (see the |
| <link |
| xlink:href="https://freemarker.apache.org/docs/api/freemarker/ext/servlet/FreemarkerServlet.html">Java |
| API documentation of |
| <literal>FreemarkerServlet</literal></link> for the |
| description of these). For example, if you run your |
| application from Eclipse with an embedded Servlet container, |
| and thus the tag library jar-s aren't on the standard |
| locations but are in the classpath like any other |
| dependencies, now you can just write:</para> |
| |
| <programlisting role="unspecified"><init-param> |
| <param-name>MetaInfTldSources</param-name> |
| <param-value>classpath</param-value> |
| </init-param></programlisting> |
| |
| <para>and then all the <literal>META-INF</literal> |
| directories that are visible for the class loader will be |
| searched for TLD-s.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>MetaInfTldSources</literal> and |
| <literal>ClasspathTlds</literal> can also be appended to or |
| replaced by the values of Java system properties |
| <literal>org.freemarker.jsp.metaInfTldSources</literal> and |
| <literal>org.freemarker.jsp.classpathTlds</literal>, |
| respectively. Thus one can adjust these in the Eclipse run |
| configuration without modifying the |
| <literal>web.xml</literal>. (See the <link |
| xlink:href="https://freemarker.apache.org/docs/api/freemarker/ext/servlet/FreemarkerServlet.html">Java |
| API documentation of |
| <literal>FreemarkerServlet</literal></link> for |
| more.)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>FreemarkerServlet</literal> now recognizes |
| the |
| <literal>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</literal> |
| servlet context attribute, and adds entries to |
| <literal>MetaInfTldSources</literal> (introduced above) from |
| it.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added <literal>protected |
| FreemarkerServlet.createTaglibFactory()</literal> to allow |
| fine tuning the settings of the |
| <literal>TaglibFactory</literal>. It now have a few setters, |
| like <literal>setObjectWrapper</literal>, |
| <literal>setMetaInfTldSource</literal>, etc.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new servlet init-param, |
| <literal>BufferSize</literal>. This sets the buffer size via |
| <literal>HTTPServletResponse.setBufferSize()</literal> if |
| the response state still allows that, ignores it |
| otherwise.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>TemplatePath</literal> servlet init-param |
| now supports a new kind of path, that looks like |
| <literal>classpath:com/example/myapp/templates</literal>. |
| This is similar to the old |
| <literal>class://com/example/myapp/templates</literal>, but |
| it uses the Thread Context Class Loader of the thread that |
| initializes <literal>FreemarkerSerlvet</literal>, and thus |
| will work even if <literal>freemarker.jar</literal> is not |
| local to the web application. <literal>class://</literal> |
| has the problem that it uses the defining class loader of |
| <literal>FreemarkerSerlvet</literal> itself (or of its |
| subclass).</para> |
| </listitem> |
| |
| <listitem> |
| <para>If <literal>incompatible_improvements</literal> is set |
| to 2.3.22 (or higher), the <literal>TemplatePath</literal> |
| servlet init-param supports specifying multiple comma |
| separated paths inside |
| <literal>[<replaceable>...</replaceable>]</literal>, like |
| <literal><param-value>[ WEB-INF/templates, |
| classpath:com/example/myapp/templates |
| ]</param-value></literal>. This internally creates a |
| <literal>freemarker.cache.MultiTemplateLoader</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new servlet <literal>init-param</literal>, |
| <literal>ExceptionOnMissingTemplate</literal>. Setting this |
| to <literal>true</literal> changes the behavior on |
| template-not-found errors to similar to what you experience |
| with other kind of template exceptions (a HTTP 500 |
| <quote>Internal Server error</quote> response on most |
| setups). When it's <literal>false</literal> (the legacy |
| behavior), you only get a HTTP 404 <quote>Not found</quote>. |
| While that's also how JSP views work, this turns out to be a |
| problem, because some frameworks give 404 to the visitor too |
| if the MVC view gives 404. But to get to the point where you |
| forward to the MVC View, the visitor had to visit a valid |
| URL, only that page misses its View, so its broken on the |
| server side, so it should be a 500.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new overridable method: |
| <literal>FreemarkerServlet.createDefaultObjectWrapper()</literal>. |
| This can be used for what |
| <literal>createObjectWrapper()</literal> is usually |
| overridden for, but without unwillingly disabling the |
| processing of the related init-params (like of |
| <literal>object_wrapper</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Improved (or fixed) error logging: Now logs will |
| always get into FreeMarker's own log, not only into the |
| servlet container log. Also, earlier template-not-found and |
| template parsing error details logs were sometimes lost, |
| depending on the servlet container.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed, only active with |
| <literal>incompatible_improvements</literal> set to 2.3.22 |
| (or higher): Some kind of values, when put into the JSP |
| <emphasis>page</emphasis> scope (via |
| <literal>#global</literal> or via the JSP |
| <literal>PageContext</literal> API) and later read back with |
| the JSP <literal>PageContext</literal> API (typically in a |
| custom JSP tag), might come back as FreeMarker |
| <literal>TemplateModel</literal> objects instead of as |
| objects with a standard Java type. Other Servlet scopes |
| aren't affected. It's highly unlikely that something expects |
| the presence of this bug. The affected values are of the FTL |
| types listed below, and to trigger the bug, they either had |
| to be created directly in the template (like as an FTL |
| literal or with |
| <literal>?date</literal>/<literal>time</literal>/<literal>datetime</literal>), |
| or you had to use <literal>DefaultObjectWrapper</literal> or |
| <literal>SimpleObjectWrapper</literal> (or a subclass of |
| them):</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>FTL date/time/date-time values may came back as |
| <literal>freemarker.template.SimpleDate</literal>-s, now |
| they come back as <literal>java.util.Date</literal>-s |
| instead.</para> |
| </listitem> |
| |
| <listitem> |
| <para>FTL sequence values may came back as |
| <literal>SimpleSequence</literal>-s, now they come back |
| as <literal>java.util.List</literal>-s as expected. This |
| stands assuming that the |
| <literal>object_wrapper</literal> configuration setting |
| is a subclass of <literal>BeansWrapper</literal> (such |
| as <literal>DefaultObjectWrapper</literal>), but that's |
| practically always the case in applications that use |
| FreeMarker's JSP extension (otherwise it can still work, |
| but it depends on the quality and capabilities of the |
| <literal>ObjectWrapper</literal> implementation).</para> |
| </listitem> |
| |
| <listitem> |
| <para>FTL hash values may came back as |
| <literal>SimpleHash</literal>-es, now they come back as |
| <literal>java.util.Map</literal>-s as expected (again, |
| assuming that the object wrapper is a subclass of |
| <literal>BeansWrapper</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>FTL collection values may came back as |
| <literal>SimpleCollection</literal>-s, now they come |
| back as <literal>java.util.Collection</literal>-s as |
| expected (again, assuming that the object wrapper is a |
| subclass of <literal>BeansWrapper</literal>).</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: Now <literal>*.tld</literal> files are |
| searched in <literal>WEB-INF/</literal> and in all its |
| subdirectories recursively. Earlier they were only searched |
| directly under <literal>WEB-INF/</literal> and |
| <literal>WEB-INF/lib/</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: Leading and trailing whitespace in TLD-s |
| inside the <literal>name</literal> and |
| <literal>tag-class</literal> elements is now removed.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Unwanted behavior fixed: In case multiple TLD-s map to |
| the same tag library URI, now |
| <literal>WEB-INF/**/*.tld</literal>-s has priority over |
| <literal>META-INF/**/*.tld</literal>-s coming from jar-s or |
| classpath directories. Earlier, it was the other way around, |
| except that <literal>META-INF/lib/*.tld</literal>-s could |
| still take precedence randomly. While the JSP specification |
| (2.2) explicitly states that the order is not defined and |
| shouldn't be relied upon, it's just logical that if someone |
| puts a TLD directly under <literal>WEB-INF</literal>, he |
| meant that to be used in that particular web application, |
| rather than the TLD-s coming from the dependency jars which |
| are often shared by multiple web applications.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: Defaults set in an overridden |
| <literal>FreemarkerServlet.createConfiguration</literal> |
| won't be accidentally overwritten by |
| <literal>FreemarkerServlet</literal>'s factory defaults |
| anymore. This was a problem with theses settings only: |
| <literal>template_exception_handler</literal>, |
| <literal>log_template_exceptions</literal>, |
| <literal>object_wrapper</literal>, |
| <literal>template_loader</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: If you had multiple |
| <literal>FreemarkerServlet</literal>-s with different |
| configuration settings in the same servlet context, that |
| could lead to malfunction. (Normally, you only have one, |
| just like there's only one servlet that processes |
| <literal>*.jsp</literal>.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Removed all the <literal>xsd</literal> files |
| (<literal>web-app</literal> and <literal>taglib</literal> |
| schemas) from the FreeMarker artifact and from the XML |
| entity resolver, as they were unused during XML |
| parsing.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Generally improved implementation quality |
| (maintainability, error messages, performance bug fixes, |
| test coverage) and better API documentation.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Logging facility improvements:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Just like earlier, when auto-selecting the logger |
| library (the default behavior), FreeMarker choses Log4j if |
| it's available. But now, if that turns out to be |
| <literal>log4j-over-slf4j</literal>, FreeMarker will use |
| SLF4J directly instead. (This fixes the issue where the |
| logged location points to FreeMarker's log adapter class |
| instead of the real call place.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>FreeMarker now recognizes the |
| <literal>org.freemarker.loggerLibrary</literal> system |
| property, which specifies which logger to use, like |
| <literal>java <replaceable>...</replaceable> |
| -Dorg.freemarker.loggerLibrary=SLF4J</literal>. This option |
| deprecates |
| <literal>Logger.selectLoggerLibrary(int)</literal> as that |
| was inherently unreliable (because you usually can't control |
| class initialization order very well). The system property |
| has precedence over |
| <literal>Logger.selectLoggerLibrary</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Generally improved implementation quality (more info |
| printed when something fails, etc.).</para> |
| </listitem> |
| |
| <listitem> |
| <para>New configuration setting: |
| <literal>log_template_exceptions</literal> |
| (<literal>Configuration.setLogTemplateExceptions(boolean)</literal>). |
| This specifies if <literal>TemplateException</literal>-s |
| thrown by template processing are logged by FreeMarker or |
| not. The default is <literal>true</literal> for backward |
| compatibility, but that results in logging the exception |
| twice in properly written applications, because there the |
| <literal>TemplateException</literal> thrown by the public |
| FreeMarker API is also logged by the caller (even if only as |
| the cause exception of a higher level exception). Hence, in |
| modern applications it should be set to |
| <literal>false</literal>. (Note that this setting has no |
| effect on the logging of exceptions caught by |
| <literal>#attempt</literal>/<literal>#recover</literal>; |
| those are always logged.)</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para><literal>Environment</literal> and custom directive |
| related improvements:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added |
| <literal>Environment.getCurrentDirectiveCallPlace()</literal>, |
| which returns a <literal>DirectiveCallPlace</literal> object |
| when called from a custom directive (i.e., from |
| <literal>TemplateDirectiveModel.execute()</literal>). The |
| <literal>DirectiveCallPlace</literal> objects lets you |
| associate an arbitrary object to the directive invocation |
| inside the template, which can be used for call-place-bound |
| caching (like the minification of non-dynamic nested |
| content). See <literal>DirectiveCallPlace</literal> in the |
| Java API documentation for more.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>Environment.getMainTemplate()</literal>. Deprecated |
| the ambiguous (and often broken: [<link |
| xlink:href="https://sourceforge.net/p/freemarker/bugs/145/">145</link>]) |
| <literal>Environment.getTemplate()</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Template loading:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added new <literal>Configuration</literal> setting, |
| <literal>template_lookup_strategy</literal> |
| (<literal>Configuration.setTemplateLookupStrategy(TemplateLookupStrategy)</literal>). |
| This allows customizing what |
| <literal>TemplateLoader</literal>-level names will be tried |
| when a template is requested. With this you can, for |
| example, define a custom localized lookup sequence instead |
| of the default (which looks like: |
| <literal>foo_de_LU_MAC.ftl, foo_de_LU.ftl, |
| foo_de.ftl,</literal><literal> foo.ftl</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new |
| <literal>Configuration.getTemplate(<replaceable>...</replaceable>)</literal> |
| parameter, <literal>Object customLookupCondition</literal>. |
| This parameter can be used by custom a |
| <literal>TemplateLookupStrategy</literal> to deduce the |
| actual template name(s) from the requested name (similarly |
| to as the default lookup strategy does that based on the |
| locale). For example, on a multi-domain Web site, one may |
| want to define some templates that are specialized to a |
| domain, and thus use the domain name as the custom lookup |
| condition. Then, when <literal>foo.ftl</literal> is |
| requested, a custom |
| <literal>TemplateLookupStrategy</literal> could first look |
| for <literal>@somedomain.com/foo.ftl</literal>, and then for |
| <literal>@default/foo.ftl</literal>. See the JavaDoc of the |
| relevant |
| <literal>Configuration.getTemplate(<replaceable>...</replaceable>)</literal> |
| overload for more details; note there the requirements |
| regarding the <literal>hashCode</literal> and |
| <literal>equals</literal> of the |
| <literal>customLookupCondition</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new <literal>Configuration</literal> setting, |
| <literal>template_name_format</literal> |
| (<literal>Configuration.setTemplateNameFormat(TemplateNameFormat)</literal>). |
| This allows specifying the naming rules used by FreeMarker. |
| For now, custom implementations aren't allowed, and you can |
| only chose between |
| <literal>TemplateNameFormat.DEFAULT_2_3_0</literal> (the |
| default) and <literal>DEFAULT_2_4_0</literal> (recommended, |
| at least for new projects). <literal>DEFAULT_2_4_0</literal> |
| has several advantages, but isn't fully backward compatible |
| (though most applications won't be affected). For typical |
| mistakes like using backslash instead of slash, or backing |
| out of the root, it gives |
| <literal>MalformedTemplateNameFormatException</literal> |
| instead of <literal>TempalteNotFoundException</literal>. It |
| allows scheme names to be terminated with |
| <literal>:</literal> alone, instead of a |
| <literal>://</literal> (which is also supported), like in |
| <literal>classpath:foo/bar.ftl</literal>. It fixes numerous |
| legacy glitches (bugs), mostly related to the interpretation |
| of <literal>..</literal> after special steps like |
| <literal>.</literal> or <literal>*</literal>. See the full |
| list of differences in the <link |
| xlink:href="https://freemarker.apache.org/docs/api/freemarker/cache/TemplateNameFormat.html#DEFAULT_2_4_0">Java |
| API documentation of |
| <literal>TemplateNameFormat.DEFAULT_2_4_0</literal></link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>ClassTemplateLoader</literal> now can be |
| created by specifying a <literal>ClassLoader</literal> |
| directly, rather than by specifying a base |
| <literal>Class</literal>. That is, now there's |
| <literal>ClassTemplateLoader(ClassLoader, String)</literal> |
| constructor, and also a |
| <literal>Configuration.setClassLoaderForTemplateLoading(ClassLoader, |
| String)</literal> method.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new exception, |
| <literal>TemplateNotFoundException</literal>, which is now |
| used instead of <literal>TemplateNotFoundException</literal> |
| when getting a template. As it extends |
| <literal>TemplateNotFoundException</literal>, this change is |
| backward compatible. The main goal was to counter the common |
| misunderstanding that template paths are real file paths. |
| However, the new exception also has the benefit that it can |
| give additional FreeMarker-specific information about the |
| error, like right now it has |
| <literal>getTemplateName()</literal> and |
| <literal>getCustomLookupCondition()</literal> |
| methods.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>Template</literal>-s now have a |
| <literal>getSourceName()</literal> method, in additionally |
| to <literal>getName()</literal>. These two return the same |
| as far as no localized lookup or acquisition |
| (<literal>*</literal> in the name) or other lookup strategy |
| was actively involved. But when it was, |
| <literal>getSourceName()</literal> gives the name with which |
| the template was actually loaded from the |
| <literal>TemplateLoader</literal>, while |
| <literal>getName()</literal> returns (and had always |
| returned) the name with which the template was requested (in |
| canonicalized form). <literal>getName()</literal> is used |
| for everything (like for relative inclusion resolution), |
| except for location information in error messages, which now |
| uses <literal>getSourceName()</literal>. Also, |
| <literal>TemplateException</literal> now has a |
| <literal>getSourceName()</literal> method.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>Configuration.getTemplate(<replaceable>...</replaceable>)</literal> |
| overloads now accept <literal>null</literal> for the |
| <literal>locale</literal> and <literal>encoding</literal> |
| parameters, in which case they use the same defaults as the |
| overloads where the parameter is omitted.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Debugger SPI implementators, attention: The |
| <literal>DebugBreak</literal> instruction will now send the |
| <literal>sourceName</literal> of the template to the |
| <literal>suspendEnvironmentSpi</literal> callback, rather |
| than its <literal>name</literal>. You should also use the |
| <literal>sourceName</literal> in |
| <literal>registerTemplateSpi</literal> and such, not the |
| <literal>name</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Configuration:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added |
| <literal>Configuration.unset<replaceable>Xxx</replaceable></literal> |
| and |
| <literal>is<replaceable>Xxx</replaceable>ExplicitlySet</literal> |
| methods for several settings. Unsetting a setting makes it |
| behave as if |
| <literal>set<replaceable>Xxx</replaceable></literal> was |
| never called, thus the setting will use the default value |
| that fits the current |
| <literal>incompatible_improvements</literal> value and will |
| be adjusted as <literal>incompatible_improvements</literal> |
| is changed later.</para> |
| </listitem> |
| |
| <listitem> |
| <para>When configuring FreeMarker from |
| <literal>java.util.Properties</literal> (or with |
| <literal>String</literal>-<literal>String</literal> |
| name-value pairs in general):</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The <literal>default</literal> setting value is |
| now recognized by |
| <literal>template_exception_handler</literal>, |
| <literal>template_storage</literal>, |
| <literal>template_loader</literal> (and by the new |
| <literal>template_lookup_strategy</literal> and |
| <literal>template_name_format</literal>) settings, and |
| it causes |
| <literal>Configuration.unset<replaceable>Xxx</replaceable>()</literal> |
| to be called.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: When setting |
| <literal>object_wrapper</literal> to |
| <literal>default</literal> (as opposed to not specifying |
| it), it has ignored the |
| <literal>incompatible_improvements</literal> and has |
| always used |
| <literal>ObjectWrapper.DEFAULT_WRAPPER</literal>. This |
| fix only matters when |
| <literal>incompatible_improvements</literal> is exactly |
| 2.3.21, as that's when the default object wrapper was |
| changed from |
| <literal>ObjectWrapper.DEFAULT_WRAPPER</literal> to the |
| result of <literal>new |
| DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_21).build()</literal>, |
| which is a bit different singleton, as it has read-only |
| configuration settings and bug fixed overloaded method |
| selection rules. To use |
| <literal>ObjectWrapper.DEFAULT_WRAPPER</literal> |
| regardless of the value of the |
| <literal>incompatible_improvements</literal> setting, |
| use the new <literal>default_2_3_0</literal> |
| value.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: Changing the value of the |
| <literal>localized_lookup</literal> setting now empties the |
| template cache, so that old lookup results won't be reused. |
| (This of course only matters if you change this setting |
| under an already running service, which is very |
| unlikely.)</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Miscellaneous:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="https://sourceforge.net/p/freemarker/bugs/145/">145</link>], |
| active only with |
| <literal>incompatible_improvements</literal> set to 2.3.22 |
| (or higher): <literal>#include</literal> and |
| <literal>#nested</literal> doesn't change the parent |
| <literal>Template</literal> (see |
| <literal>Configurable.getParent()</literal>) of the |
| <literal>Environment</literal> anymore to the |
| <literal>Template</literal> that's included or where |
| <literal>#nested</literal> <quote>returns</quote> to. Thus, |
| the parent of <literal>Environment</literal> will be now |
| always the main <literal>Template</literal>. (The main |
| <literal>Template</literal> is the |
| <literal>Template</literal> whose <literal>process</literal> |
| or <literal>createProcessingEnvironment</literal> method was |
| called to initiate the output generation.) Note that this |
| only matters if you have set settings directly on |
| <literal>Template</literal> objects (not to be confused with |
| setting settings in templates via |
| <literal>#setting</literal>, which just modifies the |
| <literal>Environment</literal>, and so isn't affected by |
| this fix), and almost nobody does that. Also note that macro |
| calls have never changed the <literal>Environment</literal> |
| parent to the <literal>Template</literal> that contains the |
| macro definition, so there's no change there now.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="https://sourceforge.net/p/freemarker/bugs/419/">419</link>]: |
| FreeMarker doesn't fail anymore when it has no permission to |
| read Java system properties, like when used in unsigned |
| applets. It just logs some warnings.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>HTML_DEBUG</literal> and |
| <literal>DEBUG</literal> |
| <literal>TemplateExceptionHandler</literal> output now |
| contains a warning like <quote>HTML_DEBUG mode; use RETHROW |
| in production!</quote>, due to frequent misuse.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Some fixes and improvements in template canonical form |
| output, and as a consequence of that, in FTL stack trace |
| instruction displaying.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Marked some historically public but otherwise internal |
| API-s as deprecated, so that the disclaimer is more apparent |
| in IDE-s.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Notes</title> |
| |
| <para xml:id="topic.defaultObjectWrapperSwitchToAdapters">The |
| consequences and reasons of introducing adapter approach for |
| container types in <literal>DefaultObjectWrapper</literal> when its |
| incompatibleImprovements is set to 2.3.22:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>With the new approach (the adapter approach), the key |
| order of <literal>Map</literal>-s is never lost. The copying |
| approach could only keep that for <literal>HashMap</literal> |
| subclasses (such as <literal>LinkedHashMap</literal>) and |
| <literal>SortedMap</literal>-s (such as |
| <literal>TreeMap</literal>), but not for more exotic |
| <literal>Map</literal>-s, like Guava's |
| <literal>ImmutableMap</literal>. Also, any other behavioral |
| peculiarities of the original <literal>Map</literal> (e.g., case |
| insensitive key lookup) is kept now.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The exact type and identity of the |
| <literal>Map</literal>/<literal>List</literal> is kept when the |
| wrapped value is passed back to a Java method from the template. |
| With the legacy approach the Java methods have received a |
| <literal>Map</literal> or <literal>List</literal> of a special |
| FreeMarker specific type (that acted as an adapter for the |
| <literal>TemplateModel</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Performance characteristics change, mostly for the better, |
| but it depends on the application. If the template reads the |
| <emphasis>same(!)</emphasis> entry <emphasis>from the data |
| model</emphasis> roughly once or twice (or not at all), which is |
| typical, them the adapter approach gives better results, |
| otherwise the legacy copying approach is faster (as it can reuse |
| the wrapped entry from the previous read), though this slowdown |
| certainly not a concern for most applications. The performance |
| of the new adapter approach is more predictable, because it has |
| no initial <quote>spike</quote> to set up the container copy |
| (especially painful for huge collections), instead the |
| performance is linearly proportional to the number of data model |
| reads (and not to the number of collection entries).</para> |
| </listitem> |
| |
| <listitem> |
| <para>If the |
| <literal>Map</literal>/<literal>List</literal>/array is changed |
| after it was wrapped, the change will now become visible in the |
| data-model. With the copying approach, the wrapped value was a |
| shallow-snapshot of the original |
| <literal>Map</literal>/<literal>List</literal>/array. While it's |
| unlikely that someone has deliberately utilized this, it's a |
| risk factor when switching to adapters.</para> |
| </listitem> |
| |
| <listitem> |
| <para>It's theoretically possible that some code (mostly |
| <literal>TemplateDirectiveModel</literal> implementations) |
| mistakenly assumed that wrapped <literal>Map</literal>-s are |
| <literal>SimpleHash</literal>-es, and wrapped |
| <literal>List</literal>-s are |
| <literal>SimpleSequence</literal>-s, etc., instead of them just |
| being <literal>TemplateHashModel</literal>-s and |
| <literal>TemplateSequenceModel</literal>-s. Such code was always |
| wrong, but now it will indeed break, so it's a risk |
| factor.</para> |
| </listitem> |
| |
| <listitem> |
| <para>As now the exact type of the wrapped original object is |
| used for overloaded method selection, the choice can be |
| different (and similar to what it would be with pure |
| <literal>BeansWrapper</literal>). It's difficult to find cases |
| where this matters. A change is most probable around arrays, as |
| with the copying approach they were unwrapped to |
| <literal>List</literal>-s, not to the original array. As the |
| overloaded method mechanism can convert between arrays and lists |
| (in both directions), it's usually not a problem. But, it |
| doesn't do conversion between different array types when the |
| overloaded method has various types on the parameter position of |
| the array, so that's a risk factor.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>SimpleHash</literal> and |
| <literal>SimpleSequence</literal> haven't become deprecated. |
| They are still used for hashes and sequences created in FTL, and |
| are recommended for values that are built specifically to be |
| used from templates, rather than wrapping an already existing |
| <literal>Map</literal> or <literal>List</literal> or |
| array.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>List</literal>-s and <literal>Map</literal>-s |
| that are exposed to templates in multiple threads are now under |
| greater stress regarding their correct operation under |
| multi-threaded read-only access. This is because the adapters |
| won't copy their contents into well known |
| <literal>List</literal> and <literal>Map</literal> |
| implementations (<literal>HashMap</literal>, |
| <literal>ArrayList</literal>, etc.) before accessing them from |
| multiple threads. So this is mostly a concern with custom |
| <literal>List</literal> and <literal>Map</literal> |
| implementations, which aren't as mature as the standard Java |
| classes. Note that this was always like so with pure |
| <literal>BeansWrapper</literal>, which is used by a lot of |
| projects/frameworks (like by Struts) for a long time, so it's |
| not an uncharted territory.</para> |
| </listitem> |
| |
| <listitem> |
| <para>When the wrapped <literal>List</literal> is a |
| <literal>AbstractSequentialList</literal> (like a |
| <literal>LinkedList</literal>), the resulting adapter will |
| implement <literal>TemplateCollectionModel</literal> for more |
| efficient enumeration (<literal>#list</literal>-ing), in |
| additionally to <literal>TemplateSequenceModel</literal> of |
| course. <literal>TemplateCollectionModel</literal> allows FTL to |
| traverse the list without accessing elements by index. With the |
| legacy copying approach |
| <literal>TemplateCollectionModel</literal> wasn't implemented as |
| it wasn't needed for efficient enumeration there.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Iterators (when you put them directly into the data-model) |
| are wrapped into <literal>DefaultIteratorAdapter</literal> |
| instead of <literal>SimpleCollection</literal>. This has two |
| consequences:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The wrapped <literal>Iterator</literal> is now |
| unwrapped properly to the original Java object when it's |
| passed to Java method from the template.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Wrapped <literal>Iterator</literal>-s (not to be |
| confused with <literal>Iterable</literal>) aren't |
| thread-safe anymore, to spare some synchronizations, after |
| all, exposing the same <literal>Iterator</literal> to |
| multiple parallel template executions doesn't make much |
| sense. This shouldn't be a migration concern, as even |
| earlier, only one of those template executions could succeed |
| (the <quote>content</quote> of <literal>Iterator</literal>-s |
| wasn't copied, so the one who first accessed it become the |
| exclusive owner). The change is just that earlier it was |
| guaranteed that the other threads will fail (that was the |
| thread-safe about it), while now there are no such |
| guarantees.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_21"> |
| <title>2.3.21</title> |
| |
| <para>Date of release: 2014-10-12</para> |
| |
| <para>Note that since 2.3.21 is designed to be fully backward |
| compatible with the previous 2.3.x releases, <emphasis>some of the |
| improvements and fixes described below are only activated when you |
| specifically ask for 2.3.21 <quote>incompatible |
| improvements</quote></emphasis>, because they could, with very small |
| chance, break existing applications. If the dependent project is still |
| actively developed, allowing 2.3.21 "incompatible improvements" is |
| highly recommended. See <link |
| linkend="pgui_config_incompatible_improvements_how_to_set">how to set |
| <quote>incomplatible improvements</quote> here</link>.</para> |
| |
| <para>Note that we have changed our proprietary BSD-style license to |
| Apache License, Version 2.0. See the <link linkend="app_license">new |
| license here</link>.</para> |
| |
| <para>Note that the minimum required Java version was increased from |
| 1.2 to 1.4.</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Improved ranges:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added ranges with exclusive end: |
| <literal><replaceable>start</replaceable>..<<replaceable>end</replaceable></literal> |
| (also can be written as |
| <literal><replaceable>start</replaceable>..!<replaceable>end</replaceable></literal>). |
| <link |
| linkend="dgui_template_exp_direct_ranges">More...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Added length limited ranges: |
| <literal><replaceable>start</replaceable>..*<replaceable>length</replaceable></literal>: |
| For example, <literal>10..*4</literal> gives <literal>[10, |
| 11, 12, 13]</literal>, <literal>10..*-4</literal> gives |
| <literal>[10, 9, 8, 7]</literal>, and |
| <literal>10..*0</literal> gives <literal>[]</literal>. 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. Thus, for example, to take the first 10 characters |
| from the string <literal>s</literal>, or less if |
| <literal>s</literal> is shorter than 10 characters, you can |
| use <literal>s[0..*10]</literal>. <link |
| linkend="dgui_template_exp_seqenceop_slice">More...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Square bracket now accepts range values from any |
| source, like <literal><#assign r = 1..3> |
| ${'foobar'[r]}</literal> will print |
| <literal>"oob"</literal>. Earlier it has only supported |
| ranges that were specified directly inside the square |
| brackets, like <literal>'foobar'[1..3]</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>When slicing a sequence with a right-unbounded range, |
| it's now allowed to have a range start index that's one |
| higher than the last index of the sliced sequence. For |
| example, <literal>['x', 'y'][2..]</literal> is not an error |
| anymore, but an empty sequence. (Of course, <literal>['x', |
| 'y'][3..]</literal> is still an error.)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>someString</replaceable>?substring(<replaceable>from</replaceable>, |
| <replaceable>toExclusive</replaceable>)</literal> and |
| <literal><replaceable>someString</replaceable>?substring(<replaceable>from</replaceable>)</literal> |
| are now deprecated; use this slicing expression instead: |
| <literal><replaceable>someString</replaceable>[<replaceable>from</replaceable>..<<replaceable>toExclusive</replaceable>]</literal> |
| and |
| <literal><replaceable>someString</replaceable>[<replaceable>from</replaceable>..]</literal>. |
| A warning if you are processing XML: Since slicing |
| expressions work both for sequences and strings, and XML |
| nodes in FTL are typically both sequences and strings at the |
| same time, there the equivalent expression is |
| <literal><replaceable>someXmlNode</replaceable>?string[<replaceable>from</replaceable>..<<replaceable>toExclusive</replaceable>]</literal> |
| and |
| <literal><replaceable>exp</replaceable>?string[<replaceable>from</replaceable>..]</literal>, |
| because without the <literal>?string</literal> it would |
| slice the node sequence instead of the text value of the |
| node.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If the <literal>incompatible_improvements</literal> in |
| the FreeMarker configuration is set to at least 2.3.21, |
| right-unbounded ranges become readable (like |
| <literal>#list</literal>-able). Earlier they could only be |
| used for slicing, and behaved like empty sequences |
| otherwise.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>New built-in, <literal>?url_path</literal>: This is the |
| same as <link linkend="ref_builtin_url">the |
| <literal>url</literal> built-in</link>, except that it doesn't |
| escape slash (<literal>/</literal>) characters. This meant to be |
| used for converting paths (like paths coming from the OS or some |
| content repository) that use slash (not backslash!) to a path |
| the can be inserted into the path part of an URL.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-ins for string manipulation:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal><replaceable>someString</replaceable>?keep_before(<replaceable>substring</replaceable>[, |
| <replaceable>flags</replaceable>])</literal>: <link |
| linkend="ref_builtin_keep_before">More...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>someString</replaceable>?keep_after(<replaceable>substring</replaceable>[, |
| <replaceable>flags</replaceable>])</literal>: <link |
| linkend="ref_builtin_keep_after">More...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>someString</replaceable>?remove_beginning(<replaceable>substring</replaceable>)</literal>: |
| <link |
| linkend="ref_builtin_remove_beginning">More...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>someString</replaceable>?remove_ending(<replaceable>substring</replaceable>)</literal>: |
| <link |
| linkend="ref_builtin_remove_ending">More...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>someString</replaceable>?ensure_starts_with(<replaceable>substring</replaceable>[, |
| <replaceable>substitution</replaceable>[, |
| <replaceable>flags</replaceable>]])</literal>: <link |
| linkend="ref_builtin_ensure_starts_with">More...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>someString</replaceable>?ensure_ends_with(<replaceable>substring</replaceable>)</literal>: |
| <link |
| linkend="ref_builtin_ensure_ends_with">More...</link></para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>someString</replaceable>?number</literal> |
| now recognizes all XML Schema number formats, like |
| <literal>NaN</literal>, <literal>INF</literal>, |
| <literal>-INF</literal>, plus the Java-native formats |
| <literal>Infinity</literal> and |
| <literal>-Infinity</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If <literal>incompatible_improvements</literal> in the |
| FreeMarker configuration is set to at least 2.3.21, |
| <literal><replaceable>someNumber</replaceable>?c</literal> will |
| return <literal>"INF"</literal>, <literal>"-INF"</literal> and |
| <literal>"NaN"</literal> for positive/negative infinity and IEEE |
| floating point Not-a-Number, respectively. These are the XML |
| Schema compatible representations of these special values. |
| Earlier it has returned what |
| <literal>java.text.DecimalFormat</literal> did with US locale, |
| none of which was understood by any (common) computer |
| language.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-in: |
| <literal><replaceable>someString</replaceable>?boolean</literal>. |
| This is for example useful for converting "true" and "false" |
| strings coming from XML to real boolean values. <link |
| linkend="ref_builtin_boolean">More...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Date/time/date-time related changes:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added new kind of |
| <literal>date_format</literal>/<literal>datetime_format</literal>/<literal>time_format</literal> |
| setting values: XML Schema formats, starting with |
| <literal>"xs"</literal> and ISO 8601:2004 formats, starting |
| with <literal>"iso"</literal>. The format string can be |
| continued with various space (or <literal>_</literal>) |
| separated options, like <literal>h</literal> or |
| <literal>m</literal> or <literal>s</literal> or |
| <literal>ms</literal> for setting shown accuracy, |
| <literal>nz</literal> or <literal>fz</literal> for setting |
| time zone offset visibility, and <literal>u</literal> or, |
| <literal>fu</literal> for using UTC time zone . For example, |
| to use ISO 8601 with minute precision and without the zone |
| offset being shown, set the |
| <literal>datetime_format</literal> setting to <literal>"iso |
| m nz"</literal>, so then the output will be like |
| <literal>2014-09-03T20:56</literal>. <link |
| linkend="topic.dateTimeFormatSettings">More...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Because anything that's accepted as |
| <literal>date_format</literal>/<literal>datetime_format</literal>/<literal>time_format</literal> |
| setting value can also be used with the |
| <literal>?string</literal> and |
| <literal>?date</literal>/<literal>?time</literal>/<literal>?datetime</literal> |
| build-ins, you can use the new formats like |
| <literal>someDate?string.xs</literal> and |
| <literal>someString?date.xs</literal>. (For the |
| <literal>"xs"</literal> and <literal>"iso"</literal> |
| formats, <literal>_</literal> can be used instead of space, |
| which means that, for example, you can write |
| <literal>lastModified?string.iso_m_u</literal> instead of |
| the more verbose <literal>lastModified?string["iso m |
| u"]</literal>.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>That <literal>"iso"</literal> and |
| <literal>"xs"</literal> are now possible |
| <literal>date_format</literal>/<literal>datetime_format</literal>/<literal>time_format</literal> |
| setting values also means that such values can now be parsed |
| too via |
| <literal>?date</literal>/<literal>?time</literal>/<literal>?datetime</literal>. |
| The main application is with processing XML DOM-s, as there |
| values are coming in as strings, and now you can do |
| something like <literal>order.confirmDate?date.xs</literal> |
| to convert them to real dates.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <link |
| linkend="ref_builtin_date_iso"><literal>?iso_...</literal> |
| built-ins</link> are now deprecated in favor of the new |
| setting values described above. They can be set as the |
| default date/time/date-time format, seamlessly fit into the |
| formatting architecture (and thus can parse strings too), |
| and has more/better options (<literal>ms</literal> always |
| shows 3 millisecond digits, <literal>fz</literal> for |
| forcing showing time zone offset).</para> |
| </listitem> |
| |
| <listitem> |
| <para>If the <quote>incompatible improvements</quote> |
| configuration setting is at least 2.3.21, the |
| <literal>?iso_...</literal> built-ins won't show time zone |
| offset for <literal>java.sql.Time</literal> values anymore. |
| Most databases store time values that aren't in any time |
| zone, but just store hour, minute, second, and decimal |
| second field values, so showing the time zone doesn't make |
| sense. (Notable exceptions are PostgreSQL "time with time |
| zone" columns, where |
| <literal><replaceable>mzTime</replaceable>?string.iso_fz</literal> |
| could be used.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added <literal>?is_time</literal>, |
| <literal>?is_datetime</literal>, |
| <literal>?is_date_only</literal> (should be called |
| <literal>?is_date</literal>, but that was already taken) and |
| <literal>?is_unknown_date_like</literal> to check the exact |
| type of a date-like value.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>?is_date</literal> is now a deprecated name, |
| use <literal>?is_date_like</literal> instead. This is |
| because <literal>?is_date</literal> sounds like it checks if |
| the value is a date without time part, but actually it also |
| returns <literal>true</literal> for time, date-time, and |
| unknown date-like values.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added <literal>?date_if_unknown</literal>, |
| <literal>?time_if_unknown</literal> and |
| <literal>?datetime_if_unknown</literal> built-ins, which |
| mark a date-like value with some of the sub-types: date |
| without time, time, or date-time, respectively. However, if |
| the value already holds this information, the built-in has |
| no effect. That is, it will never convert the sub-type of a |
| value, it only adds the sub-type if it was unknown.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: ISO 8601 dates (via |
| <literal>?iso_...</literal> and <literal>"iso"</literal> |
| format settings) now use proleptic Gregorian calendar for |
| the years before 1582, rather than Julian calendar. This is |
| (indirectly) required by the standard, and it's also how the |
| default Sun/Oracle Java XML Schema date/time/dateTime parser |
| works.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Error message quality improvements (targeting frequent |
| support requests and some error message bugs):</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Fixed glitch where if an <literal>#if</literal> had |
| and <literal>#else</literal> or <literal>#elseif</literal>, |
| the |
| <literal>#if</literal>/<literal>#else</literal>/<literal>#elseif</literal> |
| wasn't hidden in the FTL stack trace when the error was |
| inside its nested block.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Some new context sensitive hints in undefined variable |
| exception error messages.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Fixed unclosed directive error messages at end of file |
| where the wrong unclosed directive name was reported</para> |
| </listitem> |
| |
| <listitem> |
| <para>Better type error messages when accessing XML data |
| (applies when wrapped with |
| <literal>freemarker.ext.dom</literal>):</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Trying to use |
| <literal>node.<replaceable>noSuchChildNodes</replaceable></literal> |
| on a place where scalar value is expected will explain |
| that the problem is that you had no matches in the |
| constructing XML query.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Trying to use |
| <literal>node.<replaceable>multipleSuchChildNodes</replaceable></literal> |
| on a place where scalar value is expected will explain |
| that the problem is that you had multiple matches in the |
| constructing XML query.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Trying to use |
| <literal>node.<replaceable>exactlyOneChildNode</replaceable></literal> |
| as number, date/time/date-time or boolean will explain |
| that values coming from XML are always strings (text), |
| and must be converted explicitly via |
| <literal>?number</literal>, <literal>?boolean</literal>, |
| <literal>?date.xs</literal>, etc.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Trying to use <literal>obj.someMethod</literal> |
| without <literal>()</literal> on a place where method value |
| is not expected will recommend calling the method.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Trying to use methods like |
| <literal>obj.getFoo</literal> or |
| <literal>obj.isFoo</literal> without <literal>()</literal>on |
| a place where method value is not expected will recommend |
| using the <literal>obj.foo</literal> form.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Messages are now much more readable when rendered in |
| environments that don't obey to line-breaks. (This often |
| happens in improperly implemented HTML error pages and logs |
| viewers.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Better FTL instruction stack traces:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Error messages now contain up to 10 lines of FTL |
| stack trace (unless it's on the top of a full FTL stack |
| trace), because the FTL stack trace wasn't printed at |
| all when the exception was a cause exception in a Java |
| stack trace, or when only the value of |
| <literal>getMessage()</literal> was printed instead of a |
| stack trace.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The FTL stack trace is now more self explanatory |
| as it contains more text labels.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Stack frames that belong to nestings are now |
| marked differently, and are filtered out when the stack |
| trace wouldn't fit into the error message |
| otherwise.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <literal>?substring</literal> has thrown |
| low level |
| <literal>java.lang.IndexOutOfBoundsException</literal>-s |
| instead of more descriptive |
| <literal>TemplateModelException</literal>-s with FTL stack |
| trace.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: Slicing with ranges sometimes thrown low |
| level |
| <literal>java.lang.IndexOutOfBoundsException</literal>-s |
| instead of more descriptive |
| <literal>TemplateModelException</literal>-s with FTL stack |
| trace.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="https://sourceforge.net/p/freemarker/bugs/402/">402</link>]: |
| Fixed misleading parser error message when a directive |
| called without its required parameters (like |
| <literal><#list></literal>) was reported as unknown |
| directive.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="http://sourceforge.net/p/freemarker/bugs/222/">222</link>]: |
| Poor quality error message when |
| <literal><replaceable>someString</replaceable>[<replaceable>someIndex</replaceable>]</literal> |
| fails with string index out of bounds.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="http://sourceforge.net/p/freemarker/bugs/27/">27</link>]: |
| Not very good quality error messages when |
| <literal>#import</literal>-ing a template whose parsing |
| fails.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>New <literal>include</literal> directive option, |
| <literal>ignore_missing=<replaceable>boolean</replaceable></literal>. |
| When this is set to <literal>true</literal>, and the template to |
| include is missing, the error will be silently ignored, and |
| nothing will be included.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>setting</literal> directive can now set the |
| <literal>output_encoding</literal> setting.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New special variable: <literal>.locale_object</literal>. |
| This is like <literal>.locale</literal>, except that it's a |
| <literal>java.util.Locale</literal> object, not a string. This |
| is handy if you want to pass the current locale to Java |
| methods.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If <literal>incompatible_improvements</literal> in the |
| FreeMarker configuration is set to at least 2.3.21, hash |
| <emphasis>literals</emphasis> that repeat keys now only have the |
| key once with <literal>?keys</literal>, and only has the last |
| value associated to that key with <literal>?values</literal>. |
| This is consistent with the behavior of |
| <literal><replaceable>hash</replaceable>[<replaceable>key</replaceable>]</literal> |
| and how maps work in Java.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <literal>?is_enumerable</literal> has returned |
| <literal>true</literal> for Java methods get from Java objects, |
| despite that those values aren't <literal><#list |
| ...></literal>-able. (This is actually a historical quirk of |
| <literal>BeansWrapper</literal>, not a bug in |
| <literal>?is_enumerable</literal>, but now |
| <literal>?is_enumerable</literal> is aware of this exceptional |
| case.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="http://sourceforge.net/p/freemarker/bugs/257/">257</link>]: |
| The result value of <literal>?matches</literal> wasn't |
| <quote>reentrant</quote>. For example, you couldn't list the |
| matches inside another listing where you are also listing |
| exactly the same result value (stored in a common variable), as |
| they would consume from the same iterator. Most importantly, |
| even accessing the <literal>?size</literal> of the same result |
| value has terminated the outer listing of the same value.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="http://sourceforge.net/p/freemarker/bugs/229/">229</link>]: |
| If you set <literal>incompatible_improvements</literal> to |
| 2.3.21 (or higher), unclosed comments (<literal><#-- |
| <replaceable>...</replaceable></literal>) and |
| <literal>#noparse</literal>-s won't be silently closed at the |
| end of template anymore, but cause a parsing error |
| instead.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added new <literal>Configuration</literal> constructor, |
| <literal>Configuration(Version |
| incompatibleImprovements)</literal>. This deprecates the vague |
| <literal>Configuration()</literal> constructor, and makes using |
| <literal>setIncompatibleImprovements(Version)</literal> needless |
| in most cases. See an example <link |
| linkend="pgui_quickstart_createconfiguration">here...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>When setting the |
| <literal>incompatible_improvements</literal> setting (like with |
| the constructor above) to 2.3.21, two setting defaults |
| change:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The default of the <literal>object_wrapper</literal> |
| setting |
| (<literal>Configuration.getObjectWrapper()</literal>) |
| changes from |
| <literal>ObjectWrapper.DEFAULT_WRAPPER</literal> to another |
| almost identical <literal>DefaultObjectWrapper</literal> |
| singleton, returned by <literal>new |
| DefaultObjectWrapperBuilder(Version).build()</literal>. The |
| new default object wrapper's <quote>incompatible |
| improvements</quote> version is set to the same as of the |
| <literal>Configuration</literal>. (See later regarding the |
| 2.3.21 <quote>incompatible improvements</quote> of |
| <literal>BeansWrapper</literal> and |
| <literal>DefaultObjectWrapper</literal>). Furthermore, the |
| new default object wrapper doesn't allow changing its |
| settings; setter methods will throw |
| <literal>IllegalStateException</literal>. (If anything tries |
| to call setters on the old default in your application, |
| that's a dangerous bug that won't remain hidden now. As the |
| old default is a singleton too, potentially shared by |
| independently developed components, most of them expects the |
| out-of-the-box behavior from it (and the others are |
| necessarily buggy). Also, then concurrency glitches can |
| occur (and even pollute the class introspection cache) |
| because the singleton is modified after publishing.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>The default of the <literal>template_loader</literal> |
| setting |
| (<literal>Configuration.getTemplateLoader()</literal>}) |
| changes to <literal>null</literal>, which means that |
| FreeMarker will not find any templates. Earlier the default |
| was a <literal>FileTemplateLoader</literal> that used the |
| current directory as the root. This was dangerous and |
| fragile as you usually don't have good control over what the |
| current directory will be. Luckily, the old default almost |
| never looked for the templates at the right place anyway, so |
| pretty much all applications had to set |
| <literal>template_loader</literal>, so it's unlikely that |
| changing the default breaks your application.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>New <literal>BeansWrapper</literal>, |
| <literal>DefaultObjectWrapper</literal> and |
| <literal>SimpleObjectWrapper</literal> constructor that takes a |
| <literal>Version</literal> |
| <literal>incompatibleImprovements</literal> argument. This has |
| the same role as the |
| <literal>incompatible_improvements</literal> setting of the |
| <literal>Configuration</literal>, but it applies to the |
| <literal>ObjectWrapper</literal> instead. (As |
| <literal>ObjectWrapper</literal>-s are often shared among |
| multiple <literal>Configuration</literal>-s, so they can't use |
| that setting of the <literal>Configuration</literal>.) In new or |
| actively developed projects it's recommended to use |
| <literal>Configuration.VERSION_2_3_21</literal> now. The |
| constructor without the <literal>Version</literal> parameter is |
| now deprecated.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Safer and more memory-efficient way of managing singletons |
| of <literal>DefaultObjectWrapper</literal>-s and |
| <literal>BeansWrapper</literal>-s that are possibly shared by |
| independently developed subsystems:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Instead of <literal>new |
| DefaultObjectWrapper(<replaceable>...</replaceable>)</literal> |
| and <literal>new |
| BeansWrapper(<replaceable>...</replaceable>)</literal>, from |
| now on you should use <literal>new |
| DefaultObjectWrapperBuilder(version).build()</literal> and |
| <literal>new BeansWrapperBuilder(version).build()</literal>. |
| (The builder objects have properties (configuration |
| settings) like <literal>BeansWrapper</literal> has, which |
| specify the properties of the objects created.) The created |
| objects are <emphasis>singletons</emphasis> (VM-wide, or at |
| least Web-Application-wide) and read-only (means, |
| non-configurable, hence safe to share). The main benefit of |
| using these factories instead of creating new instances is |
| that it allows FreeMarker to share the class introspection |
| caches (an internal part of |
| <literal>BeansWrapper</literal>-s/<literal>DefaultObjectWrapper</literal>-s |
| that is expensive to populate) among the returned instances. |
| This allow sharing the caches (and the object wrappers) |
| between components that aren't aware of each other and use |
| FreeMarker internally.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Deprecated the static fields |
| <literal>ObjectWrapper.DEFAULT_WRAPPER</literal>, |
| <literal>BEANS_WRAPPER</literal> and |
| <literal>SIMPLE_WRAPPER</literal>, because these |
| <literal>ObjectWrapper</literal>-s are configurable (not |
| read-only), and thus dangerous to use as singletons (a badly |
| behaving 3rd party component can mess them up). Use the |
| factories described above instead. They are also more |
| flexible, as you can specify the desired |
| incompatible-improvements version for them and various other |
| <literal>BeansWrapper</literal> settings.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Deprecated all <literal>SimpleHash</literal>, |
| <literal>SimpleCollection</literal> and |
| <literal>SimpleSequence</literal> constructors that didn't |
| take an <literal>ObjectWrapper</literal> argument, as they |
| have usually used |
| <literal>ObjectWrapper.DEFAULT_WRAPPER</literal> as the |
| default, which itself is deprecated.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>BeansWrapper</literal>, |
| <literal>DefaultObjectWrapper</literal> and |
| <literal>SimpleObjectWrapper</literal> now implements the |
| <literal>freemarker.template.utility.WriteProtectable</literal> |
| interface with which the configuration properties of the |
| object wrapper can be set permanently to read-only by |
| calling <literal>writeProtect()</literal>. An attempt to |
| call a setter on a such <literal>ObjectWrapper</literal> |
| will immediately cause |
| <literal>IllegalStateException</literal>. (This is what's |
| used for the singletons returned by the |
| <literal>getInstance</literal> methods too; see |
| earlier).</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>The value of the <literal>time_zone</literal> setting, |
| when you specify it with a <literal>String</literal> (in a |
| <literal>java.util.Properties</literal> object, or via |
| <literal><#setting |
| <replaceable>...</replaceable>></literal>) can now be |
| <literal>"JVM default"</literal> to use the JVM default time |
| zone. The JVM default is the default value of that setting |
| anyway, but now you can state this explicitly, or restore this |
| value if it was overridden earlier.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new configuration setting, |
| <literal>sql_date_and_time_time_zone</literal> |
| (<literal>Configurable.setSQLDateAndTimeTimeZone(TimeZone)</literal>). |
| When this is set to non-<literal>null</literal>, the time zone |
| used when dealing with <literal>java.sql.Date</literal> and |
| <literal>java.sql.Time</literal> values will be this time zone |
| instead of the value of the <literal>time_zone</literal> |
| FreeMarker configuration setting. This is useful because JDBC |
| will, usually, construct the Java <literal>Date</literal> |
| objects so that they will show the year-month-day and |
| hour-minute-seconds values from the database <quote>as |
| is</quote> if you render them using the JVM default time zone. |
| As time zone conversions for SQL date-only and SQL time-only |
| values doesn't make much sense (unlike for SQL timestamps), you |
| should certainly set this setting to the JVM default time zone |
| (<literal>TimeZone.getDefault()</literal>, or if you configure |
| FreeMarker via <literal>java.util.Properties</literal>, as |
| property value "JVM default"). The default value is |
| <literal>null</literal> for backward compatibility. For more |
| details see the JavaDoc of |
| <literal>Configurable.setSQLDateAndTimeTimeZone(TimeZone)</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>When configuring FreeMarker with |
| <literal>java.util.Properties</literal> (typically, when the |
| configuration is stored in a <literal>.properties</literal> |
| file), for the settings where you could specify a fully |
| qualified class name (most notably for the |
| <literal>object_wrapper</literal> setting) now you can also |
| specify constructor arguments and JavaBean property assignments. |
| For example, now you can write |
| <literal>object_wrapper=com.example.MyObjectWrapper(1, 2, |
| exposeFields=true, cacheSize=5000)</literal>that's nearly |
| equivalent with this Java code: <literal>obj = new |
| com.example.MyObjectWrapper(1, 2); obj.setExposeFields(true); |
| obj.setCacheSize(5000); object_wrapper = obj;</literal>. If you |
| are using this new syntax (i.e., if you have parentheses after |
| the class name, even if they are empty), and there's a builder |
| class for the requested class, that will be automatically used. |
| For example, |
| <literal>object_wrapper=DefaultObjectWrapper(2.3.21)</literal> |
| will create a <literal>DefaultObjectWrapperBuilder</literal> to |
| build the final instance, thus the object wrapper will be a |
| singleton instead of a new instance. The new syntax will also |
| look for a public static <literal>INSTANCE</literal> field if |
| there are 0 arguments and property assignments. For more details |
| see the Java API documentation of |
| <literal>Configuration.setSetting</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Template not found exceptions now explain that the |
| template path is interpreted by a template loader, and show the |
| <literal>toString</literal> of the |
| <literal>TemplateLoader</literal>. The out-of-the-box |
| <literal>TemplateLoader</literal> implementations now have an |
| overridden <literal>toString</literal> to show the actual base |
| directory and such details. Custom |
| <literal>TemplateLoader</literal> implementations are encouraged |
| to override <literal>toString</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>Configuration.setSharedVariables(Map/*<String, |
| Object>*/)</literal> for setting the shared variables from |
| Spring IoC and other IoC solutions. The already existing |
| <literal>Configuration.setSharedVariable(String, |
| Object)</literal> isn't a JavaBean property so it was hard to |
| use for that. Furthermore, the order in which |
| <literal>Configuration.setObjectWrapper</literal> and |
| <literal>Configuration.setSharedVariables</literal> are called |
| doesn't mater (unlike in the case of |
| <literal>Configuration.setSharedVariable</literal>), which is |
| essential in most IoC solutions.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Mostly concerning tool (like IDE plugin) authors:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>ParseException</literal>-s now also store the |
| end-location of the error, not just its start-location. This |
| is useful if you want to underline the error in the source |
| code, not just point at it.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>Configuration.getSupportedBuiltInDirectiveNames()</literal> |
| can be used to return the names of directives supported by |
| FreeMarker.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>TemplateExceptions</literal> now expose the |
| position of the error (template name, line, column, end |
| line, end column) similarly to |
| <literal>ParseException</literal>-s. Where applicable, they |
| also expose the blamed expression in its canonical FTL |
| source form; this is mostly useful for |
| <literal>InvalidReferenceException</literal>-s.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>The concurrent performance of overloaded method lookups |
| (from the cache) was improved under Java 5 and later.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>Version</literal> instances that are |
| <quote>incompatible improvements</quote> break points are now |
| available via constants like: |
| <literal>Configuration.VERSION_2_3_21</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>From now on, if you try to set the <quote>incompatible |
| improvements</quote> to greater than the current FreeMarker |
| version, or less than 2.3.0, an |
| <literal>IllegalArgumentException</literal> will be thrown. |
| Thus, <literal>new |
| Configuration(<replaceable>someVersion</replaceable>)</literal> |
| not only activates the fixes up to that version, but ensures |
| that the application will not run in an environment with an |
| older FreeMarker version. (On an older FreeMarker version the |
| improvements that you have requested aren't implemented yet, so |
| you should get an exception.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new configuration setting, |
| <literal>show_error_tips</literal>, defaults to |
| <literal>true</literal>. Sets if tips should be shown in error |
| messages of errors arising during template processing.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Instead of overriding |
| <literal>BeansWrapper.finetuneMethodAppearance</literal> (now |
| deprecated), now you can use |
| <literal>BeansWrapper.setMethodAppearanceFineTuner(MethodAppearanceFineTuner)</literal>, |
| so you don't need to extend the object wrapper class to |
| customize this aspect.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>Configuration.getCoreDirecticeNames()</literal> which |
| returns the names of all directives that are provided by |
| FreeMarker. This can useful for IDE-s.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>template_loader</literal> was added as possible |
| configuration setting <literal>Properties</literal> key.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The standard <literal>CacheStorage</literal> |
| implementations now have a <literal>getSize()</literal> method |
| for monitoring the cache size. |
| <literal>MruCacheStorage</literal> also has |
| <literal>getSoftSize()</literal> and |
| <literal>getStrongSize()</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Various smaller improvements in configuration setting |
| errors messages.</para> |
| </listitem> |
| |
| <listitem> |
| <para>With incompatible improvements 2.3.21 only: Empty ranges |
| return <literal>Constants.EMPTY_SEQUENCE</literal> instead of an |
| empty <literal>SimpleSequence</literal>. This is in theory |
| backward compatible, as the API only promises to give something |
| that implements <literal>TemplateSequenceModel</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>FreeMarker now requires Java version has changed from 1.2 |
| to 1.4.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugs fixed and improvements in overloaded method |
| selection/invocation, but only if you create the |
| <literal>BeansWrapper</literal>/<literal>DefaultObjectWrapper</literal> |
| with constructor parameter |
| <literal>Configuration.VERSION_2_3_21</literal> (or if you are |
| using <literal>Properties</literal> to configure FreeMarker, you |
| can do that like |
| <literal>object_wrapper=BeansWrapper(2.3.21)</literal>), or if |
| you have a <literal>Configuration</literal> with similar |
| <literal>incompatible_improvements</literal> 2.3.21 |
| <emphasis>and</emphasis> you leave the |
| <literal>object_wrapper</literal> setting on its default value. |
| There's a little chance that because of these changes, a |
| different overloaded method will be chosen than before, or even |
| that ambiguity errors will arise where earlier they didn't |
| (although the opposite is far more frequent), hence the fixes |
| aren't automatically activated. But the fix mostly only effect |
| calls that were failing or have chosen then wrong method |
| earlier, so it's recommended to activate it for projects that |
| are still actively developed. This fix includes numerous |
| changes:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Earlier, <literal>null</literal> argument values has |
| only matched overloaded methods where the corresponding |
| parameter had <literal>Object</literal> type, not a subclass |
| of it. That's clearly a bug. Now it considers all overloads |
| where the parameter type is non-primitive, and just like the |
| Java language, it choses the one with the most specific type |
| among them. This is the most important fix, and also the |
| most risky one regarding backward-compatibility. Like if you |
| have <literal>m(Object o)</literal> and <literal>m(String |
| s)</literal> in a Java class, earlier for a |
| <literal>m(null)</literal> call in the template it has |
| chosen <literal>m(Object o)</literal>, but now it will |
| choose <literal>m(String s)</literal> instead (because |
| <literal>String</literal> is also |
| <literal>null</literal>-able and is more specific than |
| <literal>Object</literal>). Furthermore, if you also had |
| <literal>m(File f)</literal> in the same class, now it will |
| cause an ambiguity exception, since the specificity of |
| <literal>File</literal> and <literal>String</literal> can't |
| be compared (same rule as under Java language), while |
| earlier that wasn't a problem as only <literal>m(Object |
| o)</literal> was seen as applicable.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The behavior of numbers with overloaded method |
| selection was heavily reworked:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>If possible, it now always choses the overload |
| where overflow and truncation to integer (like 1.5 to 1) |
| is avoided. Among the methods where no such critical |
| loss occurs, it choses the overload with the least risk |
| of precision loss (unless other conditions with higher |
| priority suggest otherwise). Earlier, the method |
| selection was prone to do choices that led to overflow |
| or precision loss, especially when the parameter was a |
| literal with decimals.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Overloaded method call can now convert to |
| non-primitive numerical types, like a |
| <literal>Byte</literal> or <literal>byte</literal> value |
| is automatically converted to <literal>Integer</literal> |
| if the parameter type is <literal>Integer</literal>. |
| (This has always worked for non-overloaded methods.) |
| Earlier where such conversion was needed, the method |
| wasn't seen seen applicable.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Method selection is now not only based on the type |
| of the wrapped number, but also on its value. For |
| example, a <literal>Long</literal> with value |
| <literal>1</literal> is now seen as compatible with a |
| method with parameter type <literal>int</literal> or |
| <literal>short</literal> or <literal>byte</literal>, as |
| <literal>1</literal> can be stored in those without |
| loss. This is important as unlike in Java language, in |
| FTL you doesn't have strict control over the numerical |
| types (the type of the wrapped number, actually), as FTL |
| has no type declarations. (If multiple compatible |
| methods are available, it will still try to chose the |
| one with the same or bigger numerical type.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Conversion from/to <literal>BigInteger</literal> |
| is now supported.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Method choice ambiguity errors now occur much less |
| often. Ambiguities was and are resolved by selecting the |
| compatible methods then choosing the one with the most |
| specific parameter types among them. The changes are:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>When comparing the overall specificity of two |
| parameter lists: Earlier the parameter list seen as more |
| specific was the one that had some parameters that won |
| in specificity, and if both had such parameters then it |
| was an ambiguity. Now it's enough if a method has more |
| such parameters where it's a better match than the other |
| has, or if the two methods are still equal, if it has |
| the first better matching parameter. This can lead to |
| choices that seem arbitrary (but are still |
| deterministic), but as there's no automated way of |
| discovering method selection ambiguities in templates |
| (unlike in Java source code, where they will be detected |
| during compilation), especially as overloaded selection |
| has to rely on the <emphasis>runtime</emphasis> type of |
| the values which even make proper testing hard, this was |
| considered to be a better compromise than throwing an |
| exception whenever the choice of the method is not |
| obvious. Also note that in fact this mechanism is more |
| complicated than just counting the <quote>winner</quote> |
| parameter positions for each methods, as certain kind of |
| wins are stronger than any number of the others: wins |
| where the other possibility is risking of substantial |
| mantissa precision loss are the strongest (like dropping |
| decimals versus not to), wins where the primitive type |
| wins over the boxed class is the weakest (like |
| <literal>int</literal> versus |
| <literal>Integer</literal>), subclassing wins (like |
| <literal>String</literal> versus |
| <literal>Object</literal>) are between these two.</para> |
| </listitem> |
| |
| <listitem> |
| <para>When comparing the specificity of two parameters |
| types at the same parameter position: The algorithm now |
| considers a primitive type as more specific that its |
| corresponding boxing class (like <literal>int</literal> |
| is considered to be more specific than |
| <literal>Integer</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>There was a bug with overloaded varargs methods of |
| different parameter counts, where sometimes the last |
| parameters of the compared methods was ignored, which is |
| taking away a potential deciding factor and thus can |
| lead to ambiguity error. Whether this happened depends |
| on the order in which the Java reflection API has |
| returned the methods, which is undocumented and known to |
| change at least after some Java updates, breaking the |
| application.</para> |
| </listitem> |
| |
| <listitem> |
| <para>When comparing the specificity of two array types, |
| until now they were seen as equal. Now the component |
| types are compared, and then that with the less specific |
| component type is preferred. For example, among |
| <literal>f(String[])</literal> and |
| <literal>f(Object[])</literal>, the last will always |
| win. This might sounds controversial, but as we can't |
| efficiently tell the common type of all the items in a |
| sequence or <literal>List</literal>, and so we don't |
| know if both arrays are indeed valid targets, we go for |
| the safest choice.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>FTL sequence values (like Java |
| <literal>List</literal>-s or FTL |
| <literal>[<replaceable>x</replaceable>, |
| <replaceable>y</replaceable>, |
| <replaceable>...</replaceable>]</literal> constants) were |
| not seen as applicable to a parameter with array type if |
| there were multiple overloaded methods with the same number |
| of parameters but with different types on the position of |
| the array parameter. That is, if you had |
| <literal>f(String[])</literal> and |
| <literal>f(String)</literal> in Java, then |
| <literal>f(['foo', 'bar'])</literal> in the template |
| reported no compatible overloads. Now it will choose |
| <literal>f(String[])</literal>. Note that if there's also an |
| <literal>f(List)</literal> or even an |
| <literal>f(Collection)</literal>, it will prefer those over |
| arrays. (For consistency, this conversion will work even if |
| the argument is a <literal>List</literal> that come directly |
| from Java (as opposed to be created inside FTL), i.e., when |
| it was wrapped then unwrapped to the original |
| <literal>List</literal> object.) For a multidimensional |
| array parameter type, this conversion works recursively, so |
| you can pass in a sequence-of-sequences as the |
| argument.</para> |
| </listitem> |
| |
| <listitem> |
| <para>FTL sequence values that wrapped a Java array (when |
| FreeMarker was also aware of that via |
| <literal>AdapterTemplateModel</literal> or |
| <literal>WrapperTemplateModel</literal>) were not seen as |
| applicable to a parameter with <literal>List</literal> type |
| if there were multiple overloaded methods with the same |
| number of parameters but with different types on the |
| position of the array parameter. So this is pretty much like |
| the issue described in the previous point, but for array to |
| <literal>List</literal> conversion. The array to |
| <literal>List</literal> conversion will be avoided if |
| possible, but it will be attempted if there's no other |
| alternative. Note that unlike with <literal>List</literal> |
| to array conversions, here FreeMarker can't cope with |
| multi-dimensional lists, that is, an array-of-arrays won't |
| be converted to a |
| <literal>List</literal>-of-<literal>List</literal>-s.</para> |
| </listitem> |
| |
| <listitem> |
| <para>FTL string to Java |
| <literal>char</literal>/<literal>Character</literal> |
| conversion now works for overloaded method parameters; |
| earlier it has worked for non-overloaded methods only. If |
| the string length is 1, it will be seen as compatible with |
| parameters with <literal>char</literal> or |
| <literal>Character</literal> type.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Decreased the chance of choosing the wrong target Java |
| type when unwrapping multi-typed FTL values: When unwrapping |
| a parameter value that implements multiple FTL types (e.g. |
| string and hash) but doesn't implement |
| <literal>AdapterTemplateModel</literal> or |
| <literal>WrapperTemplateModel</literal>, a decision has to |
| be made if to what Java type the value should be unwrapped |
| to (e.g. to <literal>String</literal> or to |
| <literal>Map</literal>). In earlier versions that decision |
| was made based on the most specific common super type of the |
| parameters types of the given parameter position. However, |
| it's quite common that the common super type is too generic, |
| usually <literal>Object</literal>. Now |
| <literal>BeansWrapper</literal> stores <quote>type |
| flags</quote> for each parameter position of overloaded |
| methods, from which it can tell whether a potential target |
| Java type occurs in any of the overloads on the given |
| parameter position.</para> |
| </listitem> |
| |
| <listitem> |
| <para>In many cases, less specific hint class was used for |
| unwrapping than that was possible within the limitations of |
| the applied hint generation algorithm. (The unwrapping hint |
| has influence when there's an ambiguity regarding how to |
| create a Java object form an FTL value. In the vast majority |
| of the cases, a too generic hint has no effect.) (This is a |
| highly technical topic. The way it works is that a single |
| common unwrapping hint class is chosen for a given argument |
| position shared by the overloads that has the same number of |
| parameters, and that hint class has to be as specific as |
| possible while it must fit all those parameter types. The |
| issue with the too generic hints had several instances: (a) |
| When the most specific common class/interface of two |
| same-position parameter types was searched, if there was |
| multiple common classes/interfaces that had no relationship |
| (this is always at most one class and one or more unrelated |
| interfaces), due to the ambiguity it has felt back to using |
| <literal>Object</literal> as the unwrapping hint. Now if |
| there's a non-<literal>Object</literal> class among them in |
| such case, it will be chosen as the hint (i.e., we ignore |
| the common interfaces). Otherwise if only a single interface |
| remains by removing <literal>Cloneable</literal>, |
| <literal>Serializable</literal>, and |
| <literal>Comparable</literal> (in that order), that will be |
| chosen. Only then it falls back to |
| <literal>Object</literal>. (b) The common most specific |
| class of a primitive type and the corresponding boxing class |
| was sometimes <literal>Object</literal> instead of the |
| boxing class. This has depended on Java's internal ordering |
| of the methods, and so were quite unpredictable, like the |
| result could change after upgrading Java under the |
| application. (c) The common superclass of a numerical |
| primitive value and a numerical non-primitive value was |
| always <literal>Object</literal>, now if they are a |
| primitive-boxing class pair, then it's the boxing class, |
| otherwise it's <literal>Number</literal>. (d) If the varags |
| parameter position was not the same in all the overloaded |
| varargs methods, sometimes some varargs arguments where |
| unwrapped with too generic hints. When this happened was |
| unpredictable as it depended on Java's internal method |
| ordering again.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>When unwrapping method call arguments before calling a |
| Java method, if the argument was an |
| <literal>AdapterTemplateModel</literal> and the target |
| parameter type was primitive, |
| <literal>AdapterTemplateModel.getAdaptedObject(Class |
| hint)</literal> has received the primitive type of the |
| target parameter (like <literal>int</literal> instead of |
| <literal>Integer</literal>) as the hint. This did not make |
| sense since <literal>getAdaptedObject</literal> can only |
| return <literal>Object</literal>-s, not primitive values. |
| Yet, <literal>BeansWrapper</literal> has expected the |
| returned value to be of the primitive type, otherwise it has |
| discarded it. Exactly the same problem occurs with |
| <literal>WrapperTemplateModel</literal>. Thus, ultimately, |
| if the target parameter type was primitive and some of these |
| interfaces were implemented, their return value was always |
| discarded and FreeMarker has felt back to other means of |
| unwrapping. Now <literal>BeansWrapper</literal> always |
| passes in and expects the boxing type (like |
| <literal>Integer</literal>) instead of the primitive |
| type.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="http://sourceforge.net/p/freemarker/bugs/373/">373</link>]: |
| These are three bugs actually, which can cause problems when |
| FreeMarker re-loads a template because of a charset override |
| with <literal><#ftl encoding="..."></literal>: First, if |
| the template loader was a <literal>URLTemplateLoader</literal>, |
| when <literal>TemplateLoader.getReader()</literal> was called |
| for the second time, and the <literal>Reader</literal> returned |
| for the first time was already used, it might returned an empty |
| or corrupted template, depending on the backing URL |
| implementation. Secondly, when FreeMarer has decided if a |
| template file has to be re-loaded because its encoding specified |
| with <literal><#ftl encoding="..."></literal> differs from |
| the encoding used for loading the template first, it has used |
| case-sensitive comparison, thus often re-loaded needlessly (like |
| "UTF-8" and "utf-8" mean the same). Now this comparison is |
| case-insensitive. Last not least, when retrying with the second |
| charset, the <literal>TemplateCache</literal> has forgotten to |
| close the first <literal>Reader</literal>, which can be a handle |
| leak.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="http://sourceforge.net/p/freemarker/bugs/411/">411</link>]: |
| Invalid and redundant execution environment names from the OSGi |
| bundle manifest were removed. It looks like this now: |
| <literal>Bundle-RequiredExecutionEnvironment: J2SE-1.5, |
| J2SE-1.4</literal>. That is, we prefer (and compile against) |
| 1.5, but only require 1.4.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="http://sourceforge.net/p/freemarker/bugs/409/">409</link>]: |
| <literal>SimpleHash</literal>'s internal <literal>Map</literal> |
| is concurrently modified on a non-safe way when getting length-1 |
| <literal>String</literal> key that exists but maps to |
| <literal>null</literal>. This operation will accidentally add a |
| <literal>Character</literal> key to the internal map, which is |
| not a thread-safe operation.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="http://sourceforge.net/p/freemarker/bugs/273/">273</link>]: |
| <literal>TemplateLoader</literal>-s that use |
| <literal>java.net.URLConnection</literal>-s should set |
| <literal>URLConnection.useCaches</literal> to |
| <literal>false</literal>, or else it won't detect template |
| caches on certain configurations.</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>URLTemplateLoader</literal> and its |
| subclasses and |
| <literal>WebApplicationTemplateLoader</literal> now has a |
| <literal>setURLConnectionUsesCaches(Boolean)</literal> |
| method. It's recommended to set this property to |
| <literal>false</literal> from its default backward |
| compatible value, <literal>null</literal>. As FreeMarker has |
| its own template cache with its own update delay setting |
| (<literal>template_update_delay</literal>, |
| <literal>Configuration.setTemplateUpdateDelay(int)</literal>), |
| it shouldn't cause performance problems. The |
| <literal>null</literal> value will leave the caching of the |
| <literal>java.net.URLConnection</literal> on its default, |
| which is usually <literal>true</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If <literal>incompatible_improvements</literal> is set |
| to 2.3.21 (or higher) and templates are loaded through |
| <literal>Configuration.getTemplate</literal>, and the |
| <literal>TemplateLoader</literal> in use has |
| <literal>URLConnectionUsesCaches</literal> left on |
| <literal>null</literal>, it will behave as if it was set to |
| <literal>false</literal>. Note that this |
| <literal>incompatible_improvements</literal> trick only |
| works if the template is loaded through |
| <literal>Configuration.getTemplate</literal> (or |
| <literal>TemplateCache</literal>).</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: When changing the properties of |
| <literal>DefaultObjectWrapper</literal> or |
| <literal>BeansWrapper</literal> that influenced class |
| introspection results (like <literal>exposureLevel</literal> or |
| <literal>exposeFields</literal>), the introspection cache wasn't |
| cleared, and thus returned stale information for the classes |
| that were introspected before those properties were changed. Now |
| changing such properties always clears the introspection |
| caches.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: Constants used for empty sequence, empty hash, |
| empty collection and empty iterator weren't |
| <literal>Serializable</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="http://sourceforge.net/p/freemarker/bugs/311/">300</link>]: |
| Logger class availability check was incorrect in that it has |
| checked the availability of logger libraries with the thread |
| context class loader, then later it tried to link to them with |
| the defining class loader of the FreeMarker classes. With some |
| class loader setups (notably under Netbeans sometimes) this led |
| to <literal>ClassDefNotFoundError</literal>-s that made |
| FreeMarker unusable. (The check itself was also not very |
| durable, as it didn't expected <literal>LinakeError</literal>-s, |
| only <literal>ClassNotFoundException</literal>.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <literal>ClassUtil.forName</literal>, used |
| inside FreeMarker everywhere to resolve class names to classes, |
| if the thread context class loader is <literal>null</literal>, |
| no longer tries to load with the bootstrap class loader before |
| loading with the defining class loader of FreeMarker.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="http://sourceforge.net/p/freemarker/bugs/311/">311</link>]: |
| <literal>TemplateBooleanModel.TRUE</literal> and |
| <literal>FALSE</literal> are now serializable</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: Various issues in <literal>Version</literal> |
| class, such as wrong <literal>hashCode</literal>, possible |
| concurrency glitches, and acceptance of some malformed version |
| strings.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed [<link |
| xlink:href="https://sourceforge.net/p/freemarker/bugs/414/">414</link>]: |
| Eclipse debug mode running was suspended during FreeMarker |
| static initialization on the JRebel availability checked if |
| JRebel wasn't available.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Other changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The license has changed from our proprietary BSD-Style |
| license to the well know "Apache License, Version 2.0". |
| Furthermore, the copyright owner has changed from "Visigoth |
| Software Society" (which was founded by Jonathan Revusky) to the |
| three main FreeMarker 2 developers/contributors, "Attila |
| Szegedi, Daniel Dekany, and Jonathan Revusky". See the <link |
| linkend="app_license">new license here</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The required minimum Java version was raised from 1.2 to |
| 1.4. FreeMarker will not work on Java 1.2 or 1.3.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Many smaller improvements and fixes in the Manual and API |
| JavaDocs.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_20"> |
| <title>2.3.20</title> |
| |
| <para>Date of release: 2013-06-27</para> |
| |
| <para>If you are IDE/tools author, <link |
| linkend="version_2_3_20_ide">note these changes</link>.</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Error message quality improvements:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Many error messages are now more helpful, especially |
| for users who are not experienced with FreeMarker. For |
| example, some of the most common user mistakes are |
| recognized and tips are shown to fix them, reducing support |
| costs or the time employees spend to figure them out.</para> |
| </listitem> |
| |
| <listitem> |
| <para>It's now ensured that the error location in the |
| template is included in the message returned by |
| <literal>TemplateException.getMessage()</literal>. The stack |
| trace always showed this information anyway, but some users |
| only see the <quote>message</quote>, not the stack trace, |
| and that often didn't contained the location.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The template language part of the stack trace is now |
| more detailed, and easier to understand. This is especially |
| helpful in applications that use a complex library of macros |
| and functions.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Several smaller bugs were fixed that made the error |
| information wrong or lacking.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The layout of the error messages is now more |
| consistent, and generally easier to read.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Changes regarding boolean to string conversions and |
| formatting:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>?c</literal> (computer-language formatting) |
| now works with booleans too, always giving |
| <literal>"true"</literal> or <literal>"false"</literal> |
| regardless of the <literal>boolean_format</literal>. This |
| way it's safe for generating JavaScript in a context where |
| human-readable text is also rendered.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If the <literal>boolean_format</literal> setting is |
| set to anything but the default |
| <literal>"true,false"</literal> value, boolean values will |
| be automatically converted to string where a string value is |
| expected by the template language, instead of giving an |
| error. This helps you spare |
| those<literal>?string</literal>-s after boolean values. This |
| is the same logic as with numbers and dates, which were |
| always automatically converted to string, according the |
| corresponding format setting. Except, the provided default |
| boolean format is useless for automatic conversion (but it's |
| still there for <literal>?string</literal>, for backward |
| compatibility), hence it must be set manually. (We certainly |
| couldn't come up with a sensible default anyway, as for |
| booleans it depends too much on the application, not to |
| mention the localisation issues.)</para> |
| |
| <para>Exactly like with numbers and dates, automatic |
| conversion doesn't happen in these cases:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Comparisons, i.e., <literal>someBoolean == |
| 'true'</literal> is still an error</para> |
| </listitem> |
| |
| <listitem> |
| <para>Method calls where the declared type of the |
| parameter is <literal>String</literal> but the actual |
| value is a boolean; still an error</para> |
| </listitem> |
| |
| <listitem> |
| <para>When the boolean value is used as key in |
| <literal><replaceable>expr</replaceable>[<replaceable>key</replaceable>]</literal>, |
| it's still an error (there was no automatic conversion |
| there for other types either, as numerical and string |
| keys have different meaning)</para> |
| </listitem> |
| |
| <listitem> |
| <para>The opposite direction, i.e., string to boolean |
| conversion; won't happen</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>New built-ins for numbers: <link |
| linkend="ref_builtin_abs"><literal>abs</literal></link>, <link |
| linkend="ref_builtin_is_nan"><literal>is_nan</literal></link>, |
| <link |
| linkend="ref_builtin_is_infinite"><literal>is_infinite</literal></link>. |
| Like <literal>n?abs</literal> will give the absolute value of |
| <literal>n</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-in for sequences: <link |
| linkend="ref_builtin_join"><literal>join</literal></link>. Like |
| <literal>[1, 2, 3]?join(", ")</literal> will give the string |
| <literal>"1, 2, 3"</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If you set the |
| <literal>incompatible_improvements</literal> setting (see <link |
| xlink:href="https://freemarker.apache.org/docs/api/freemarker/template/Configuration.html#setIncompatibleImprovements%28freemarker.core.Version%29">here</link>) |
| to <literal>2.3.20</literal> or higher, <literal>?html</literal> |
| will escape apostrophe-quotes just like |
| <literal>?xhtml</literal> does. Utilizing this is highly |
| recommended, because otherwise if interpolations are used inside |
| attribute values that use apostrophe-quotation (<literal><foo |
| bar='${val}'></literal>) instead of plain quotation mark |
| (<literal><foo bar="${val}"></literal>), they might |
| produce HTML/XML that's not well-formed. Note that |
| <literal>?html</literal> didn't do this because long ago there |
| was no cross-browser way of doing this, but it's not a real |
| concern anymore. Also note that this will be the default |
| behavior starting from 2.4.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fix [<link |
| xlink:href="https://sourceforge.net/p/freemarker/bugs/390/">390</link>] |
| (and other improvements): <literal>?js_string</literal> and |
| <literal>?json_string</literal> didn't escape the |
| <literal>u2028</literal>-<literal>u2029</literal> line |
| terminators (problem for JavaScript) and the |
| <literal>u007F</literal>-<literal>u009F</literal> control |
| characters (maybe a problem in JSON, depending on |
| implementation). Furthermore, the escaping of |
| <literal>\</literal>, <literal><</literal>, and |
| <literal>></literal> become safer in that now they are |
| escaped whenever it can't be guaranteed that they won't be part |
| of <literal><!</literal>, <literal>]]></literal> or |
| <literal></</literal>. Earlier they were only escaped when it |
| was known that they are part of these patterns, thus it was |
| possible to assemble these patterns from two adjacent |
| interpolations. Additionally, from now on |
| <literal><?</literal> and <literal>--></literal> also |
| count as dangerous patterns, and will trigger |
| <literal><</literal> and <literal>></literal> |
| escaping.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: The following string built-ins didn't coerce |
| the numerical, date (and now the boolean) left-values to string, |
| instead they threw a type error: contains, |
| <literal>index_of</literal>, <literal>last_index_of</literal>, |
| <literal>left_pad</literal>, <literal>right_pad</literal>, |
| <literal>matches</literal>, <literal>replace</literal>, |
| <literal>split</literal>, <literal>new</literal>. The other |
| string built-ins already did this conversion for a long time; |
| this was an accidental inconsistency.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: With the default arithmetic engine, it's now |
| supported to compare infinite (positive or negative) with 0, to |
| decide its sign.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>BeansWrapper</literal> introspection cache |
| improvements:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added public API to <literal>BeansWrapper</literal> |
| for clearing the class cache: |
| <literal>clearClassIntrospecitonCache()</literal>, |
| <literal>removeFromClassIntrospectionCache(Class)</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Significantly improved multi-core performance:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Uses <literal>ConcurrentHashMap</literal> when |
| running on Java 5 or later.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The cache won't block readers while introspecting |
| a class after a cache miss</para> |
| </listitem> |
| |
| <listitem> |
| <para>If multiple threads need to introspect the same |
| class that's not in the cache yet, only one of them will |
| do it, the others will wait for its results.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fix [<link |
| xlink:href="https://sourceforge.net/p/freemarker/bugs/361/">361</link>]: |
| There was a small chance of deadlock when class-reloading |
| was detected. Locking was redesigned to prevent such |
| oversights in the future.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The internal package-visible |
| <literal>freemarker.ext.beans</literal> API was slightly |
| changed as the result of internal cleanup. Nobody but the |
| FreeMarker developers should define classes in that package, |
| so it shouldn't break anything. But if somebody did some |
| in-house hacks there, re-compile to see if it still |
| works.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Nameless templates (those directly created with |
| <literal>new Template(null, |
| <replaceable>...</replaceable>)</literal> instead of loaded |
| through <literal>Configuration</literal>) couldn't include or |
| import other templates, and thrown a |
| <literal>NullPointerException</literal> when they tried to. Now |
| they resolve relative paths as if they were in the template root |
| directory.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fix: Regular expression built-ins and some logger |
| libraries (most importantly Log4J) were unavailable on the |
| Google App Engine platform. This fix is only present in the |
| GAE-compatible build, 2.3.20-gae.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new method to <literal>Configuration</literal>: |
| <literal>CacheStorage getCacheStorage()</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new methods to <literal>Environment</literal> to |
| make comparisons among <literal>TemplateModel</literal>-s |
| according the rules of the template language operators: |
| <literal>applyEqualsOperator</literal>, |
| <literal>applyEqualsOperatorLenient</literal>, |
| <literal>applyLessThanOperator</literal>, |
| <literal>applyLessThanOrEqualsOperator</literal>, |
| <literal>applyGreaterThanOperator</literal>, |
| <literal>applyWithGreaterThanOrEqualsOperator</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new method, |
| <literal>Environment.isInAttemptBlock()</literal> to check if we |
| are within an <literal>#attempt</literal> block. This can be |
| useful for <literal>TemplateExceptionHandler</literal>-s, as |
| then they don't need to print the error to the output since |
| <literal>#attempt</literal> will roll it back anyway. This is |
| already utilized by the built-in |
| <literal>TemplateExceptionHandler</literal>-s |
| (<literal>DEBUG_HANDLER</literal> and |
| <literal>HTML_DEBUG_HANDLER</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added convenience constructor <literal>Template(String |
| name, String sourceCode, Configuration cfg)</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>TemplateException</literal>-s and |
| <literal>TemplateModelExcepton</literal>-s now can have |
| <literal>Throwable</literal> cause, not just |
| <literal>Exception</literal> (it was an old oversight that |
| somehow wasn't fixed so far).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Parsing error messages under the JBoss Tools FreeMarker |
| IDE now doesn't contain the usual location line, so that the |
| actual error description is immediately visible in the Eclipse |
| <quote>Problems</quote> view. (It's a <quote>hack</quote> in |
| FreeMarler itself; it tries to detect if it runs under the |
| plugin and then changes its behavior.)</para> |
| </listitem> |
| |
| <listitem xml:id="version_2_3_20_ide"> |
| <para>Mostly concerning tool (like IDE plugin) authors:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The error message formats (what |
| <literal>Throwable.getMessage()</literal> returns) were |
| heavily changed for <literal>TemplateException</literal>-s, |
| and somewhat for <literal>ParseException</literal>-s. It's |
| unlikely that anybody depends on these, but if you tried to |
| parse these messages, be aware of this.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Fixed bug where <literal>ParseException</literal> has |
| contained 0 as line and column number for lexical errors. |
| Now it contains the correct information.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>ParseException.getEditorMessage()</literal>: As in |
| IDE-s the error markers show the error location to the user |
| already, the location should not be repeated in the error |
| message. So in IDE-s you should use this method instead of |
| <literal>getMessage()</literal>. (Under JBoss Tools: |
| FreeMarker now <emphasis>tries</emphasis> to detect that it |
| runs under the plugin, and then it already does this, except |
| that it still shows the column number as that's missing from |
| the error marker location.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>ParseException.getTemplateName()</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>Configuration.getSupportedBuiltInNames()</literal>. |
| As new built-ins |
| (<literal><replaceable>expr</replaceable>?<replaceable>builtin_name</replaceable></literal>) |
| are very often added to new FreeMarker versions, |
| auto-completion or syntax highlighting should use this set |
| instead of a fixed set of a names.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The format returned by |
| <literal>TemplateElement.getDescription()</literal> was |
| heavily changed. It's what FTL stack traces and maybe some |
| outline views (tree-views) show. It was always for human |
| reading (and till now was too inconsistent for anything |
| else), so it's unlikely that this breaks anything.</para> |
| </listitem> |
| |
| <listitem> |
| <para>There were some smaller changes in |
| <literal>freemarker.debug</literal>, and it's expected that |
| there will be more, so it was marked as experimental. As far |
| as we know, nobody used it, so it shouldn't break |
| anything.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>In <emphasis>experimental status only</emphasis>, but |
| <literal>freemarker.jar</literal> is now an OSGi bundle (see |
| <literal>freemarker.jar/META-INF/MANIFEST.MF</literal>). |
| Depending on user feedback, the bundle description may change in |
| the future. So please give feedback, especially if you are an |
| OSGi expert!</para> |
| </listitem> |
| |
| <listitem> |
| <para>Improved the HTML generated by |
| <literal>HTML_DEBUG_HANDLER</literal> (the |
| red-on-yellow-background error message). Most importantly, now |
| it will word-wrap. Other changes are minor, like now it can |
| break out of CDATA sections, or now it has less intense |
| colors.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New <literal>Template</literal> method, |
| <literal>getActualTagSyntax()</literal>: Tells if the template |
| is using traditional or square-bracket syntax. As the syntax can |
| be overridden in the template, also it's possibly decided by |
| auto-detection, it wasn't trivial to it tell till now.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added some utility methods that are useful for generating |
| error messages in custom directives: |
| <literal>ClassUtil.getFTLTypeDescription(TemplateModel)</literal>, |
| <literal>getShortClassName</literal>, |
| <literal>getShortClassNameOfObject</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fix [<link |
| xlink:href="https://sourceforge.net/p/freemarker/bugs/364/">364</link>]: |
| <literal>freemarker.template.EmptyMap</literal> (which is passed |
| to <literal>TemplateDirectiveModel</literal>-s if there are no |
| parameters) now allows <literal>remove(key)</literal>, |
| <literal>clear()</literal> and |
| <literal>putAll(anyEmptyMap)</literal> as these do nothing |
| anyway.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fix [<link |
| xlink:href="https://sourceforge.net/p/freemarker/bugs/375/">375</link>]: |
| <literal>NullPointerException</literal> on IBM J9 VM (not on the |
| Sun/Oracle implementation) in <literal>BeansWrapper</literal> |
| when the Java implementation legally returns |
| <literal>null</literal> for some <literal>BeanInfo</literal> |
| getters.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fix: Cloning a <literal>Configuration</literal> didn't |
| deep-clone the data structures storing the |
| <literal>auto_imports</literal> and |
| <literal>auto_includes</literal> settings, hence possibly |
| leading to aliasing problems.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fix [<link |
| xlink:href="https://sourceforge.net/p/freemarker/bugs/377/">377</link>]: |
| After a failed method call the exception handler could fail in |
| the rare occasion when |
| <literal>targetObject.toString()</literal> fails, raising a |
| runtime exception that not even the <literal>attempt</literal> |
| directive will catch.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fix [<link |
| xlink:href="https://sourceforge.net/p/freemarker/bugs/391/">391</link>]: |
| If a template name has contained <literal>*</literal> that was |
| not the only character in the path step, it threw |
| <literal>NegativeArraySizeException</literal> instead of |
| <literal>FileNotFoundException</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>With the default arithmetic engine, performance |
| optimizations of comparison operations when some of the numbers |
| is 0, and when the sign of the numbers differ.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Some smaller fixes in |
| <literal>TemplateElement.getCanonicalForm()</literal>, also some |
| quality improvements there.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixes in <literal>classic_compatible</literal> mode |
| (this mode is to help migrating from FreeMarker 1), thanks to |
| Information Mosaic:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>When a macro was called with a |
| <literal>null</literal>/missing parameter value, it has |
| caused error like in FreeMarker 2.3</para> |
| </listitem> |
| |
| <listitem> |
| <para>When a hash literal contained reference to a |
| <literal>null</literal>/missing variable, like in <literal>{ |
| 'a': missingVar }</literal>, it has caused an error like in |
| 2.3</para> |
| </listitem> |
| |
| <listitem> |
| <para>When a sequence literal contained reference to a |
| <literal>null</literal>/missing variable, like in |
| <literal>[1, missingVar]</literal>, it has caused an error |
| like in 2.3</para> |
| </listitem> |
| |
| <listitem> |
| <para>When a the left-side of the <literal>.</literal> (dot) |
| or <literal>[<replaceable>key</replaceable>]</literal> |
| operator was <literal>null</literal> or missing variable, |
| like in <literal>missingVar.subVar</literal>, it has caused |
| an error like in 2.3</para> |
| </listitem> |
| |
| <listitem> |
| <para>When <literal>BeanModel</literal>-s are tried to be |
| treated as strings, for most subclasses it has failed with |
| type error, like in 2.3. In FreeMarker 1 all |
| <literal>BeanModel</literal>-s were |
| <literal>TemplateScalarModel</literal>-s, so it should |
| succeed. The fix for this only works where FreeMarker |
| <emphasis>coerces</emphasis> to string (string built-ins on |
| the left-side and concatenation (<literal>+</literal>) and |
| interpolation |
| (<literal>${<replaceable>...</replaceable>}</literal>) do |
| that), otherwise unfortunately it will still fail.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>classic_compatible</literal> setting now |
| accepts value <literal>2</literal> along |
| <literal>true</literal> (alias <literal>1</literal>) and |
| <literal>false</literal> (alias <literal>0</literal>). |
| <literal>2</literal> means <literal>true</literal> but with |
| emulating bugs in early 2.x classic-compatibility mode. |
| Currently this only affects how booleans are converted to |
| string; with <literal>1</literal> it's always |
| <literal>"true"</literal>/<literal>""</literal>, but with |
| <literal>2</literal> it's <literal>"true"/"false"</literal> |
| for values wrapped by <literal>BeansWrapper</literal> as |
| then <literal>Boolean.toString()</literal> prevails. Note |
| that |
| <literal><replaceable>someBoolean</replaceable>?string</literal> |
| will always consistently format the boolean according the |
| <literal>boolean_format</literal> setting, just like in |
| FreeMarker 2.3.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fix [<link |
| xlink:href="https://sourceforge.net/p/freemarker/bugs/394/">394</link>]: |
| When trying to access the optional Jython (or W3C DOM) classes |
| has failed in <literal>DefaultObjectWrapper</literal> with an |
| <literal>Error</literal>, rather than with an |
| <literal>Exception</literal>, loading the |
| <literal>DefaultObjectWrapper</literal> class itself has failed, |
| instead of the Jython (or W3C DOM) support being disabled. From |
| now in, it will survive any kind of <literal>Throwable</literal> |
| there, and if the <literal>Throwable</literal> is not an |
| <literal>ClassNotFoundException</literal>, it will also log the |
| <literal>Throwable</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Improved the performance of |
| <literal>(thisVarIsMissing.foo)!default</literal> and similar |
| <emphasis>parenthetical</emphasis> existence operators and |
| existence built-ins in the case when the |
| <literal>null</literal>/missing variable is not the last step |
| inside the parenthesis. In that case it's about 30 times faster |
| now, measured on Java 6. In other cases (when all variables |
| exists, or the the last step is missing) the performance is |
| about the same (relatively fast) as before.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added interface |
| <literal>freemarker.cache.CacheStorageWithGetSize</literal> |
| which allows querying the current number of cache entries in a |
| <literal>CacheStorage</literal> that implements it. It's |
| implemented by all out-of-the-box |
| <literal>CacheStorage</literal> implementations. Also added |
| <literal>getStrongSize()</literal> and |
| <literal>getSoftSize()</literal> to |
| <literal>MRUCacheStorage</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Version and build information changes:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The form of the nightly build version numbers has |
| changed to be Maven/JSR 277 compliant. What earlier was |
| <literal>2.3.19mod</literal> is now something like |
| <literal>2.3.20-nightly_20130605T130506Z</literal> (note how |
| the last points to the target release version instead of the |
| last release version).</para> |
| </listitem> |
| |
| <listitem> |
| <para>The form of the Release Candidate and Preview version |
| numbers where changed to be Maven/JSP 277 compliant: |
| <literal>2.4pre2</literal> is now |
| <literal>2.4.0-pre02</literal>, <literal>2.4rc1</literal> is |
| now <literal>2.4.0-rc01</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new static method to |
| <literal>Configuration</literal> to query build date: |
| <literal>getBuildDate()</literal>. This is also printed by |
| the main command line class.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Various internal code cleanups.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Other changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Many JavaDoc improvements, mostly in the documentation of |
| the basic (most frequently used) classes.</para> |
| </listitem> |
| |
| <listitem> |
| <para>FreeMarker source code has moved to GitHub (<link |
| xlink:href="???">https://github.com/freemarker/freemarker</link>), |
| other project resources has remained on sourceforge.net.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Project structure cleanup, Ivy-based build script.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_19"> |
| <title>2.3.19</title> |
| |
| <para>Date of release: 2012-02-29</para> |
| |
| <para>Don't miss the <link linkend="v2319secfix">security related |
| changes</link>, they may affect your application!</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para><emphasis>Attention</emphasis>: The output of <link |
| linkend="ref_builtin_date_iso">ISO 8601 date/time formatting |
| built-ins</link>, introduced in 2.3.17, was slightly changed. |
| From now on, the time zone offset, when it's displayed and it |
| isn't <literal>Z</literal>, always includes the minutes. For |
| example, <literal>15:30:15+02</literal> becomes to |
| <literal>15:30:15+02:00</literal> in the template output. Both |
| formats are valid according to ISO 8601 (so anything that |
| expects ISO 8601 date/times should continue working), but only |
| the last format complies with the XML Schema date/time formats, |
| hence this change.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-in for escaping inside JSON string literals: |
| <link |
| linkend="ref_builtin_json_string"><literal>json_string</literal></link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: Wrong <literal>#</literal> tags were printed as |
| static text instead of causing parsing error if there was no |
| correct <literal>#</literal> tag earlier in the same template. |
| Since fixing this would not be 100% backward compatible, the old |
| behavior has remained, unless you set the |
| <literal>incompatible_enhancements</literal> setting |
| (<literal>Configuration.setIncompatibleEnhancements(String)</literal>) |
| to <literal>"2.3.19"</literal> or higher.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para xml:id="v2319secfix"><emphasis>Attention</emphasis>: This |
| release contains two important security workarounds that |
| unavoidably make it obvious how some applications can be |
| exploited. <emphasis>FreeMarker can't solve these issues on all |
| configurations, so please read the details instead of just |
| updating FreeMarker!</emphasis> Also, these changes are not 100% |
| backward compatible in theory, however it's not probable that |
| they will break anything. The two changes are:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The character with character code 0 |
| (<literal>\u0000</literal>) is not allowed in template paths |
| anymore. When a path contains it, FreeMarker behaves as if |
| the template was not found.</para> |
| |
| <para>This is to fix the security problem where a template |
| path like <literal>"secret.txt\u0000.ftl"</literal> is used |
| to bypass extension filtering in an application. FreeMarker |
| itself doesn't care about the extension, but some |
| applications decide based on the extension if they will |
| delegate a path to FreeMarker. When they do with such a |
| path, the C/C++ implementation behind the storage mechanism |
| may sees the path as <literal>"secret.txt"</literal> as the |
| 0 terminates the string in C/C++, and thus load a non-FTL |
| file as a template, returning the file contents to the |
| attacker.</para> |
| |
| <para>Note that some HTTP servers, notably Tomcat and the |
| Apache HTTP Server blocks URL-s where the URL contains 0 |
| (<literal>%00</literal>) outside the query string, thus this |
| wasn't exploitable there through such Web URL-s. Some other |
| HTTP servers however, like Jetty, doesn't block such |
| URL-s.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>ClassTemplateLoader</literal>, when it's |
| created with base path <literal>"/"</literal> (like with |
| <literal>new ClassTemplateLoader(someClass, "/")</literal>), |
| will not allow template paths that contain colon earlier |
| than any <literal>/</literal>, and will act like if the |
| template was not found in such case.</para> |
| |
| <para>This is to fix the security problem where a template |
| path like <literal>"file:/etc/secret"</literal> or |
| <literal>"http://example.com/malware.ftl"</literal> is |
| interpreted as a full URL by a |
| <literal>java.net.URLClassLoader</literal> in the |
| class-loader hierarchy, and thus allow loading files from |
| these URL-s as templates. This is a quirk (or bug) of |
| <literal>java.net.URLClassLoader</literal>, thus this |
| problem only exists on systems that use such |
| class-loaders.</para> |
| |
| <para>Beware, some frameworks use their own |
| <literal>TemplateLoader</literal> implementations, and if |
| those are vulnerable, they will remain so after updating |
| FreeMarker too! Note that this exploit only works if the |
| class-loader hierarchy contains an |
| <literal>URLClassLoader</literal> and the class-loader is |
| used to load templates without adding any prefix before the |
| template path (other than <literal>"/"</literal>).</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>These security issues mostly only affect applications |
| <emphasis>where the user (the visitor) can supply arbitrary |
| template paths to the application</emphasis>. This is not the |
| case with properly built MVC applications, as there only the MVC |
| Controller can be addressed directly, and it's the Controller |
| that specifies the template paths. But legacy MVC applications |
| based on <link linkend="pgui_misc_servlet_model2">JSP |
| Model-2</link> often expose the MVC Views as public URL-s ending |
| with <literal>.ftl</literal>, thus allowing the user to give |
| arbitrary paths to FreeMarker. Such applications should be |
| secured with a <literal>security-constratint</literal> in |
| <literal>web.xml</literal> as shown in the <link |
| linkend="pgui_misc_servlet_model2">related Manual |
| section</link>. This should be done regardless of the current |
| security fixes.</para> |
| |
| <para>In general, you should not allow users to specify |
| arbitrary template paths, or if you do allow that, you should be |
| extra careful with the <literal>TemplateLoader</literal> |
| used.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>Configuration</literal> has new methods: |
| <literal>removeTemplateFromCache(...)</literal>. This will |
| remove the given template for the given locale from the cache, |
| so it will be re-loaded regardless of the template update delay |
| when it's next time requested.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>BeansWrapper</literal> ignores setter methods |
| from now when introspecting classes. They weren't used anyway, |
| so they unnecessarily caused |
| "<literal>java.beans.IntrospectionException</literal>: type |
| mismatch between read and write methods" errors.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>TemplateClassResolver.SAFER_RESOLVER</literal> |
| now disallows creating |
| <literal>freemarker.template.utility.JythonRuntime</literal> and |
| <literal>freemarker.template.utility.Execute</literal>. This |
| change affects the behavior of the <link |
| linkend="ref_builtin_new"><literal>new</literal> built-in</link> |
| if FreeMarker was configured to use |
| <literal>SAFER_RESOLVER</literal>, which is not the default |
| until 2.4 and is hence improbable.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: Calling varargs methods now indeed works. |
| (Earlier it only worked for overloaded methods.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed <link |
| xlink:href="https://sourceforge.net/tracker/index.php?func=detail&aid=1837697&group_id=794&atid=100794">[1837697]</link> |
| <link |
| xlink:href="https://sourceforge.net/tracker/index.php?func=detail&aid=2831150&group_id=794&atid=100794">[2831150]</link> |
| <link |
| xlink:href="https://sourceforge.net/tracker/index.php?func=detail&aid=3039096&group_id=794&atid=100794">[3039096]</link> |
| <link |
| xlink:href="https://sourceforge.net/tracker/index.php?func=detail&aid=3165425&group_id=794&atid=100794">[3165425]</link>: |
| Jython support now works with Jython 2.2 and 2.5.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed <link |
| xlink:href="https://sourceforge.net/tracker/index.php?func=detail&aid=3325103&group_id=794&atid=100794">[3325103]</link>: |
| <literal>TemplateException</literal>-s and |
| <literal>ParseException</literal>-s are now serializable.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_18"> |
| <title>2.3.18</title> |
| |
| <para>Date of release: 2011-05-21</para> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bugfix <link |
| xlink:href="https://sourceforge.net/tracker/?func=detail&aid=3304568&group_id=794&atid=100794">[3304568]</link>: |
| 2.3.17 didn't find TLD-s in <literal>WEB-INF\lib\*.jar</literal> |
| unless they were explicitly pointed in the |
| <literal>web.xml</literal> with a <literal>taglib</literal> |
| element. This bug was introduced in 2.3.17.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Other changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added <literal>LICENSE.txt</literal> and |
| <literal>NOTICE.txt</literal> to |
| <literal>freemarker.jar</literal> under |
| <literal>META-INF</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_17"> |
| <title>2.3.17</title> |
| |
| <para>Date of release: 2011-05-17</para> |
| |
| <para>It's possibly urgent to update to this version because of a |
| <link linkend="v2317secfix">security fix</link>!</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>?seq_index_of</literal> and |
| <literal>?seq_last_index_of</literal> now works on collections |
| (<literal>freemarker.template.TemplateCollectionModel</literal>-s) |
| too, not only on sequences |
| (<literal>freemarker.template.TemplateSequenceModel</literal>-s).</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>?long</literal> now works for date, date-time or |
| time values, and returns the milliseconds since the epoch (as |
| <literal>java.util.Date.getTime()</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>To convert numbers (usually Java |
| <literal>long</literal>-s) to date or date-time and time values, |
| <literal>?number_to_date</literal>, |
| <literal>?number_to_time</literal>, |
| <literal>?number_to_datetime</literal> was added. <link |
| linkend="ref_builtin_numToDate">See more here...</link> |
| (Unfortunately, <literal>?date</literal> and like can't be |
| extended to support this due to backward compatibility |
| issues.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-ins to format numbers with ISO 8601 "extended" |
| format regardless of the current date/time formatting settings, |
| and even regardless of the current time zone setting. For |
| example <literal>${myTimeStamp?iso_utc}</literal> will print |
| something like <literal>2010-05-16T23:05:45Z</literal>. <link |
| linkend="ref_builtin_date_iso">See more here...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>New <link linkend="ref_specvar">special variable</link>, |
| <literal>now</literal>. This returns the current date-time. |
| Usage examples: "<literal>Page generated: ${.now}</literal>", |
| "<literal>Today is ${.now?date}</literal>", "<literal>The |
| current time is ${.now?time}</literal>".</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>?sort</literal> and <literal>?sort_by</literal> |
| now supports sorting boolean values.</para> |
| </listitem> |
| |
| <listitem> |
| <para>When using unsupported or unknown <link |
| linkend="ref_builtin_string_flags">string built-in flags</link>, |
| FreeMarker will now <link linkend="pgui_misc_logging">log</link> |
| warnings (maximum 25 times per class-loader, to prevent flooding |
| the log). It's certain that starting from FreeMarker 2.4 these |
| will count as errors.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed <link |
| xlink:href="http://sourceforge.net/tracker/?func=detail&atid=100794&aid=3047201&group_id=794">[3047201]</link>: |
| Using regular expressions (like with <literal>?match</literal>) |
| could cause lockup in multi-threaded environment, also memory |
| leakage when using dynamically generated regular |
| expressions.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <literal>?seq_contains</literal>, |
| <literal>?seq_index_of</literal> and |
| <literal>?seq_last_index_of</literal> has failed with |
| non-<literal>java.util.List</literal> |
| <literal>java.util.Collection</literal>-s that are wrapped with |
| pure <literal>BeansWrapper</literal> (not the |
| <literal>DefaultObjectWrapper</literal>) as |
| <literal>TemplateSequenceModel</literal>. (See also: |
| <literal>getSupportsIndexedAccess()</literal> below)</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para xml:id="v2317secfix"><emphasis>Security fix</emphasis>: |
| Using carefully crafted template names (template paths) that |
| contain code point 0 (<literal>'\u0000'</literal>), it was |
| possible to load files from outside the template root directory |
| like if they were FreeMarker templates. The root of the problem |
| is that the underlying native C/C++ part (which belongs to the |
| Java platform or to the OS) interprets the 0 as the end of the |
| string, while Java (and hence FreeMarker and the Servlet |
| container) doesn't. Thus a path that looked safe for FreeMarker |
| become unsafe on the lower level. The problem is present with |
| all ways of loading templates by name |
| (<literal>Configuration.getTemplate(<replaceable>...</replaceable>)</literal>, |
| <literal><#include |
| <replaceable>...</replaceable>></literal>, |
| <literal><#import |
| <replaceable>...</replaceable>></literal>).</para> |
| |
| <para>You are not affected if you don't allow users to upload |
| templates and also at least one of these stands:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>In your system users can't provide arbitrary strings |
| as template names (template paths). For example, if users |
| are only allowed to visit the URL-s that belong to the MVC |
| Controller (like they can't visit <literal>*.ftl</literal>) |
| then they can't suggest arbitrary template names.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The template names are part of the path in the Web |
| page URL, and your webserver or Servlet container disallows |
| URL-s that contain <literal>%00</literal>, or terminate the |
| URL at it before passing it to the servlets.</para> |
| </listitem> |
| |
| <listitem> |
| <para>You are using <literal>FileTemplateLoader</literal> |
| and linking is not allowed in it (by default it isn't |
| allowed).</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>FreeMarker now can log its messages directly using SLF4J |
| or Apache Commons Logging. However, it will not use these logger |
| libraries automatically, until 2.4; <link |
| linkend="pgui_misc_logging">see more here...</link> But it's |
| recommended to switch to SLF4J now.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New setting: <literal>"auto_flush"</literal>, |
| <literal>Configurable.setAutoFlush(boolean)</literal>. Sets |
| whether the output <literal>Writer</literal> is automatically |
| flushed at the end of <literal>Template.process(Object, |
| Writer)</literal> (and its overloads). The default is |
| <literal>true</literal>, which corresponds to the earlier |
| behavior. Using <literal>false</literal> is needed for example |
| when a Web page is composed from several boxes (like portlets, |
| GUI panels, etc.) that aren't inserted with |
| <literal>#include</literal> (or with similar directives) into a |
| master FreeMarker template, rather they are all processed with a |
| separate |
| <literal>Template.process(<replaceable>...</replaceable>)</literal> |
| call. In a such scenario the automatic flushes would commit the |
| HTTP response after each box, hence interfering with full-page |
| buffering, and also possibly decreasing performance with too |
| frequent and too early response buffer flushes.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added new setting: |
| <literal>Configuration.setNewBuiltinClassResolver(TemplateClassResolver)</literal>, |
| or <literal>new_builtin_class_resolver</literal> property. This |
| allows you to specify how the <link |
| linkend="ref_builtin_new"><literal>new</literal> built-in</link> |
| (like in <literal>"com.example.SomeClass"?new()</literal>) |
| resolves classes and which classes are accessible at all. If you |
| are allowing not-so-much-trusted users to upload templates, you |
| should be definitely interested; see the Java API docs of |
| <literal>freemarker.core.Configurable.setSetting</literal> and |
| <literal>freemareker.template.Configuration.setNewBuiltinClassResolver</literal>. |
| Otherwise it's still recommended to set this to |
| <literal>TemplateClassResolver.SAFER_RESOLVER</literal> (or |
| <literal>safer</literal> if you are using properties), although |
| that's not 100% backward compatible (see Java API docs) .</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added |
| <literal>freemarker.cache.NullCacheStorage</literal>: Setting |
| this as the cache storage in <literal>Configuration</literal> |
| disables caching.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added <literal>getSupportsIndexedAccess()</literal> to |
| <literal>freemarker.ext.beans.CollectionModel</literal>, so one |
| can check if <literal>TemplateSequenceModel.get(int)</literal> |
| will work with a particular <literal>CollectionModel</literal> |
| instance or not.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed <link |
| xlink:href="http://sourceforge.net/tracker/?func=detail&aid=2992265&group_id=794&atid=100794">[2992265]</link>: |
| JSP <literal>FreeMarkerPageContext.include</literal> behaved |
| incorrectly.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: When using FreeMarker's JSP support with JSP |
| tags that use |
| <literal>javax.servlet.jsp.PageContext.pushBody</literal> (like |
| some Stripes tags), <literal>"ArrayIndexOutOfBoundsException: |
| -1"</literal> occurred inside |
| <literal>freemarker.ext.jsp.FreeMarkerPageContext.popWriter</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed <link |
| xlink:href="http://sourceforge.net/tracker/?func=detail&atid=100794&aid=3033015&group_id=794">[3033015]</link>: |
| <literal>AllHttpScopesHashModel</literal> used |
| <literal>WrappingTemplateModel.getDefaultObjectWrapper()</literal> |
| for wrapping variables in the page scope, while used the |
| user-specified <literal>ObjectWrapper</literal> for all other |
| scopes (request, session, etc.). Now it uses the user-specified |
| wrapper in the page scope as well.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed <link |
| xlink:href="https://sourceforge.net/tracker/?func=detail&aid=3128073&group_id=794&atid=100794">[3128073]</link>: |
| <literal>HashAdapther.containsKey(...)</literal> returned |
| <literal>true</literal> for a key that doesn't exist when |
| unwrapping the key has failed. As a side effect of the fix, |
| <literal>BeansWrapper.CAN_NOT_UNWRAP</literal> is now private; |
| earlier it was public by mistake.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Big fixed <link |
| xlink:href="http://sourceforge.net/tracker/?func=detail&aid=3151085&group_id=794&atid=100794">[3151085]</link>: |
| <literal>freemarker.jsp.TaglibFactory</literal> didn't locate |
| tld files properly. This fix gives better compliance with JSP |
| specification for resolving and loading tld files.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: Unwrapping <literal>null</literal> with a |
| <literal>BeansWrapper</literal> that had a custom null-model |
| didn't result in <literal>null</literal>. Now both unwrapping |
| <literal>null</literal> and the custom null-model gives |
| <literal>null</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Log messages doesn't contain line-breaks (CR or LF) |
| anymore and quote paths and other arbitrary text with Java |
| string literal syntax that also escapes <literal><</literal> |
| characters as <literal>\u003C</literal>. These address security |
| concerns related to poor quality log appenders and buggy log |
| readers. This change is mostly noticeable on template processing |
| error entries, which will now quote the exception message. Note |
| that how stack traces (the <literal>Throwable</literal> objects) |
| are logged is still up to the logging framework you are |
| using.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Other changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The DTD-s and XSD-s that are included in |
| <literal>freemarker.jar</literal> under |
| <literal>freemarker/ext/jsp</literal> are now under Apache |
| Software License, Version 2. This is also clarified in the |
| <literal>LICENSE.txt</literal>. Earlier these files had no clear |
| license terms.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_16"> |
| <title>2.3.16</title> |
| |
| <para>Date of release: 2009-12-07</para> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Fixed a bug that caused incorrect unwrapping of sequences |
| to Java arrays (<link |
| xlink:href="https://sourceforge.net/tracker/?func=detail&aid=2105310&group_id=794&atid=100794">See |
| bug report</link>)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Fixed a bug that caused rounding of float and double |
| values (<link |
| xlink:href="https://sourceforge.net/tracker/?func=detail&aid=2503124&group_id=794&atid=100794">See |
| bug report</link>)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Created a new |
| <literal>freemarker.runtime.attempt</literal> category and |
| exceptions caught in <literal><#attempt></literal> blocks |
| are logged into it at a DEBUG severity.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Fixing the (ages old) problem of |
| <literal>RhinoWrapper</literal> not working with all versions of |
| Rhino because of binary incompatible change of Rhino's |
| <literal>Undefined.instance</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Fixed bug where <literal>TextUtil.XMLEncNQG</literal> |
| didn't escape <literal>]]></literal> as |
| <literal>]]&gt;</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Fixed bug where the root directory couldn't be used as the |
| template base directory, as |
| <literal>FileTemplateLoader</literal> believed that the template |
| is outside the base directory.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Macro names can no longer be changed through the |
| API.</para> |
| </listitem> |
| |
| <listitem> |
| <para>FreemarkerServlet now cooperates with Session Fixation |
| Attack Protection in Spring Security, see <link |
| xlink:href="https://sourceforge.net/projects/freemarker/forums/forum/2345/topic/3475868"> |
| forum discussion</link> for details.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Substantially improved performance of the |
| <literal><#return></literal> directive.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Fixed bug where |
| <literal><replaceable>anXMLNode</replaceable>.@@markup</literal> |
| and <literal>@@nested_markup</literal> didn't escape |
| <literal>]]></literal> as |
| <literal>]]&gt;</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_15"> |
| <title>2.3.15</title> |
| |
| <para>Date of release: 2008-12-16</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bug fixed: Hash concatenation (like <literal>hash1 + |
| hash2</literal>) shuffled the order of keys/values even if both |
| hashes were ordered.</para> |
| </listitem> |
| |
| <listitem> |
| <para>In web pages that are based on the |
| <literal>FreemarkerServlet</literal>, you can now use |
| <literal><@include_page path="..."/></literal> to use |
| servlet includes. See more <link |
| linkend="pgui_misc_servlet_include">here...</link></para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The <literal>BeansWrapper</literal> can automatically |
| detect that classes were reloaded by JavaRebel.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Fixed a bug that caused <literal>null</literal> to be |
| returned from |
| <literal>Environment.getCurrentEnvironment()</literal> while |
| processing autoincludes and autoimports. (<link |
| xlink:href="https://sourceforge.net/forum/message.php?msg_id=5531621">See |
| bug report</link>)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Fixed a bug that caused |
| <literal>getObject(Object)</literal> method on POJOs to not be |
| recognized as a general get method.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Substantially improved performance of the |
| <literal><#break></literal> directive.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>DeepUnwrap</literal> now unwraps custom null |
| model of the current object wrapper into a Java |
| <literal>null</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_14"> |
| <title>2.3.14</title> |
| |
| <para>Date of release: 2008-09-01</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>New built-in: <literal>xhtml</literal>. See more <link |
| linkend="ref_builtin_xhtml">here...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>New special variable: <literal>template_name</literal>. |
| See more <link linkend="ref_specvar">here...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Now you can use the values of parameters as the defaults |
| of other parameters, for example <literal><#macro section |
| title label=title></literal>. In earlier versions it worked |
| unreliably. There are no restriction regarding the order of |
| parameters, like <literal><#macro section label=title |
| title></literal> works too.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added a new <link |
| linkend="ref_builtin_string_for_number">number format |
| specifier</link>, <literal>computer</literal>. This uses the |
| same formatting as |
| <literal><replaceable>exp</replaceable>?c</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The constructor to |
| <literal>freemarker.ext.servlet.AllHttpScopesHashModel</literal> |
| is now public, allowing it to be reused in 3rd party web |
| frameworks.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: |
| <literal>freemarker.ext.beans.SimpleMapModel</literal> (unlike |
| either <literal>freemarker.ext.beans.MapModel</literal> or |
| <literal>freemarker.template.SimpleHash</literal>) didn't allow |
| lookup by <literal>java.lang.Character</literal> key when passed |
| a single-character string as a key.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: permissive unwrapping in |
| <literal>freemarker.template.utility.DeepUnwrap</literal> class |
| was not recursively permissive with elements of sequences and |
| hashes.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: <literal>freemarker.ext.beans.MapModel</literal> |
| returns <literal>BeansWrapper.wrap(null)</literal> instead of |
| <literal>null</literal> for <literal>null</literal> values |
| explicitly bound into the map.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: Fixed a subtle bug with property getters of |
| classes implementing a type-parametrized interface.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: A further corner case of <link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1939742&group_id=794&atid=100794">[1939742]</link>.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_13"> |
| <title>2.3.13</title> |
| |
| <para>Date of release: 2008-05-05</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>New built-ins for rounding numbers: |
| <literal>round</literal>, <literal>floor</literal>, |
| <literal>ceiling</literal>. See more <link |
| linkend="ref_builtin_rounding">here...</link></para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para><link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1898300&group_id=794&atid=350794">[1898300]</link>, |
| <link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1818742&group_id=794&atid=350794">[1818742]</link>, |
| <link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1780882&group_id=794&atid=350794">[1780882]</link>: |
| Reworked template caching mechanism for radically improved |
| concurrent performance, with help from Azul Systems engineers. |
| (Achieved 20x speedup with Struts2 webapps on a 128-CPU Azul |
| device compared to 2.3.12.) Also, template loading (including |
| parsing) errors are now cached, improving performance in |
| applications that often try to get missing templates.</para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1892546&group_id=794&atid=100794">[1892546]</link> |
| Allow for custom <literal>TemplateLoader</literal> in |
| <literal>FreemarkerServlet</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1725107&group_id=794&atid=100794">[1725107]</link> |
| Using the FreeMarker JSP taglib support with Servlet 2.4 may |
| generates XML validation warnings.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1939742&group_id=794&atid=100794">[1939742]</link> |
| <literal>ConcurrentModificationException</literal> on accessing |
| nonexistent <literal>SimpleHash</literal> entries in a |
| loop</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1902012&group_id=794&atid=100794">[1902012]</link> |
| <literal>IteratorModel</literal> eats exception causes</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <literal><#assign |
| x></#assign></literal> (empty nested content) has |
| caused <literal>NullPointerException</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1926150&group_id=794&atid=100794">[1926150]</link> |
| <literal>CachedTemplate</literal> should be serializable</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_12"> |
| <title>2.3.12</title> |
| |
| <para>Date of release: 2008-02-03</para> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1857161&group_id=794&atid=100794">[1857161]</link> |
| JSP <literal>SimpleTag</literal> support was broken in |
| 2.3.11.</para> |
| </listitem> |
| |
| <listitem> |
| <para>In the templates, now you can conveniently call Java |
| methods that use the Java 5 varargs feature (variable-length |
| argument lists). Also the overloaded-method chooser logic now |
| considers vararg methods more intelligently.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Enum constants are now identified by their |
| <literal>name()</literal> instead of by their |
| <literal>toString()</literal> (because the latter can be |
| overridden in subclasses). This doesn't affect the way enum |
| constants are printed; of course that still uses |
| <literal>toString()</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Messages in parser exceptions now display the name of the |
| template.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_11"> |
| <title>2.3.11</title> |
| |
| <para>Date of release: 2007-12-04</para> |
| |
| <para>This release contains several performance and usability |
| improvements.</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1687248&group_id=794&atid=100794">[1687248]</link> |
| <emphasis role="bold">Warning! This bugfix may breaks some |
| templates!</emphasis> Fixed the bugs of the <link |
| linkend="ref_builtin_c"><literal>c</literal> built-in</link> |
| (<literal>?c</literal>) that sometimes caused whole numbers to |
| be formatted with <quote>.0</quote> at the end (like: 1.0), and |
| caused numbers sometimes formatted to exponential form (like |
| 4E-20). From now whole numbers will never use decimal dot (not |
| even if the wrapped number is a <literal>double</literal>; |
| remember, the template language knows only a single numerical |
| type), and exponential form will never be used either. Also, the |
| maximum number of digits after the decimal dot was limited to |
| 16, so numbers smaller than 1E-16 will be shown as 0.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>FreeMarker now has much better JSP 2.0 and JSP 2.1 |
| compliance. Most notably, the JSP 2.0 |
| <literal>SimpleTag</literal> interface is now supported. |
| Additionally, even when run in an environment that doesn't have |
| its own JSP implementation, the FreeMarker JSP runtime will make |
| available its own implementation of |
| <literal>JspFactory</literal> and |
| <literal>JspEngineInfo</literal> to tags when JSP 2.0 API JAR is |
| available in classpath, as well as an implementation of |
| <literal>JspApplicationContext</literal> when JSP 2.1 API JAR is |
| available in classpath.</para> |
| </listitem> |
| |
| <listitem> |
| <para>A new model interface, |
| <literal>TemplateDirectiveModel</literal> provides an easier |
| paradigm for implementing user-defined directives than |
| <literal>TemplateTransformModel</literal> did previously. |
| <literal>TemplateTransformModel</literal> will be |
| deprecated.</para> |
| </listitem> |
| |
| <listitem> |
| <para>FreeMarker now finds the Xalan-based XPath support |
| included in Sun JRE/JDK 5 and 6, so no separate Xalan jar is |
| required for the XPath support to work. (However, we recommend |
| Jaxen over Xalan, as the FreeMarker XPath support is more |
| complete with that. Of course for that the Jaxen jar is still |
| needed.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Wrapping performance of <literal>BeansWrapper</literal> |
| has been significantly improved by eliminating repetitive |
| execution of various class tests.</para> |
| |
| <para><emphasis role="bold">Note for |
| <literal>BeansWrapper</literal> customizers:</emphasis> |
| subclasses of <literal>BeansWrapper</literal> that previously |
| overrode <literal>getInstance(Object, ModelFactory)</literal> |
| method should now instead override |
| <literal>getModelFactory(Class)</literal> to take advantage of |
| this improvement. Overriding the old method still works, but it |
| will not take advantage of the performance improvement.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Memory footprint of a wrapper created by |
| <literal>BeansWrapper</literal> has been reduced (by a size of |
| one default-sized <literal>HashMap</literal>) until methods or |
| indexed properties are accessed on it (simple properties can be |
| accessed without increasing memory footprint).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Rhino objects can be used in templates as scalars, |
| numbers, and booleans, following the JavaScript conversion |
| semantics for these types.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>.data_model</literal> is now a |
| <literal>TemplatHashModelEx</literal> when possible. This means |
| that the list of the data-model variable names usually can be |
| get with <literal>.data_model?keys</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>FileTemplateLoader</literal> can now optionally |
| allow following symlinks that point out of the base directory. |
| It is disabled by default for backward compatibility.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1670887&group_id=794&atid=100794">[1670887]</link> |
| <literal>TaglibFactory</literal> taglib matching did not follow |
| JSP 1.2 FCS.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1754320&group_id=794&atid=100794">[1754320]</link> |
| Bug in <literal>setXPathSupportClass</literal> prevented |
| plugging in a user-supplied <literal>XPathSupport</literal> |
| implementation.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1803298&group_id=794&atid=100794">[1803298]</link> |
| Parser error while parsing macro with loop variables</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1824122&group_id=794&atid=100794">[1824122]</link> |
| Loading templates from JAR files could lead to leaking of file |
| handles (due to a bug in the Java API implementation of |
| Sun).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: Cached template is now removed from the cache |
| if the re-loading of the modified template file fails, so no |
| staled template is served.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Documentation changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Substantial reworkings in the Template Authors's Guide |
| (which was previously called Designer's Guide), especially in |
| the Getting Started section.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>#{...}</literal> is documented as deprected |
| construct from now.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The "transform" term is now removed from the |
| documentation. Instead the more general "user-defined directive" |
| term is used, which encompasses macros, |
| <literal>TemplateTransformModel</literal>-s and the new |
| <literal>TemplateDirectiveModel</literal>-s, which are just |
| different ways of implementing user-defined directives.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Some more minor improvements in the Manual.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_10"> |
| <title>2.3.10</title> |
| |
| <para>Date of release: 2007-04-20</para> |
| |
| <para>This release contains several important bugfixes.</para> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>[1589245] <literal>MultiTemplateLoader</literal> clears |
| its internal cached data (used for optimizing subsequent lookups |
| of the same template) when |
| <literal>Configuration.clearTemplateCache()</literal> is |
| invoked.</para> |
| </listitem> |
| |
| <listitem> |
| <para>[1619257] A bug that caused an exception when |
| <literal>strict_bean_model</literal> was used in a FreeMarker |
| configuration <literal>Properties</literal> object or in the |
| <literal><#setting .../></literal> directive has been |
| fixed.</para> |
| </listitem> |
| |
| <listitem> |
| <para>[1685176] A bug that caused |
| <literal>StackOverflowError</literal> in certain interactions of |
| garbage collector with MRU cache under Sun's Java 6 JVM has been |
| fixed.</para> |
| </listitem> |
| |
| <listitem> |
| <para>[1686955] When <literal>ResourceBundleModel</literal> |
| constructs <literal>MessageFormat</literal> objects, it passes |
| them its own locale. <link linkend="beanswrapper_method">More |
| info...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>[1691432] A bug that caused |
| <literal>BeansWrapper.EXPOSE_SAFE</literal> to be no safer than |
| <literal>BeansWrapper.EXPOSE_ALL</literal> has been |
| fixed.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>[1628550] You can now use |
| <literal>dateExp?string.full</literal> for formatting dates |
| using Java built-in format |
| <literal>java.util.Date.FULL</literal> <link |
| linkend="ref_builtin_string_for_date">More info...</link></para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_9"> |
| <title>2.3.9</title> |
| |
| <para>Date of release: 2007-01-23</para> |
| |
| <para>This release contains support for accessing JDK 1.5 enums and |
| public fields of classes from the templates through the |
| BeansWrapper.</para> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>BeansWrapper</literal> can now expose public |
| fields of objects to the template if you call the |
| <literal>setExposeFields(true)</literal> on it. <link |
| linkend="beanswrapper_hash">More info...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>BeansWrapper</literal> can now pass any sequence |
| model to Java methods expecting a |
| <literal>java.util.Collection</literal> or a native Java array |
| (including primitive arrays). <link |
| linkend="beanswrapper_hash">More info...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>BeansWrapper</literal> can now pass any sequence |
| and collection model to Java methods expecting a |
| <literal>java.lang.Iterable</literal>. <link |
| linkend="beanswrapper_hash">More info...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>BeansWrapper</literal> can now unwrap numeric |
| models into correct target types when passing to Java methods |
| expecting a primitive or boxed number. Use of various <link |
| linkend="ref_builtins_expert">expert built-ins</link> to |
| manually coerce the types becomes mostly unnecessary.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Fixed a bug where <literal>BeansWrapper</literal> would |
| pass a <literal>java.util.Collection</literal> to a method |
| expecting a <literal>java.util.Set</literal> in certain rare |
| cases. <link linkend="beanswrapper_hash">More |
| info...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Support for JDK 1.5 enums in |
| <literal>BeansWrapper</literal> and |
| <literal>DefaultObjectWrapper</literal>. By calling the |
| <literal>getEnumModels()</literal> method, you can retrieve a |
| hash model that is keyed by class names and allows access to |
| enumerated values. I.e. if you bind this hash model under name |
| <literal>enums</literal> in the data-model, you can write |
| expressions like |
| <literal>enums["java.math.RoundingMode"].UP</literal> in the |
| template. The enum values can be used as scalars and support |
| equality and inequality comparisons. <link |
| linkend="jdk_15_enums">More info...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>freemarker.ext.rhino.RhinoWrapper</literal> now |
| correctly translates Rhino <literal>Undefined</literal> |
| instance, <literal>UniqueTag.NOT_FOUND</literal>, and |
| <literal>UniqueTag.NULL</literal> to FreeMarker undefined |
| value.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_8"> |
| <title>2.3.8</title> |
| |
| <para>Date of release: 2006-07-09</para> |
| |
| <para>This release substantially improves the JSP 2.0 compatibility. |
| (For those who have seen the same points in 2.3.7: Sorry, the version |
| history was incorrect... those JSP 2.0 related changes were not in the |
| release yet.)</para> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>JSP support improvement: <link |
| xlink:href="http://sourceforge.net/tracker/?func=detail&atid=100794&aid=1326058&group_id=794">[1326058]</link> |
| Added support for <literal>DynamicAttributes</literal> (new in |
| JSP 2.0)</para> |
| </listitem> |
| |
| <listitem> |
| <para>JSP support improvement: Added support for |
| <literal>pushBody()</literal>/<literal>popBody()</literal> in |
| <literal>FreemarkerPageContext</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>JSP support improvement: Added support for |
| <literal>getVariableResolver()</literal> (new in JSP |
| 2.0).</para> |
| </listitem> |
| |
| <listitem> |
| <para>JSP support improvement: Added support for |
| <literal>include(String, boolean)</literal> (new in JSP |
| 2.0).</para> |
| </listitem> |
| |
| <listitem> |
| <para>JSP support improvement: Added support for |
| <literal>getExpressionEvaluator()</literal> (new in JSP 2.0). |
| However, it will need Apache commons-el in the class path, or |
| else this method will not work (it's optional). Note that EL |
| support is not needed in principle, since FreeMarker has it's |
| own expression language. But some custom JSP 2 tags may still |
| want to use this method, after all it's in the JSP 2 API.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_7"> |
| <title>2.3.7</title> |
| |
| <para>Date of release: 2006-06-23</para> |
| |
| <para>This release, compared to 2.3.7 RC1, contains new operators for |
| handling null/missing variables, , the <literal>substring</literal> |
| built-in, and some more bugfixes. Note that 2.3.7 RC1 has a long |
| change log, so you may want to <link linkend="versions_2_3_7rc1">read |
| that</link> too.</para> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The <literal>seq_contains</literal> built-in now handles |
| <literal>TemplateCollectionModel</literal>-s as well.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: In 2.3.7 RC1 |
| <literal>FreemarkerServlet</literal> has always died with |
| <literal>NullPointerException</literal> during |
| initialization.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>3 new operators were added for terser missing variable |
| handling. These operators make the <literal>default</literal>, |
| <literal>exists</literal> and <literal>if_exists</literal> |
| built-ins deprecated. (The parser doesn't issue any warning |
| messages when you use deprecated built-ins, and they are still |
| working.):</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal><replaceable>exp1</replaceable>!<replaceable>exp2</replaceable></literal> |
| is near equivalent with |
| <literal><replaceable>exp1</replaceable>?default(<replaceable>exp2</replaceable>)</literal>, |
| also |
| <literal>(<replaceable>exp1</replaceable>)!<replaceable>exp2</replaceable></literal> |
| is near equivalent with |
| <literal>(<replaceable>exp1</replaceable>)?default(<replaceable>exp2</replaceable>)</literal>. |
| The only difference is that this new operator doesn't |
| evaluate the |
| <literal><replaceable>exp2</replaceable></literal> when the |
| default value is not needed.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>exp1</replaceable>!</literal> is |
| similar to |
| <literal><replaceable>exp1</replaceable>?if_exists</literal>, |
| also <literal>(<replaceable>exp1</replaceable>)!</literal> |
| is similar to |
| <literal>(<replaceable>exp1</replaceable>)?if_exists</literal>. |
| The difference is that with this new operator the default |
| value is an empty string and an empty list and empty hash at |
| the same time (multi-type variable), while with |
| <literal>if_exists</literal> the default value was an empty |
| string and an empty list and empty hash and boolean |
| <literal>false</literal> and a transform that does nothing |
| and ignores all parameters at the same time.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal><replaceable>exp1</replaceable>??</literal> |
| is equivalent with |
| <literal><replaceable>exp1</replaceable>?exists</literal>, |
| also <literal>(<replaceable>exp1</replaceable>)??</literal> |
| is equivalent with with |
| <literal>(<replaceable>exp1</replaceable>)?exists</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>New built-in: |
| <literal><replaceable>exp</replaceable>?substring(<replaceable>from</replaceable>, |
| <replaceable>toExclusive</replaceable>)</literal>, also callable |
| as |
| <literal><replaceable>exp</replaceable>?substring(<replaceable>from</replaceable>)</literal>. |
| Getting substrings was possible for a long time like |
| <literal><replaceable>myString</replaceable>[<replaceable>from</replaceable>..<replaceable>toInclusive</replaceable>]</literal> |
| and |
| <literal><replaceable>myString</replaceable>[<replaceable>from</replaceable>..]</literal>, |
| but |
| <literal><replaceable>myString</replaceable>?substring(<replaceable>from</replaceable>, |
| <replaceable>toExclusive</replaceable>)</literal> and |
| <literal><replaceable>myString</replaceable>?substring(<replaceable>from</replaceable>)</literal> |
| has the advantage that it has an exclusive end, which is more |
| practical. (Edit: Since 2.3.21 ranges are the preferred way |
| again, as it has |
| <literal><replaceable>myString</replaceable>[<replaceable>from</replaceable>..<<replaceable>toExclusive</replaceable>]</literal>.) |
| Sequence (list) slices still has to be get with the old syntax, |
| since <literal>substring</literal> only applies to strings. |
| Please note that the <quote>to</quote> parameter is 1 greater |
| with this new builtin, as it is an exclusive index. Further |
| difference is that the <literal>substring</literal> built-in |
| requires that the <quote>from</quote> index is less than or |
| equal to the <quote>to</quote> index. So 0 length substrings are |
| possible now, but not reversed substrings.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/?func=detail&atid=100794&aid=1487694&group_id=794">[1487694]</link> |
| malfunction when the <literal>recover</literal> directive has no |
| nested content</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_7rc1"> |
| <title>2.3.7 RC1</title> |
| |
| <para>Date of release: 2006-04-27</para> |
| |
| <para>This release contains many bugfixes and some |
| <literal>FreemarkerServlet</literal> related improvements. It's a |
| Release Candidate, which means that it shouldn't be used in production |
| environment yet. We recommend this release for development, however. |
| Please test it.</para> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>FreemarkerServlet</literal> improvement: |
| <literal>AllHttpScopesHashModel</literal> is now public, so you |
| can add unlisted variables to the data-model.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>FreemarkerServlet</literal> improvement: When it |
| throws a <literal>ServletException</literal>, the J2SE 1.4 cause |
| exception is now set under J2SE 1.4.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/?func=detail&atid=100794&aid=1469275&group_id=794">[1469275]</link> |
| <literal>NullPointerException</literal> when using |
| <literal>BeansWrapper</literal> with reloaded classes</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/?func=detail&atid=100794&aid=1449467&group_id=794">[1449467]</link> |
| <literal>HttpSessionHashModel</literal> is not |
| <literal>Serializable</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/?func=detail&atid=100794&aid=1435113&group_id=794">[1435113]</link> |
| Error in <literal>BeanWrapper</literal> with indexed |
| properties</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/?func=detail&atid=100794&aid=1411705&group_id=794">[1411705]</link> |
| Acquisition bug in <literal>TemplateCache</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1459699&group_id=794&atid=100794">[1459699]</link> |
| Tag syntax can't set with |
| <literal>Configuration.setSetting(String, |
| String)</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/?func=detail&atid=100794&aid=1473403&group_id=794">[1473403]</link> |
| <literal>ReturnInstruction.Return</literal> should be |
| public</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/?func=detail&atid=100794&aid=1463664&group_id=794">[1463664]</link>kup |
| <literal>[/#noparse]</literal> is printed out</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_6"> |
| <title>2.3.6</title> |
| |
| <para>Date of release: 2006-03-15</para> |
| |
| <para>Quick release that fixes a serious bug of 2.3.5, days after its |
| release. So for the recently added new features please <link |
| linkend="versions_2_3_5">see the section of 2.3.5.</link></para> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bug fixed: In FreeMarker 2.3.5 only, when you read a bean |
| property for the second time, FreeMarker will say that it's |
| missing (null).</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_5"> |
| <title>2.3.5</title> |
| |
| <para>Date of release: 2006-03-11</para> |
| |
| <para><emphasis>This release was withdrawn because of a serious bug in |
| it. Please don't use it! Of course, all new features of it are |
| included in FreeMarker 2.3.6.</emphasis></para> |
| |
| <para>A few new features and several bugfixes.</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/?func=detail&atid=100794&aid=1435847&group_id=794">[1435847]</link> |
| Alternative syntax doesn't work for comments</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: With the new square bracket syntax, the tag |
| could be closed with <literal>></literal>. Now it can be |
| closed with <literal>]</literal> only.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/?func=detail&atid=100794&aid=1324020&group_id=794">[1324020]</link> |
| <literal>ParseException</literal> with the |
| <literal>ftl</literal> directive if it wasn't in its own |
| line</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/?func=detail&atid=100794&aid=1404033&group_id=794">[1404033]</link> |
| <literal>eval</literal> built-in fails with hash |
| concatenation</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>A new <literal>Configuration</literal> level setting, |
| <literal>tagSyntax</literal> was added. This determines the |
| syntax of the templates (angle bracket syntax VS <link |
| linkend="dgui_misc_alternativesyntax">square bracket |
| syntax</link>) that has no <literal>ftl</literal> directive in |
| it. So now you can choose to use the new square bracket syntax |
| by default. However, the recommended is to use auto-detection |
| (<literal>yourConfig.setTagSyntax(Configuration.AUTO_DETECT_TAG_SYNTAX)</literal>), |
| because that will be the default starting from 2.4. |
| Auto-detection chooses syntax based on the syntax of the first |
| FreeMarker tag of the template (could be any FreeMarker tag, not |
| just <literal>ftl</literal>). Note that as with the previous |
| version, if a the template uses <literal>ftl</literal> |
| directive, then the syntax of the <literal>ftl</literal> |
| directive determines the syntax of the template, and the |
| <literal>tagSyntax</literal> setting is ignored.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Now <literal>BeansWrapper</literal>, |
| <literal>DefaultObjectWrapper</literal> and |
| <literal>SimpleObjectWrapper</literal> support lookup with 1 |
| character long strings in <literal>Map</literal>-s (like |
| <literal>myHash["a"]</literal>) that use |
| <literal>Character</literal> keys. Simply, as a special case, |
| when a hash lookup fails on a string that is 1 character long, |
| it checks for the <literal>Character</literal> key in the |
| underlying map. (Bug tracker entry <link |
| xlink:href="http://sourceforge.net/tracker/?func=detail&atid=100794&aid=1299045&group_id=794">[1299045]</link> |
| FreeMarker doesn't support map lookup with Character |
| keys.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>A new property, <literal>strict</literal> was added to |
| <literal>BeansWrapper</literal>, |
| <literal>DefaultObjectWrapper</literal> and |
| <literal>SimpleObjectWrapper</literal>. If this property is |
| <literal>true</literal> then an attempt to read a bean propertly |
| in the template (like <literal>myBean.aProperty</literal>) that |
| doesn't exist in the bean class (as opposed to just holding |
| <literal>null</literal> value) will cause |
| <literal>InvalidPropertyException</literal>, which can't be |
| suppressed in the template (not even with |
| <literal>myBean.noSuchProperty?default('something')</literal>). |
| This way <literal>?default('something')</literal> and |
| <literal>?exists</literal> and similar built-ins can be used to |
| handle existing properties whose value is |
| <literal>null</literal>, without the risk of hiding typos in the |
| property names. Typos will always cause error. But mind you, it |
| goes against the basic approach of FreeMarker, so use this |
| feature only if you really know what are you doing.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1426227&group_id=794&atid=100794">[1426227]</link> |
| <literal>NullPointerException</literal> in |
| <literal>printStackTrace(...)</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Bug fixed: <link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1386193&group_id=794&atid=100794">[1386193]</link> |
| Division by zero in <literal>ArithmeticEngine</literal></para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_4"> |
| <title>2.3.4</title> |
| |
| <para>Date of release: 2005-10-10</para> |
| |
| <para>Some new features and bugfixes.</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Now you can use <literal>[</literal> and |
| <literal>]</literal> instead of <literal><</literal> and |
| <literal>></literal> for the FreeMarker tags. For example you |
| can write <literal>[#if |
| loggedIn]<replaceable>...</replaceable>[/#if]</literal> and |
| <literal>[@myMacro /]</literal>. <link |
| linkend="dgui_misc_alternativesyntax">More info...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: the <literal>has_content</literal> built-in |
| returned <literal>false</literal> for number, date and boolean |
| values (if the value was not a multi-type value that is also a |
| sequence or collection or hash or string). Now it always returns |
| <literal>true</literal> for a number, date or boolean values |
| (except if the value is also a sequence or collection or hash or |
| string, because then it will be examined only like that).</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bugfix: the parameterless constructor of the |
| <literal>ClassTemplateLoader</literal> didn't worked.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: The Jython wrapper didn't wrapped |
| <literal>java.util.Date</literal> objects well. Now it wraps |
| them with <literal>BeanWrapper</literal> to |
| <literal>TemplateDateModel</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: the <literal>include</literal> directive was |
| blamed when the included file had syntax error.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Other changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Minor Manual fixes.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_3"> |
| <title>2.3.3</title> |
| |
| <para>Date of release: 2005-06-23</para> |
| |
| <para>Some new features and lot of bugfixes.</para> |
| |
| <para>Attention:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>If you are using the Log4J logging, from now at least Log4J |
| 1.2 is required. This is because of incompatible changes in the |
| Log4J API.</para> |
| </listitem> |
| |
| <listitem> |
| <para>If you build FreeMarker yourself: from now at least JavaCC |
| 3.2 (instead of JavaCC 2.1) and at least Ant 1.6.1 (instead of Ant |
| 1.5.x) is required. This doesn't affect users who use the |
| <literal>freemarker.jar</literal> comes with the |
| distribution.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>New built-in for formatting numbers for <quote>computer |
| audience</quote> as opposed to human audience: <link |
| linkend="ref_builtin_c"><literal>c</literal></link>. It should |
| be used for numbers that must use Java language formatting |
| regardless of the number format and locale settings, like for a |
| database record ID used as the part of an URL or as invisible |
| field value in a HTML form, or for printing CSS/JavaScript |
| numerical literals.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-in for the columnar/tabular displaying of |
| sequences: <link |
| linkend="ref_builtin_chunk"><literal>chunk</literal></link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <link |
| linkend="dgui_template_exp_seqenceop_slice">sequence |
| slice</link> and substring operators now allow the omitting of |
| the last index, in which case it defaults to the index of the |
| last sequence item or character. Example: |
| <literal>products[2..]</literal>. (Also, <link |
| linkend="dgui_template_exp_direct_seuqence">numerical range |
| literals</link> now allow the omitting of the final number, in |
| which case it defaults to infinity. Example: |
| <literal>5..</literal>.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: <literal>?replace</literal> has worked forever if |
| the string to replace was <literal>""</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>New template loader: |
| <literal>freemarker.cache.StringTemplateLoader</literal>. It |
| uses a <literal>Map</literal> with <literal>Strings</literal> as |
| its source of templates. See more in the JavaDoc.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Experimental Rhino support: FreeMarker now comes with an |
| experimental object wrapper for Rhino (Java ECMAScript |
| implementation): |
| <literal>freemarker.ext.rhino.RhinoWrapper</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Some new utility methods for |
| <literal>Simple<replaceable>Xxx</replaceable></literal> classes: |
| <literal>SimpleHash.toMap()</literal>, |
| <literal>SimpleSequence.toList()</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: FTL literals and any other |
| <literal>SimpleSequnce</literal>-s, and |
| <literal>SimpleHash</literal>-es now can be used as parameters |
| to the FreeMarker-unaware Java methods that are exposed by |
| <literal>DefaultWrapper</literal> or |
| <literal>BeansWrapper</literal>. That is, the method parameters |
| are automatically converted from |
| <literal>Template<replaceable>Type</replaceable>Model</literal>-s |
| to <literal>java.util.Map</literal> and |
| <literal>java.util.List</literal> respectively.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: The JSP support now works in JSP 2 compliant |
| containers as well. No, it doesn't support the new features of |
| JSP 2 yet, it's just that the JSP 1.2 taglib support has not |
| worked in JSP 2 containers.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: The |
| <literal>Configuration.setOutputEncoding</literal> and |
| <literal>setURLEscapingCharset</literal> methods died with |
| <literal>NullPointerException</literal> when you tried to set |
| the setting value to <literal>null</literal>, which is legal for |
| these settings.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: |
| <literal>freemarker.template.utility.StringUtil.replace(...)</literal> |
| has worked forever if the string to replace was |
| <literal>""</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: The Log4J logging was updated to be compatible |
| with the upcoming Log4J 1.3. Note that now FreeMarker will need |
| at least Log4J 1.2.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: FreeMarker didn't built from the source code on |
| J2SE 1.5, because of the introduction of the |
| <literal>enum</literal> keyword.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: The return value of |
| <literal>SimpleSequence.synchronizedWrapper()</literal> was not |
| properly synchronized. Same with |
| <literal>SimpleHash.synchronizedWrapper()</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: Problem with <literal>BeansWrapper</literal> and |
| overridden bean methods/properties. (Details: bug-tracker entry |
| <link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1217661&group_id=794&atid=100794">#1217661</link> |
| and <link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1166533&group_id=794&atid=100794">#1166533</link>)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: Can't access JSP taglibs if |
| <literal>Request</literal> attribute is defined in the |
| data-model (Details: bug-tracker entry <link |
| xlink:href="http://sourceforge.net/tracker/index.php?func=detail&aid=1202918&group_id=794&atid=100794">#1202918</link>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: Various minor parser glitches were fixed.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Other changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Manual improvements, especially in the FAQ.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_2"> |
| <title>2.3.2</title> |
| |
| <para>Date of release: 2005-01-22</para> |
| |
| <para>Bugfix release.</para> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bugfix: If you use JSP taglibs in FreeMarker templates, |
| FreeMarker possibly tried to get DTD-s from the Sun Web site |
| because of a bug introduced with FreeMarker 2.3.1. This was a |
| serious problem since if your server is offline or the Sun Web |
| site becomes temporarily inaccessible the templates that are |
| using JSP taglibs will possibly die with error.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: The <literal>DefaultObjectWrapper</literal> has |
| ignored the value of the <literal>nullModel</literal> property. |
| (Note that it's discouraged to use a <quote>null |
| model</quote>.)</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3_1"> |
| <title>2.3.1</title> |
| |
| <para>Date of release: 2005-01-04</para> |
| |
| <para>Maintenance (with some important new features) and bugfix |
| release.</para> |
| |
| <section> |
| <title>Possible backward compatibility issue</title> |
| |
| <para>There is a bugfix that may affect the behavior of you Web |
| application if you use JSP tags in FreeMarker templates: |
| FreeMarker's implementation of |
| <literal>javax.servlet.jsp.PageContext.getSession()</literal> was |
| incorrect. The <literal>getSession()</literal> method is a |
| convenience method by which the custom tag can get the current |
| <literal>HttpSession</literal> object (possibly |
| <literal>null</literal> if there is no session). Till now, if the |
| session didn't existed then it has created it automatically, so it |
| never returned <literal>null</literal>. This was a bug, so starting |
| from 2.3.1 it never creates the session, just returns |
| <literal>null</literal> if it doesn't exist. The old incorrect |
| behavior could cause page rendering to fail if the method is called |
| after the page is partially flushed. But beware, the old behavior |
| has possibly hidden some bugs of the Web application, where it |
| forgot to create the session, so with the new correct behavior you |
| may face malfunction caused by previously cloaked bugs of the Web |
| application. (It's the task of the MVC Controller to create the |
| session, except if the JSP tag that needs a session is written so it |
| creates it automatically, but then it doesn't expects that |
| <literal>getSession()</literal> will do it.)</para> |
| </section> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>New built-in: <link |
| linkend="ref_builtin_url"><literal>url</literal></link>. This |
| built-in can be used for URL escaping. Note, however, that to |
| use this built-in conveniently, the software that encapsulates |
| FreeMarker has to be 2.3.1 aware (programmers will find more |
| info bellow...).</para> |
| </listitem> |
| |
| <listitem> |
| <para>New <link linkend="ref_specvar">special variables</link>: |
| <literal>output_encoding</literal> and |
| <literal>url_escaping_charset</literal>. Note, however, that to |
| use these, the software that encapsulates FreeMarker has to be |
| 2.3.1 aware (programmers will find more info bellow...).</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-ins for sequences: <link |
| linkend="ref_builtin_seq_contains"><literal>seq_contains</literal></link>, |
| <link |
| linkend="ref_builtin_seq_index_of"><literal>seq_index_of</literal></link>, |
| <link |
| linkend="ref_builtin_seq_last_index_of"><literal>seq_last_index_of</literal></link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-ins for strings: <link |
| linkend="ref_builtin_left_pad"><literal>left_pad</literal></link>, |
| <link |
| linkend="ref_builtin_right_pad"><literal>right_pad</literal></link> |
| and <link |
| linkend="ref_builtin_contains"><literal>contains</literal></link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New directive: <link |
| linkend="ref.directive.attempt"><literal>attempt</literal>/<literal>recover</literal></link></para> |
| </listitem> |
| |
| <listitem> |
| <para>The <link |
| linkend="ref_builtin_js_string"><literal>js_string</literal> |
| built-in</link> now escapes <literal>></literal> as |
| <literal>\></literal> (to avoid |
| <literal></script></literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>sort</literal> and <literal>sort_by</literal> |
| built-ins now can sort by date values. Also, |
| <literal>sort_by</literal> built-in now can sort by the |
| subvarible of a subvariable of a subvariable... etc. for any |
| level depth. (<link |
| linkend="ref_builtin_sort_by">Details...</link>)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>freemarker.template.TemplateExceptionHandler.HTML_DEBUG_HANDLER</literal> |
| now prints more HTML-context-proof messages.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>New setting: <literal>output_encoding</literal>. This |
| setting is used for informing FreeMarker about the charset that |
| the enclosing software (as a Web application framework) uses for |
| the output of FreeMarker. It's undefined by default, and |
| although it is not strictly required to set it, the enclosing |
| software should do so. This setting must be set if templates |
| want to use the new <literal>output_encoding</literal> special |
| variable, and possibly if they want to use the new |
| <literal>url</literal> built-in. Note that the FreeMarker API |
| allows you to set settings for each template execution |
| individually (look at |
| <literal>Template.createProcessingEnvironment(...)</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>New setting: <literal>url_escaping_charset</literal>. This |
| is the charset used for calculating the escaped parts |
| (<literal>%<replaceable>XX</replaceable></literal>) when you do |
| URL escaping with the new <literal>url</literal> built-in. If it |
| is not set, then the <literal>url</literal> built-in uses the |
| value of the <literal>output_encoding</literal> setting, and if |
| that's not set either, then the parameterless version of |
| <literal>url</literal> built-in (<literal>${foo?url}</literal>) |
| can't be used.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Using the singleton (static) |
| <literal>Configuration</literal> instance is clearly a bad |
| practice, so related methods are now deprecated, and the Manual |
| was adjusted, and the <literal>FreemarkerXmlTask</literal> was |
| updated as well.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The |
| <literal>freemarker.template.utility.Constants</literal> class |
| was added that contains various static final fields that store |
| frequently used constant <literal>TemplateModel</literal> |
| values, as <literal>EMPTY_SEQUENCE</literal>, |
| <literal>ZERO</literal>, ...etc.</para> |
| </listitem> |
| |
| <listitem> |
| <para>When using <literal>SecurityManager</literal> with |
| FreeMarker, accessing system properties may caused |
| AccessControlException. Now such exceptions are catched and |
| logged with warning level, and the default value of the property |
| is returned.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The needles <literal>InvocationTargetException</literal> |
| is now removed from the exception cause trace in certain |
| cases.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added a dirty hack that prints |
| <literal>ServletException</literal> root cause in |
| <literal>TemplateException</literal>'s stack trace if that's the |
| direct cause exception of the |
| <literal>TemplateException</literal>, despite the poorly written |
| <literal>ServletException</literal> class.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: FreeMarker's implementation of |
| <literal>javax.servlet.jsp.PageContext.getSession()</literal> |
| was incorrect. The <literal>getSession()</literal> method is a |
| convenience method by which the custom tag can get the current |
| <literal>HttpSession</literal> object (possibly |
| <literal>null</literal> if there is no session). Till now, if |
| the session didn't existed then it has created it automatically, |
| so it never returned <literal>null</literal>. This was a bug, so |
| starting from 2.3.1 it never creates the session, just returns |
| <literal>null</literal> if it doesn't exist. The old incorrect |
| behavior could cause page rendering to fail if the method is |
| called after the page is partially flushed. But beware, the old |
| behavior has possibly hidden some bugs of the Web application, |
| where it forgot to create the session, so with the new correct |
| behavior you may face malfunction caused by previously cloaked |
| bugs of the Web application. (It's the task of the MVC |
| Controller to create the session, except if the JSP tag that |
| needs a session is written so it creates it automatically, but |
| then it doesn't expects that <literal>getSession()</literal> |
| will do it.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: The <literal>BeansWrapper</literal> didn't always |
| handled properly the case of a Java class having both a public |
| static field and a public static method with the same |
| name.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: <literal>SimpleMethodModel</literal> had |
| incorrectly propagate exceptions sometimes, causing null pointer |
| exception.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: The template execution may used outdated cached |
| values when you have processed the same |
| <literal>Environment</literal> for multiple times, and changed |
| settings between the two processings. Note that this could |
| happen only in single-thread environment, where such setting |
| modifications are allowed.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: Some of the string built-ins has died with |
| <literal>IndexOutOfBounds</literal> exception if the template |
| author has forgotten to specify required parameters. Now they |
| die with more helpful error messages.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: |
| <literal>freemarker.ext.dom.NodeModel.equals(...)</literal> has |
| died with null pointer exception if its argument was |
| <literal>null</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: The cause exception of |
| <literal>TemplateException</literal>-s was sometimes printed |
| twice in stack traces with J2SE 1.4 or later.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: The |
| <literal>StringUtil.FTLStringLiteralEnc(String)</literal> method |
| was finished.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Other changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Fixes and improvements in the Manual and in the API |
| JavaDoc.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>The history of the releases before the final version</title> |
| |
| <section> |
| <title>Differences between the preview release and final |
| release</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added a dirty hack that prints |
| <literal>ServletException</literal> root cause in |
| <literal>TemplateException</literal>'s stack trace if that's |
| the direct cause exception of the |
| <literal>TemplateException</literal>, despite the poorly |
| written <literal>ServletException</literal> class.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: |
| <literal>freemarker.ext.dom.NodeModel.equals(...)</literal> |
| has died with null pointer exception if its argument was |
| <literal>null</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: The cause exception of |
| <literal>TemplateException</literal>-s was sometimes printed |
| twice in stack traces with J2SE 1.4 or later.</para> |
| </listitem> |
| |
| <listitem> |
| <para>More minor improvements in the Manual.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_3"> |
| <title>2.3</title> |
| |
| <para>Date of release: 2004-June-15</para> |
| |
| <para>FreeMarker 2.3 introduces numerous little new features and |
| quality improvements compared to the 2.2.x series. The most notable |
| improvements are the ability to define functions (methods) in |
| templates, the ability to interpolate variables in string literals, |
| the support for a variable number of macro parameters, and the more |
| intelligent default object wrapper. Although none of the improvements |
| is a drastic change, the 2.3.x series is not backward compatible with |
| the 2.2.x series (see the list below), so you may choose to use it for |
| new projects only.</para> |
| |
| <para>Probably the most <quote>loudly promoted</quote> new feature is |
| the totally redesigned XML wrapper. With the new XML wrapper |
| FreeMarker targets a new application domain, which is similar to the |
| application domain of XSLT: transforming complex XML to whatever |
| textual output. Although this subproject is young, it is definitely |
| usable in practice. See the <link linkend="xgui">XML Processing |
| Guide</link> for more details.</para> |
| |
| <section> |
| <title>Non backward-compatible changes!</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Since interpolations (<literal>${...}</literal> and |
| <literal>#{...}</literal>) now work inside string literals, the |
| character sequence <literal>${</literal> and |
| <literal>#{</literal> in string literals are reserved for that. |
| So if you have something like <literal><#set x = |
| "${foo}"></literal>, then you have to replace it with |
| <literal><#set x = r"${foo}"></literal> -- beware, escapes |
| such as <literal>\n</literal> will not work in raw |
| (<literal>r</literal>) strings.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The default (initial) value of the |
| <literal>strict_syntax</literal> setting has been changed from |
| <literal>false</literal> to <literal>true</literal>. When |
| <literal>strict_syntax</literal> is <literal>true</literal>, |
| tags with old syntax as <literal><include |
| "foo.ftl"></literal> will be considered as static text (so |
| they go to the output as-is, like HTML tags do), and not as FTL |
| tags. Such tags have to be rewritten to <literal><#include |
| "foo.ftl"></literal>, since only parts that starts with |
| <literal><#</literal>, <literal></#</literal>, |
| <literal><@</literal>, or <literal></@</literal> count as |
| FTL tags. Or, to recover the old transitional behavior, where |
| both legacy and new tag syntax was recognized, you have to |
| explicitly set <literal>strict_syntax</literal> to |
| <literal>false</literal>: |
| <literal>cfg.setStrictSyntaxMode(false)</literal>. Also, for |
| individual templates you can force the old behavior by starting |
| the template with <literal><#ftl |
| strict_syntax=false></literal>. (For more information about |
| why strict syntax is better than old syntax <link |
| linkend="ref_depr_oldsyntax">read this...</link>)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Several classes were moved from the |
| <literal>freemarker.template</literal> package, to the new |
| <literal>freemarker.core</literal> package:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>"Normal" classes: <literal>ArithmeticEngine</literal>, |
| <literal>Configurable</literal>, |
| <emphasis><literal>Environment</literal></emphasis></para> |
| </listitem> |
| |
| <listitem> |
| <para>Exceptions: |
| <literal>InvalidReferenceException</literal>, |
| <literal>NonBooleanException</literal>, |
| <literal>NonNumericalException</literal>, |
| <literal>NonStringException</literal>, |
| <literal>ParseException</literal>, |
| <literal>StopException</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Errors: <literal>TokenMgrError</literal></para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>The main reason of the splitting of |
| <literal>freemarker.template</literal> package was that the |
| amount of "expert" public classes and interfaces grows too much, |
| as we introduce API-s for third-party tools, such as debugging |
| API.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>freemarker.template.TemplateMethodModel.exec</literal> |
| now returns <literal>Object</literal> instead of |
| <literal>TemplateModel</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>White-space stripping is now more aggressive as before: it |
| always removes leading and trailing white-space if the line only |
| contains FTL tags. (Earlier the white-space was not removed if |
| the tag was <literal><#include |
| <replaceable>...</replaceable>></literal> or user-defined |
| directive tag with empty directive syntax as |
| <literal><@myMacro/></literal> (or its equivalents: |
| <literal><@myMacro></@myMacro></literal> and |
| <literal><@myMacro></@></literal>). Now white-space |
| is removed in these cases as well.) Also, white-space sandwiched |
| between two non-outputting elements, such as macro definitions, |
| assignments, imports, or property settings, is now ignored. More |
| information: <xref |
| linkend="dgui_misc_whitespace_stripping"/></para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>function</literal> directive is now used for |
| defining methods. You should replace <literal>function</literal> |
| with <literal>macro</literal> in your old templates. Note, |
| however, that old <literal>function</literal>-s will still work |
| if you don't use the <literal>return</literal> directive in |
| them, and you invoke them with the deprecated the |
| <literal>call</literal> directive.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The expressions <literal>as</literal>, |
| <literal>in</literal>, and <literal>using</literal> are now |
| keywords in the template language and cannot be used as |
| top-level variable names without square-bracket syntax. If, by |
| some chance, you have top-level variables that use one of these |
| names, you will have to rename them, or use the square-bracket |
| syntax with the <literal>.vars</literal> special variable: |
| <literal>.vars["in"]</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>?new</literal> built-in, as it was |
| implemented, was a security hole. Now, it only allows you to |
| instantiate a java object that implements the |
| <literal>freemarker.template.TemplateModel</literal> interface. |
| If you want the functionality of the <literal>?new</literal> |
| built-in as it existed in prior versions, make available an |
| instance of the |
| <literal>freemarker.template.utility.ObjectConstructor</literal> |
| class to your template. (For example: |
| <literal>myDataModel.put("objConstructor", new |
| ObjectConstructor());</literal>, and then in the template you |
| can do this: <literal><#assign aList = |
| objConstructor("java.util.ArrayList", 100)></literal>)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Changes to the |
| <literal>FreemarkerServlet</literal>:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The <literal>FreemarkerServlet</literal> uses |
| <literal>ObjectWrapper.DEFAULT_WRAPPER</literal> by default |
| instead of <literal>ObjectWrapper.BEANS_WRAPPER</literal>. |
| What this means is that, by default, objects of type |
| <literal>java.lang.String</literal>, |
| <literal>java.lang.Number</literal>, |
| <literal>java.util.List</literal>, and |
| <literal>java.util.Map</literal> will be wrapped as |
| <literal>TemplateModels</literal> via the classes |
| <literal>SimpleScalar</literal>, |
| <literal>SimpleNumber</literal>, |
| <literal>SimpleSequence</literal>, and |
| <literal>SimpleHash</literal> respectively. Thus, the java |
| methods on those objects will not be available. The default |
| wrapper implementation in FreeMarker 2.3 automatically knows |
| how to wrap Jython objects, and also wraps |
| <literal>org.w3c.dom.Node</literal> objects into instances |
| of <literal>freemarker.ext.dom.NodeModel</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>FreemarkerServlet</literal> base |
| implementation no longer deduces the locale used for |
| templates with <literal>HttpRequest.getLocale()</literal>. |
| Rather, it simply delegates to the new protected method, |
| <literal>deduceLocale</literal>. The default implementation |
| of this method simply returns the value of configuration the |
| <literal>locale</literal> setting.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Interpolation in string literals. For convenience, |
| interpolations are now supported in string literals. For |
| example: <literal><@message "Hello ${user}!" /></literal> |
| is the same as <literal><@message "Hello " + user + "!" |
| /></literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Raw string literals: In string literals prefixed with |
| <literal>r</literal>, interpolations and escape sequences will |
| not be interpreted as special tokens. For example: |
| <literal>r"\n${x}"</literal> will be simply interpreted as the |
| character sequence <literal>'\'</literal>, |
| <literal>'n'</literal>, <literal>'$'</literal>, |
| <literal>'{'</literal>, <literal>'x'</literal>, |
| <literal>'}'</literal>, and not as line-feed and the value of |
| the <literal>x</literal> variable.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Method variables can be defined in FTL, with the <link |
| linkend="ref.directive.function"><literal>function</literal></link> |
| directive.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Support for a variable number of macro parameters. If the |
| last parameter in a macro declaration ends with |
| <literal>...</literal>, all extra parameters passed to the macro |
| will be available via that parameter. For macros called with |
| positional parameters, the parameter will be a sequence. For |
| named parameters, the parameter will be a hash. Note that it all |
| works with the new <literal>function</literal> directive as |
| well.</para> |
| </listitem> |
| |
| <listitem> |
| <para>A new header parameter, <literal>strip_text</literal>, |
| that removes all top-level text from a template. This is useful |
| for <quote>include files</quote> to suppress newlines that |
| separate the macro definitions. See <link |
| linkend="ref.directive.ftl"><literal>ftl</literal> |
| directive</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>New <link linkend="ref_specvar">special variable</link>: |
| <literal>.vars</literal>. This is useful to read top-level |
| variables with square bracket syntax, for example |
| <literal>.vars["name-with-hyphens"]</literal> and |
| <literal>.vars[dynamicName]</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>macro</literal> and assignment directives now |
| accept arbitrary destination variable name with quoted syntax. |
| For example: <literal><#macro |
| "name-with-hyphens"><replaceable>...</replaceable></literal> |
| or <literal><#assign "foo bar" = 123></literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>?keys</literal> and |
| <literal>?values</literal> hash built-ins now return sequences. |
| In practical terms this means you can access their sizes or |
| retrieve their sub variables by index, and use all of the <link |
| linkend="ref_builtins_sequence">sequence built-ins</link>. (Note |
| for the programmers: The <literal>TemplateHashModelEx</literal> |
| interface has not been changed. Your old code will work. See the |
| API documentation to see why.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Existence built-ins (<literal>?default</literal>, |
| <literal>?exists</literal>, etc.) are now working with sequence |
| sub variables as well. Read the documentation of the |
| <literal>default</literal> built-in for more information.</para> |
| </listitem> |
| |
| <listitem> |
| <para>White-space stripping is now more aggressive as before: it |
| always removes leading and trailing white-space if the line only |
| contains FTL tags. (Earlier the white-space was not removed if |
| the tag was <literal><#include |
| <replaceable>...</replaceable>></literal> or user-defined |
| directive tag with empty directive syntax as |
| <literal><@myMacro/></literal> (or its equivalents: |
| <literal><@myMacro></@myMacro></literal> and |
| <literal><@myMacro></@></literal>). Now white-space |
| is removed in these cases as well.) Also, top-level white-space |
| that separates macro definitions and/or assignments is now |
| ignored. More information: <xref |
| linkend="dgui_misc_whitespace_stripping"/></para> |
| </listitem> |
| |
| <listitem> |
| <para>White-space stripping can be disabled for a single line |
| with the <link |
| linkend="ref.directive.nt"><literal>nt</literal></link> |
| directive (for No Trim).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Hashes can be concatenated using the <literal>+</literal> |
| operator. The keys in the hash on the right-hand side take |
| precedence.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-ins for Java and JavaScript string escaping: |
| <link linkend="ref_builtin_j_string">j_string</link> and <link |
| linkend="ref_builtin_js_string">js_string</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>replace</literal> and |
| <literal>split</literal> built-ins now support case-insensitive |
| comparsion and regular expressions (J2SE 1.4+ only), and some |
| other new options. More information can be found <link |
| linkend="ref_builtin_string_flags">here</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-in for regular expression matching (J2SE 1.4+ |
| only): <link |
| linkend="ref_builtin_matches"><literal>matches</literal></link></para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-in, <literal>eval</literal>, to evaluate a |
| string as FTL expression. For example |
| <literal>"1+2"?eval</literal> returns the number 3.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-ins for Java and JavaScript string escaping: |
| <link linkend="ref_builtin_j_string">j_string</link> and <link |
| linkend="ref_builtin_js_string">js_string</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>New special variables to read the value of the locale |
| setting: <literal>locale</literal>, <literal>lang</literal>. See |
| more <link linkend="ref_specvar">in the |
| reference...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>New special variable to read the FreeMarker version |
| number: <literal>version</literal>. See more <link |
| linkend="ref_specvar">in the reference...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Tree new directives, <literal>recurse</literal>, |
| <literal>visit</literal> and <literal>fallback</literal>, were |
| introduced to support declarative node-tree processing. These |
| are meant to be used typically (though not exclusively) for |
| processing XML input. Together with this, a new variable type |
| has been introduced, the node type. See the <link |
| linkend="xgui_declarative">chapter on declarative XML |
| processing</link> for more details.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>?new</literal> built-in, as it was |
| implemented, was a security hole. Now, it only allows you to |
| instantiate a java object that implements the |
| <literal>freemarker.template.TemplateModel</literal> interface. |
| <phrase role="forProgrammers">If you want the functionality of |
| the <literal>?new</literal> built-in as it existed in prior |
| versions, make available an instance of the |
| <literal>freemarker.template.utility.ObjectConstructor</literal> |
| class to your template. (For example: |
| <literal>myDataModel.put("objConstructor", new |
| ObjectConstructor());</literal>, and then in the template you |
| can do this: <literal><#assign aList = |
| objConstructor("java.util.ArrayList", |
| 100)></literal>)</phrase></para> |
| </listitem> |
| |
| <listitem> |
| <para>Variable names can contain <literal>@</literal> anywhere |
| (without using quote-bracket syntax). For example: |
| <literal><#assign x@@@ = 123></literal> is valid.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The expressions <literal>as</literal>, |
| <literal>in</literal>, and <literal>using</literal> are now |
| keywords in the template language and cannot be used as |
| top-level variable names without square-bracket syntax (as |
| <literal>.vars["in"]</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>New parameter to the <link |
| linkend="ref_directive_ftl"><literal>ftl</literal> |
| directive</link>: <literal>attributes</literal>. The value of |
| this attribute is a hash that associates arbitrary attributes |
| (name-value pairs) to the template. The values of the attributes |
| can be of any type (string, number, sequence... etc.). |
| FreeMarker doesn't try to understand the meaning of the |
| attributes. It's up to the application that encapsulates |
| FreeMarker (as a Web application framework). Thus, the set of |
| allowed attributes and their semantic is application (Web |
| application framework) dependent.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Other minor quality improvements...</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Smarter default object wrapping: The default object |
| wrapper is now |
| <literal>freemarker.template.DefaultObjectWrapper</literal>, |
| which falls back on wrapping arbitrary objects as beans using |
| the <literal>freemarker.ext.beans.BeansWrapper</literal>. Also, |
| it will wrap <literal>org.w3c.dom.Node</literal> objects with |
| the new DOM wrapper. Also, it is aware of Jython objects, and |
| will use <literal>freemarker.ext.jython.JythonWrapper</literal> |
| if the object passed in is a Jython object. (We count it as a |
| backward compatible change, since this new object wrapper wraps |
| differently only those objects that the old wrapper was not able |
| to wrap, so it has thrown exception.)</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>freemarker.template.TemplateMethodModel.exec</literal> |
| now returns <literal>Object</literal> instead of |
| <literal>TemplateModel</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The default (initial) value of the |
| <literal>strict_syntax</literal> setting has been changed from |
| <literal>false</literal> to <literal>true</literal>. When |
| <literal>strict_syntax</literal> is <literal>true</literal>, |
| tags with old syntax as <literal><include |
| "foo.ftl"></literal> will be considered as static text (so |
| they go to the output as-is, like HTML tags do), and not as FTL |
| tags. Such tags have to be rewritten to <literal><#include |
| "foo.ftl"></literal>, since only parts that starts with |
| <literal><#</literal>, <literal></#</literal>, |
| <literal><@</literal>, or <literal></@</literal> count as |
| FTL tags. Or, to recover the old transitional behavior, where |
| both legacy and new tag syntax was recognized, you have to |
| explicitly set <literal>strict_syntax</literal> to |
| <literal>false</literal>: |
| <literal>cfg.setStrictSyntaxMode(false)</literal>. Also, for |
| individual templates you can force the old behavior by starting |
| the template with <literal><#ftl |
| strict_syntax=false></literal>. (For more information about |
| why strict syntax is better than old syntax <link |
| linkend="ref_depr_oldsyntax">read this...</link>)</para> |
| </listitem> |
| |
| <listitem> |
| <para>New <literal>CacheStorage</literal> implementation: |
| <literal>freemarker.cache.MruCacheStorage</literal>. This cache |
| storage implements a two-level Most Recently Used cache. In the |
| first level, items are strongly referenced up to the specified |
| maximum. When the maximum is exceeded, the least recently used |
| item is moved into the second level cache, where they are softly |
| referenced, up to another specified maximum. |
| <literal>freemarker.cache.SoftCachseStorage</literal> and |
| <literal>StrongCachseStorage</literal> are deprected, |
| <literal>MruCachseStorage</literal> is used everywhere instead. |
| The default cache storage is now an |
| <literal>MruCachseStorage</literal> object with 0 strong size, |
| and infinite soft size. |
| <literal>Configuration.setSetting</literal> for |
| <literal>cache_storage</literal> now understands string values |
| as <literal>"strong:200, soft:2000"</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>For <literal>BeansWrapper</literal> generated models, you |
| can now use the <literal>${obj.method(args)}</literal> syntax to |
| invoke methods whose return type is <literal>void</literal>. |
| <literal>void</literal> methods now return |
| <literal>TemplateModel.NOTHING</literal> as their return |
| value.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>freemarker.template.SimpleHash</literal> now can |
| wrap read-only <literal>Map</literal>-s, such as the map of HTTP |
| request parameters in Servlet API.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>TemplateNodeModel</literal> interface was |
| introduced to support recursive processing of trees of nodes. |
| Typically, this will be used in relation to XML.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New package: <literal>freemarker.ext.dom</literal>. This |
| contains the new XML wrapper, that supports the processing of |
| XML documents using the visitor pattern (i.e. with |
| <literal><#visit <replaceable>...</replaceable>></literal> |
| and similar directives), and to provide more convenient XML |
| traversing as the legacy wrapper. See the <link |
| linkend="xgui">XML processing guide</link> for more |
| details.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New package: <literal>freemarker.core</literal>. Classes |
| used by mostly power-users was moved here from the |
| <literal>freemarker.template</literal> package. The main reason |
| of the splitting of <literal>freemarker.template</literal> |
| package was that the amount of "expert" public classes and |
| interfaces grows too much, as we introduce API-s for third-party |
| tools, such as debugging API.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New package: <literal>freemarker.debug</literal>. This |
| provides a debugging API, by which you can debug executing |
| templates through network (RMI). You have to write the front-end |
| (client), as the API is just the server side. For more |
| information please read the JavaDoc of the |
| <literal>freemarker.debug</literal> package.</para> |
| </listitem> |
| |
| <listitem> |
| <para>You can query the FreeMarker version number with static |
| method <literal>Configuration.getVersionNumber()</literal>. |
| Also, the <literal>Manifest.mf</literal> included in |
| <literal>freemarker.jar</literal> now contains the FreeMarker |
| version number, furthermore, executing it with <literal>java |
| -jar freemarker.jar</literal> will print the version number to |
| the stdout.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added a new protected <literal>FreemarkerServlet</literal> |
| method: <literal>Configuration |
| getConfiguration()</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Date support is now labeled as final. (It was experimental |
| earlier.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>BeansWrapper</literal> has been improved to |
| prevent some security exceptions when introspecting.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Other minor quality improvements and extensions...</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Other changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Fixes and improvements in the Manual and in the API |
| JavaDoc.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>The history of the releases before the final version</title> |
| |
| <section> |
| <title>Differences between the final release and Release Candidate |
| 4</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added a new special variable to print the FreeMarker |
| version number: <literal>version</literal>. See more <link |
| linkend="ref_specvar">in the reference...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Minor documentation fixes and improvements.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Release Candidate 4 and Release |
| Candidate 3</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The <literal>BeansWrapper</literal> has been improved to |
| prevent some security exceptions when introspecting.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>FreemarkerXmlTask</literal> has two new |
| sub-tasks that can be used to prepare template execution with |
| Jython scripts: <literal>prepareModel</literal> and |
| <literal>prepareEnvironment</literal>. The |
| <literal>jython</literal> sub-task is now deprecated, and does |
| the same as <literal>prepareEnvironment</literal>. See the |
| Java API documentation for more details.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New special variable to read the FreeMarker version |
| number: <literal>version</literal>. See more <link |
| linkend="ref_specvar">in the reference...</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: Greater-than sign doesn't confuse the |
| <literal>eval</literal> built-in anymore.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: The <literal>BeansWrapper</literal> now wrapps |
| the <literal>null</literal> return values of methods |
| appropriately.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: The <literal>FreemarkerXmlTask</literal> doesn't |
| need Jython classes anymore, unless you really use Jython |
| scripts. Several other bugfixes in the Jython related |
| features.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: If the template exception handler has ignored |
| the exception, errors occurring in interpolations inside FTL |
| tags (e.g. <literal><#if "foo${badVar}" != |
| "foobar"></literal>) were handled in the same way as errors |
| occuring in interpolations outside FTL tags. Thus, the |
| directive call was not skipped, and the problematic |
| interpolation was replaced with an empty string. (This was |
| inconsistent with the behavior of <literal><#if |
| "foo"+badVar != "foobar"></literal>, which should be 100% |
| equivalent with the previous example.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: The <literal>FileTemplateLoader</literal> is now |
| more robust when it receives paths that are malformed |
| according the native file system. In the earlier version such |
| paths sometimes caused unexpected |
| <literal>IOException</literal> that aborted the searching for |
| the template in further |
| <literal>FileTemplateLoader</literal>-s when you use the |
| <literal>MultiTemplateLoader</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Release Candidate 3 and Release |
| Candidate 2</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bugfix: Fixing a fatal bug in the template cache that |
| was introduced with the latest cache bugfix. The template |
| cache has always reloaded the unchanged template when the |
| update delay has been elapsed, until the template has been |
| actually changed, in which case it has never reloaded the |
| template anymore.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Release Candidate 2 and Release |
| Candidate 1</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bugfix: The template cache didn't reload the template |
| when it was replaced with an older version.</para> |
| </listitem> |
| |
| <listitem> |
| <para>API JavaDoc fix: date/time related classes/interfaces |
| were marked as experimental. They are not experimental.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Minor site improvements.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Release Candidate 1 and Preview 16 |
| releases</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para><emphasis>Warning! Non-backward-compatible |
| change!</emphasis> The default (initial) value of the |
| <literal>strict_syntax</literal> setting has been changed from |
| <literal>false</literal> to <literal>true</literal>. When |
| <literal>strict_syntax</literal> is <literal>true</literal>, |
| tags with old syntax as <literal><include |
| "foo.ftl"></literal> will be considered as static text (so |
| they go to the output as-is, like HTML tags do), and not as |
| FTL tags. Such tags have to be rewritten to |
| <literal><#include "foo.ftl"></literal>, since only |
| parts that starts with <literal><#</literal>, |
| <literal></#</literal>, <literal><@</literal>, or |
| <literal></@</literal> count as FTL tags. Or, to recover |
| the old transitional behavior, where both legacy and new tag |
| syntax was recognized, you have to explicitly set |
| <literal>strict_syntax</literal> to <literal>false</literal>: |
| <literal>cfg.setStrictSyntaxMode(false)</literal>. Also, for |
| individual templates you can force the old behavior by |
| starting the template with <literal><#ftl |
| strict_syntax=false></literal>. (For more information about |
| why strict syntax is better than old syntax <link |
| linkend="ref_depr_oldsyntax">read this...</link>)</para> |
| </listitem> |
| |
| <listitem> |
| <para>New parameter to the <link |
| linkend="ref_directive_ftl"><literal>ftl</literal> |
| directive</link>: <literal>attributes</literal>. The value of |
| this attribute is a hash that associates arbitrary attributes |
| (name-value pairs) to the template. The values of the |
| attributes can be of any type (string, number, sequence... |
| etc.). FreeMarker doesn't try to understand the meaning of the |
| attributes. It's up to the application that encapsulates |
| FreeMarker (as a Web application framework). Thus, the set of |
| allowed attributes and their semantic is application (Web |
| application framework) dependent.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: |
| <literal>freemarker.template.utility.DeepUnwrap</literal> |
| unwrapped sequences to empty |
| <literal>ArrayList</literal>-s.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: If you included/imported a template with |
| <literal>*/</literal> in path (acquisition), and that template |
| in turn itself included/imported another template with |
| <literal>*/</literal> in path, it may failed.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New methods to the |
| <literal>freemarker.core.Environment</literal>: |
| <literal>importLib(Template loadedTemplate, java.lang.String |
| namespace)</literal>, |
| <literal>getTemplateForImporting(...)</literal>, |
| <literal>getTemplateForInclusion(...)</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Improvements in the |
| <literal>java.io.IOException</literal> related error messages |
| of the <literal>include</literal> and |
| <literal>import</literal> directives.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Minor improvements in the documentation.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Preview 16 and Preview 15 |
| releases</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>New package: <literal>freemarker.debug</literal>. This |
| provides a debugging API, by which you can debug executing |
| templates through network (RMI). You have to write the |
| front-end (client), as the API is just the server side. For |
| more information please read the JavaDoc of the |
| <literal>freemarker.debug</literal> package. (The debugging |
| API is present for a while, just I forgot to announce it in |
| the version history. Sorry for that.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: With the new XML wrapper, |
| <literal>@@markup</literal> and similar special keys:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>have returned |
| <literal><foo></foo></literal> for empty |
| elements instead of <literal><foo /></literal>. |
| Other than it was needlessly verbose, it has confused |
| browsers if you generate HTML.</para> |
| </listitem> |
| |
| <listitem> |
| <para>have showed the attributes that have no explicitly |
| given value in the original document, just a default value |
| coming form the DTD.</para> |
| </listitem> |
| |
| <listitem> |
| <para>have forgot to put space before the system |
| identifier in the <literal><!DOCTYPE |
| <replaceable>...</replaceable>></literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: XPath with Jaxen has died with |
| <literal>NullPointerException</literal> if the context was an |
| empty node set.</para> |
| </listitem> |
| |
| <listitem> |
| <para>A bit more intelligent Xalan XPath error |
| messages.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Revoked fallback-to-classloader logic from the template |
| cache.</para> |
| </listitem> |
| |
| <listitem> |
| <para>From now on, if no XPath engine is available, and the |
| hash key in an XML query can't be interpreted without XPath, |
| an error will tell this clearly, rather than silently |
| returning undefined variable (null).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: Some templates have caused the parser to |
| die.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Some other minor improvements here and there...</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Preview 15 and Preview 14 |
| releases</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bugfix: The new default template cache storage |
| (<literal>MruCacheStorage</literal>) has started to |
| continually fail with <literal>NullPointerException</literal> |
| from a random point of time, usually when the memory usage was |
| high in the JVM.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: In error messages, when the quoted FTL directive |
| had nested content, that was quoted as well, so the quotation |
| could be very long and expose nested lines needlessly.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Preview 14 and Preview 13 |
| releases</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>freemarker.template.TemplateMethodModel.exec</literal> |
| now returns <literal>Object</literal> instead of |
| <literal>TemplateModel</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Fixes and improvements for XPath with Jaxen (not Xalan). |
| Non-node-set XPath expressions are now working. FreeMarker |
| variables are accessible in XPath expressions with XPath |
| variable references (e.g. |
| <literal>doc["book/chapter[title=$currentTitle]"]</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>freemarker.cache.SoftCachseStorage</literal> |
| and <literal>StrongCachseStorage</literal> is deprected. The |
| more flexible <literal>MruCachseStorage</literal> is used |
| instead everywhere. The default cache storage is now an |
| <literal>MruCachseStorage</literal> object with 0 strong size, |
| and infinite soft size. |
| <literal>Configuration.setSetting</literal> for |
| <literal>cache_storage</literal> now understands string values |
| as <literal>"strong:200, soft:2000"</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: |
| <literal>freemarker.cache.MruCachseStorage</literal> has died |
| with <literal>ClassCastException</literal> sometimes.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-ins for Java and JavaScript string escaping: |
| <link linkend="ref_builtin_j_string">j_string</link> and <link |
| linkend="ref_builtin_js_string">js_string</link></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>freemarker.template.TemplateExceptionHandler.HTML_DEBUG_HANDLER</literal> |
| now prints more HTML-context-proof messages.</para> |
| </listitem> |
| |
| <listitem> |
| <para>You can query the FreeMarker version number with static |
| method <literal>Configuration.getVersionNumber()</literal>. |
| Also, the <literal>Manifest.mf</literal> included in |
| <literal>freemarker.jar</literal> now contains the FreeMarker |
| version number, furthermore, executing it with <literal>java |
| -jar freemarker.jar</literal> will print the version number to |
| the stdout.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Added a new protected |
| <literal>FreemarkerServlet</literal> method: |
| <literal>Configuration getConfiguration()</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: FreeMarker has frozen on empty conditional |
| blocks in certain contexts.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: Methods called twice on an object using the |
| <literal>list</literal> directive, as |
| <literal>parent.getChildren()</literal> with |
| <literal><#list parent.children as child> |
| ...</#list></literal></para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Preview 13 and Preview 12 |
| releases</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>White-space stripping is now more aggressive as before: |
| it always removes leading and trailing white-space if the line |
| only contains FTL tags. (Earlier the white-space was not |
| removed if the tag was <literal><#include |
| <replaceable>...</replaceable>></literal> or user-defined |
| directive tag with empty directive syntax as |
| <literal><@myMacro/></literal> (or its equivalents: |
| <literal><@myMacro></@myMacro></literal> and |
| <literal><@myMacro></@></literal>). Now |
| white-space is removed in these cases as well.) Also, |
| top-level white-space that separates macro definitions and/or |
| assignments is now ignored. More information: <xref |
| linkend="dgui_misc_whitespace_stripping"/></para> |
| </listitem> |
| |
| <listitem> |
| <para>White-space stripping can be disabled for a single line |
| with the <link |
| linkend="ref.directive.nt"><literal>nt</literal></link> |
| directive (for No Trim).</para> |
| </listitem> |
| |
| <listitem> |
| <para>A new directive for the declarative XML processing: |
| <link |
| linkend="ref.directive.fallback"><literal>fallback</literal></link></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>freemarker.template.SimpleHash</literal> now |
| can wrap read-only <literal>Map</literal>-s, such as the map |
| of HTTP request parameters in Servlet API.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Preview 12 and Preview 11 |
| releases</title> |
| |
| <para>The only change between this and the previous preview |
| release is that Preview 11 had a bug where DOM trees would |
| <emphasis>never</emphasis> be garbage-collected.</para> |
| </section> |
| |
| <section> |
| <title>Differences between the Preview 11 and Preview 10 |
| releases</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Many XML related changes. Some of them are incompatible |
| with the previous preview releases! For a more detailed |
| explanation of how XML related features now work, see: <xref |
| linkend="xgui"/></para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Attention! Attribute queries such as |
| <literal>foo.@bar</literal> now return sequences |
| (similarly to child element queries and XPath queries), |
| not single nodes. Because of the rule with node sequences |
| of size 1, it is still good to write |
| <literal>${foo.@bar}</literal>, but built-ins such as |
| <literal>?exists</literal>, <literal>?if_exists</literal> |
| or <literal>?default</literal> don't work as before. For |
| example, instead of |
| <literal>foo.@bar?default('black')</literal>, you now have |
| to write <literal>foo.@bar[0]?default('black')</literal>. |
| So if you have used existence built-ins with attributes, |
| you have to find those occurrences in the templates and |
| add that <literal>[0]</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Attention! XML name-space handling has been totally |
| reworked and is absolutely incompatible with pre 10. Don't |
| worry about this if none of your XML input documents use |
| you use <literal>xmlns</literal> attributes. Worry, |
| though, if you have utilized the <quote>loose |
| mode</quote>, where only the local name of elements were |
| compared, because that's now gone. Sorry...</para> |
| </listitem> |
| |
| <listitem> |
| <para>Attention! Special-keys <literal>@@</literal> and |
| <literal>@*</literal> now return a sequence of attribute |
| nodes instead of the hash of them.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Several hash keys are now working for node sequences |
| that store multiple nodes. For example, to get the list of |
| all <literal>para</literal> elements of all |
| <literal>chapter</literal>-s, just write |
| <literal>doc.book.chapter.para</literal>. Or, to get list |
| of title attributes of all <literal>chapter</literal>-s |
| write <literal>doc.book.chapter.@title</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New special hash keys: <literal>**</literal>, |
| <literal>@@start_tag</literal>, |
| <literal>@@end_tag</literal>, |
| <literal>@@attribute_markup</literal>, |
| <literal>@@text</literal>, |
| <literal>@@qname</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>?parent</literal> for attribute nodes now |
| returns the element node the attribute node belongs |
| to.</para> |
| </listitem> |
| |
| <listitem> |
| <para>You can use Jaxen instead of Xalan for XPath |
| expressions, if you call the static |
| <literal>freemarker.ext.dom.NodeModel.useJaxenXPathSupport()</literal> |
| method once. We plan to use Jaxen automatically instead of |
| Xalan if it is available, just the Jaxen support is not |
| fully functional yet.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>New special variable: <literal>.vars</literal>. This is |
| useful to read top-level variables with square bracket syntax, |
| for example <literal>.vars["name-with-hyphens"]</literal> and |
| <literal>.vars[dynamicName]</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-in, <literal>eval</literal>, to evaluate a |
| string as FTL expression. For example |
| <literal>"1+2"?eval</literal> returns the number 3.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>FreemarkerServlet</literal> now uses the |
| configuration's <literal>locale</literal> setting, rather than |
| <literal>Locale.getDefault()</literal>, to set the locale of |
| the templates. Also, the signature of the |
| <literal>deduceLocale</literal> method has been |
| changed.</para> |
| </listitem> |
| |
| <listitem> |
| <para>We have a new (beta status) |
| <literal>CacheStorage</literal> implementation: |
| <literal>freemarker.cache.MruCacheStorage</literal>. This |
| cache storage implements a two-level Most Recently Used cache. |
| In the first level, items are strongly referenced up to the |
| specified maximum. When the maximum is exceeded, the least |
| recently used item is moved into the second level cache, where |
| they are softly referenced, up to another specified maximum. |
| You can plug to try it with <literal>cfg.setCacheStorage(new |
| freemarker.cache.MruCacheStorage(maxStrongSize, |
| maxSoftSize))</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Preview 10 and Preview 9 |
| releases</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The special key <literal>@@xmlns</literal> was removed |
| in favor of a new FTL directive for the same purpose, |
| <literal><#xmlns...></literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>By default, the system is stricter about the use of |
| namespace prefixes. In general, you must use a prefix to |
| qualify subelements that are associated with an XML |
| nampespace. You can do this with the new |
| <literal><#xmlns...></literal> directive, but prefixes |
| declared in the input XML doc will actually work with no |
| declaration.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Introduced a new special key called |
| <literal>@@text</literal> that returns all the text nodes |
| contained (recursively) in an element all concatenated |
| together.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Either Jaxen or Xalan can be used to provide XPath |
| functionality. Prior versions only worked with Xalan.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>FreemarkerServlet</literal> uses |
| <literal>ObjectWrapper.DEFAULT_WRAPPER</literal> by default |
| instead of <literal>ObjectWrapper.BEANS_WRAPPER</literal>. |
| What this means is that, by default, objects of type |
| <literal>java.lang.String</literal>, |
| <literal>java.lang.Number</literal>, |
| <literal>java.util.List</literal>, and |
| <literal>java.util.Map</literal> will be wrapped as |
| <literal>TemplateModels</literal> via the classes |
| <literal>SimpleScalar</literal>, |
| <literal>SimpleNumber</literal>, |
| <literal>SimpleSequence</literal>, and |
| <literal>SimpleHash</literal> respectively. Thus, the java |
| methods on those objects will not be available. The default |
| wrapper implementation in FreeMarker 2.3 automatically knows |
| how to wrap Jython objects, and also wraps |
| <literal>org.w3c.dom.Node</literal> objects into instances of |
| <literal>freemarker.ext.dom.NodeModel</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>FreemarkerServlet</literal> base |
| implementation no longer deduces the locale to use from the |
| HttpRequest.getLocale() hook. Rather, it simply delegates to a |
| <literal>deduceLocale()</literal> hook that is overridable in |
| subclasses. The base implementation simply uses |
| <literal>Locale.getDefault()</literal></para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Preview 9 and Preview 8 |
| releases</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Fixed bugs introduced with Preview 8: XPath, |
| <literal>@@markup</literal> and |
| <literal>@@nested_markup</literal> now works with the document |
| node.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Preview 8 and Preview 7 |
| releases</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>macro</literal> and assignment directives now |
| accept arbitrary destination variable name with quoted syntax. |
| For example: <literal><#macro |
| "foo-bar"><replaceable>...</replaceable></literal> or |
| <literal><#assign "this+that" = 123></literal>. This is |
| important, because XML element names can contain hyphen, and |
| it was not possible to define a handler macro for those |
| elements, till now.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Special key <literal>@@content</literal> was renamed to |
| <literal>@@nested_markup</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Fixed outdated XML related Manual parts (that were |
| outdated even in Preview 7).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Better parse-error messages.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Minor bugfixes here and there...</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Preview 7 and Preview 6 |
| releases</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Caching of XPath queries should lead to significant |
| performance improvements for XML processing, at least when |
| XPath is heavily used.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Refinements in handling of XML namespaces in the XML |
| processing functionality. The new |
| <literal>strict_namespace_handling</literal> setting |
| introduced in 2.3pre6 was removed. A general-purpose solution |
| was arrived at that should make that configuration setting |
| unnecessary.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Special key <literal>@xmlns</literal> was renamed to |
| @@xmlns. Reserved namespace prefix <literal>default</literal> |
| was renamed to <literal>@@default</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>ftl</literal> directive now accepts |
| non-string types.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New special keys were introduced for XML node wrappers |
| in the freemarker.ext.dom package. The |
| <literal>@@markup</literal> key returns the literal markup |
| that make up that element and the <literal>@@content</literal> |
| key returns all the element's markup excluding the opening and |
| closing tags.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Minor bugfixes here and there...</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Preview 6 and Preview 5 |
| releases</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Existence built-ins (<literal>?default</literal>, |
| <literal>?exists</literal>, etc.) now work with sequence sub |
| variables as well. Read the <link |
| linkend="ref.directive.default">documentation of the |
| <literal>default</literal> built-in</link> for more |
| information.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>matches</literal> built-in now returns a |
| sequence instead of a collection.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Refinements in handling of XML namespaces in the XML |
| processing functionality. A new setting, |
| <literal>strict_namespace_handling</literal> was introduced. |
| If this is set (it is off by default) any node-handling macro |
| used in with the visit/recurse machinery must be from a macro |
| library that declares in its ftl header that it handles the |
| namespace in question.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Minor bugfixes here and there...</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Preview 5 and Preview 4 |
| releases</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The <literal>replace</literal> and |
| <literal>split</literal> built-ins now support |
| case-insensitive comparison and regular expressions (J2SE 1.4+ |
| only), and some other new options. More information can be |
| found <link |
| linkend="ref_builtin_string_flags">here</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New butilt-in for regular expression matching (J2SE 1.4+ |
| only): <link |
| linkend="ref_builtin_matches"><literal>matches</literal></link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Minor bugfixes here and there...</para> |
| </listitem> |
| |
| <listitem> |
| <para>Manual: More browser-safe HTML-s. More updated |
| content.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Preview 4 and Preview 3 |
| releases</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bugfix: with multi-type variables, <literal>+</literal> |
| operator overload for hash type had higher precedence than the |
| precedence of some older overloads.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The API documentation was missing from the distribution |
| <literal>tar.gz</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Preview 3 and Preview 2 |
| releases</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>XML processing: Many various bugfixes, especially with |
| the declarative processing.</para> |
| </listitem> |
| |
| <listitem> |
| <para>XML processing: the <literal>namespace_uri</literal> |
| built-in, the <literal>xmlnsuri</literal> header parameter, |
| and the <literal>TemplateNodeModel.getNodeNamespace</literal> |
| method were renamed to <literal>node_namespace</literal> and |
| <literal>getNodeNamespace</literal> respectively.</para> |
| </listitem> |
| |
| <listitem> |
| <para>XML processing: Better documentation. Especially, note: |
| <xref linkend="xgui"/></para> |
| </listitem> |
| |
| <listitem> |
| <para>A new header parameter, <literal>strip_text</literal>, |
| that removes all top-level text from a template. See <link |
| linkend="ref.directive.ftl"><literal>ftl</literal> |
| directive</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Support for a variable number of macro parameters. If |
| the last parameter in a macro declaration ends with |
| <literal>...</literal>, all extra parameters passed to the |
| macro will be available via that parameter. For macros called |
| with positional parameters, the parameter will be a sequence. |
| For named parameters, the parameter will be a hash.</para> |
| </listitem> |
| |
| <listitem> |
| <para>For <literal>BeansWrapper</literal> generated models, |
| you can now use the <literal>${obj.method(args)}</literal> |
| syntax to invoke methods whose return type is |
| <literal>void</literal>. <literal>void</literal> methods now |
| return <literal>TemplateModel.NOTHING</literal> as their |
| return value.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Preview 2 and Preview 1 |
| releases</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The <literal>freemarker.ext.dom.NodeModel</literal> API |
| changed slightly. The <literal>setDocumentBuilder()</literal> |
| method was changed to |
| <literal>setDocumentBuilderFactory()</literal> because the |
| older scheme was not thread-safe. The |
| <literal>stripComments</literal> and |
| <literal>stripPIs</literal> methods are renamed to The |
| <literal>removeComments</literal> and |
| <literal>removePIs</literal>, and are fixed now. A new method, |
| <literal>simplify</literal> has been added.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The expressions <literal>as</literal>, |
| <literal>in</literal>, and <literal>using</literal> are now |
| keywords in the template language and cannot be used as |
| top-level variable names without square-bracket syntax (as |
| <literal>.vars["in"]</literal>). If, by some chance, you have |
| top-level variables that use one of these names, you will have |
| to rename them (or use the square-bracket syntax). Sorry for |
| the inconvenience.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>?new</literal> built-in, as it was |
| implemented, was a security hole. Now, it only allows you to |
| instantiate a java object that implements the |
| <literal>freemarker.template.TemplateModel</literal> |
| interface. If you want the functionality of the |
| <literal>?new</literal> built-in as it existed in prior |
| versions, make available an instance of the new |
| <literal>freemarker.template.utility.ObjectConstructor</literal> |
| class to your template.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal><#recurse></literal> directive was |
| broken. It did not work with a <literal>using</literal> |
| clause. This is now fixed.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_2_8"> |
| <title>2.2.8</title> |
| |
| <para>Date of release: 2004-June-15</para> |
| |
| <para>Bugfix and maintenance release.</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added a new special variable to print the FreeMarker |
| version number: <literal>version</literal>. See more <link |
| linkend="ref_specvar">in the reference...</link></para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The <literal>BeansWrapper</literal> has been improved to |
| prevent some security exceptions when introspecting.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: The <literal>FileTemplateLoader</literal> is now |
| more robust when it receives paths that are malformed according |
| the native file system. In the earlier version such paths |
| sometimes caused unexpected <literal>IOException</literal> that |
| aborted the searching for the template in further |
| <literal>FileTemplateLoader</literal>-s when you use the |
| <literal>MultiTemplateLoader</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Some parts of the FreeMarker code has been marked as |
| privileged code section, so you can grant extra privileges to |
| FreeMarker when you use a security manager (this is a |
| backporting from 2.3). See more <link |
| linkend="pgui_misc_secureenv">here...</link></para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Other changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Minor documentation fixes and improvements.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_2_7"> |
| <title>2.2.7</title> |
| |
| <para>Date of release: 2004-March-17</para> |
| |
| <para>Important bugfix release.</para> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bugfix: Fixing a fatal bug in the template cache that was |
| introduced with the latest cache <quote>bugfix</quote>. The |
| template cache has always reloaded the unchanged template when |
| the update delay has been elapsed, until the template has been |
| actually changed, in which case it has never reloaded the |
| template anymore.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_2_6"> |
| <title>2.2.6</title> |
| |
| <para>Date of release: 2004-March-13</para> |
| |
| <para>Maintenance and bugfix release. Some of improvements are |
| back-portings from FreeMarker 2.3rc1.</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>New <link linkend="ref_specvar">special variable</link>: |
| <literal>.vars</literal>. This is useful to read top-level |
| variables with square bracket syntax, for example |
| <literal>.vars["name-with-hyphens"]</literal> and |
| <literal>.vars[dynamicName]</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-ins for Java and JavaScript string escaping: |
| <link linkend="ref_builtin_j_string">j_string</link> and <link |
| linkend="ref_builtin_js_string">js_string</link></para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bugfix: The template cache didn't reload the template when |
| it was replaced with an older version.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: |
| <literal>freemarker.template.utility.DeepUnwrap</literal> |
| unwrapped sequences to empty |
| <literal>ArrayList</literal>-s.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: In error messages, when the quoted FTL directive |
| had nested content, that was quoted as well, so the quotation |
| could be very long and expose nested lines needlessly.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>freemarker.template.TemplateExceptionHandler.HTML_DEBUG_HANDLER</literal> |
| now prints more HTML-context-proof messages.</para> |
| </listitem> |
| |
| <listitem> |
| <para>You can query the FreeMarker version number with static |
| method <literal>Configuration.getVersionNumber()</literal>. |
| Also, the <literal>Manifest.mf</literal> included in |
| <literal>freemarker.jar</literal> now contains the FreeMarker |
| version number, furthermore, executing it with <literal>java |
| -jar freemarker.jar</literal> will print the version number to |
| the stdout.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Date support is now labeled as final. (It was experimental |
| earlier.) There was no change since FreeMarker 2.2.1.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Other changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Fixes and improvements in the Manual and in the API |
| JavaDoc. The documentation now works with the Eclipse help |
| plugin (accessible in the <quote>Editor/IDE plugins</quote> |
| section of the FreeMarker Web page).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Minor site improvements.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_2_5"> |
| <title>2.2.5</title> |
| |
| <para>Date of release: 2003-09-19</para> |
| |
| <para>Maintenance and bugfix release.</para> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Creating a <literal>Configuration</literal> instance using |
| the default constructor no longer fails if the current directory |
| is unreadable due to I/O problems, lack of security permissions, |
| or any other exception.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_2_4"> |
| <title>2.2.4</title> |
| |
| <para>Date of release: 2003-09-03</para> |
| |
| <para>Maintenance and bugfix release.</para> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Improvements to JSP taglib support. If some third party |
| taglib didn't work for you with FreeMarker, maybe now it |
| will.</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The JSP <literal>PageContext</literal> now implements |
| <literal>forward</literal> and <literal>include</literal> |
| methods.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Accepting <literal>EVAL_PAGE</literal> as an alias to |
| <literal>SKIP_BODY</literal> in return values from |
| <literal>doStartTag</literal>. It's a common bug in some |
| widespread tag libraries, and now FreeMarker is less strict |
| and accepts it.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Fixes for some rare problems regarding namespaces of |
| macros.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Other changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Minor improvements to the documentation.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_2_3"> |
| <title>2.2.3</title> |
| |
| <para>Date of release: 2003-07-19</para> |
| |
| <para>Bugfix release.</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added the <literal>is_date</literal> built-in.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: Various <literal>is_xxx</literal> built-ins were |
| returning <literal>false</literal> when applied to undefined |
| expressions. Now they correctly fail on them.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bugfix: The JSP taglib support can now read JSP 1.2 |
| compliant TLD XML files.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: The JSP taglib support now emits more helpful |
| exception messages when the specified TLD XML file is not found |
| (previously it threw a |
| <literal>NullPointerException</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: The JSP taglib support now initializes a custom |
| tag after its parent and page context is set as some tags expect |
| them to be set when attribute setters are called.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: The <literal>BeansWrapper</literal> could fail to |
| analyze classes under very rare circumstances due to a premature |
| storage optimization.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_2_2"> |
| <title>2.2.2</title> |
| |
| <para>Date of release: 2003-05-02</para> |
| |
| <para>Bugfix release.</para> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bugfix: The <literal>_text</literal> key of the |
| <literal>freemarker.ext.xml.NodeListModel</literal> was not |
| returning the text of the element when used with W3C DOM |
| trees.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The classes are now built against JDK 1.2.2 classes, |
| ensuring the binary compatibility of FreeMarker distribution |
| with JDK 1.2.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_2_1"> |
| <title>2.2.1</title> |
| |
| <para>Date of release: 2003-04-11</para> |
| |
| <para>This version introduces important new features, such as the |
| native FTL date/time type, and the auto-include and auto-import |
| settings.</para> |
| |
| <para>The date/time support is experimental, but we hope it will not |
| substantially change. We would like to label it as final ASAP, so we |
| urge everybody to send feedback on this topic to the mailing |
| lists.</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>New scalar type: date. For more information read: <xref |
| linkend="dgui_datamodel_scalar"/>, <xref |
| linkend="dgui_datamodel_scalar"/>, <link |
| linkend="dgui_template_valueinserion_universal_date">interpolation</link>, |
| <link linkend="ref_builtin_string_for_date">?string built-in for |
| dates</link></para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>New <literal>TemplateModel</literal> subinterface: |
| <literal>TemplateDateModel</literal>. For more information read |
| <xref linkend="pgui_datamodel_scalar"/></para> |
| </listitem> |
| |
| <listitem> |
| <para>auto-include and auto-import: With these new configuration |
| level settings, you can include and import commonly used |
| templates (usually collection of macro definitions) at the top |
| of all templates, without actually typing <literal><#include |
| <replaceable>...</replaceable>></literal> or |
| <literal><#import |
| <replaceable>...</replaceable>></literal> into the templates |
| again and again. For more information please read the Java API |
| documentation of <literal>Configuration</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>New template method: |
| <literal>createProcessingEnvironment</literal>. This method |
| makes it possible for you to do some special initialization on |
| the <link |
| linkend="gloss.environment"><literal>Environment</literal></link> |
| before template processing, or to read the environment after |
| template processing. For more information please read the Java |
| API documentation.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Changes to <literal>freemarker.ext.beans</literal> |
| package: <literal>BeanModel</literal>, |
| <literal>MapModel</literal>, and |
| <literal>ResourceModel</literal> now implement |
| <literal>TemplateHashModelEx</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: |
| <literal>Configurable.setSettings(Properties)</literal> didn't |
| removed redundant spaces/tabs at the end of property |
| values.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_2"> |
| <title>2.2</title> |
| |
| <para>Date of release: 2003-03-27</para> |
| |
| <para>This release introduces some really important new features. |
| Unfortunately, evolution was painful again; we have a few non-backward |
| compatible changes (see below). Also, for those of you awaiting |
| desired native date/time type, sorry, it is still not here (because of |
| some internal chaos in the team... stand by, it's coming).</para> |
| |
| <section> |
| <title>Non backward-compatible changes!</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Macros are now plain variables. This means that if you are |
| unlucky and you have both a macro and another variable with the |
| same name, now the variable will overwrite the macro, so your |
| old template will malfunction. If you have a collection of |
| common macros, you should use the new <link |
| linkend="dgui_misc_namespace">namespace feature</link> to |
| prevent accidental clashes with the variables used in the |
| templates.</para> |
| </listitem> |
| |
| <listitem> |
| <para>With the introduction of the new <link |
| linkend="dgui_misc_namespace">namespace support</link>, |
| <literal>global</literal> and <literal>assign</literal> |
| directives are no longer synonyms. <literal>assign</literal> |
| creates a variable in the current <literal>namespace</literal>, |
| while <literal>global</literal> creates variable that is visible |
| from all namespaces (as if the variable would be in the |
| data-model). Thus, the variable created with |
| <literal>assign</literal> is more specific, and hides the |
| variable of the same name created with |
| <literal>global</literal>. As a result, if you use both |
| <literal>global</literal> and <literal>assign</literal> mixed |
| for the same variable in your templates, now they will |
| malfunction. The solution is to search-and-replace all |
| <literal>global</literal>s in your old templates with |
| <literal>assign</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The reserved hash <literal>root</literal> no longer exists |
| as a predefined variable (we no longer have reserved variables). |
| Use <link linkend="dgui_template_exp_var_special">special |
| variable expressions</link> to achieve similar effects. However, |
| we have no equivalent replacement for <literal>root</literal> |
| because of the changes in the variable scopes caused by the |
| introduction of namespaces. You may should use |
| <literal>.globals</literal> or |
| <literal>.namespace</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>BeansWrapper</literal> no longer exposes |
| native Java arrays, booleans, numbers, enumerations, iterators, |
| and resource bundles as <literal>TemplateScalarModel</literal>. |
| This way, number objects wrapped through |
| <literal>BeansWrapper</literal> are subject to FreeMarker's |
| number formatting machinery. Also, booleans can be formatted |
| using the <literal>?string</literal> built-in.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The signature of |
| <literal>Configuration.setServletContextForTemplateLoading</literal> |
| has been changed: the first parameter is now |
| <literal>Object</literal> instead of |
| <literal>javax.servlet.ServletContext</literal>. Thus, you have |
| to recompile your classes that call this method. The change was |
| required to prevent class-loading failure when |
| <literal>javax.servlet</literal> classes are not available and |
| you would not call this method.</para> |
| </listitem> |
| |
| <listitem> |
| <para>This release introduces a <link |
| linkend="dgui_misc_whitespace">parse-time white-space |
| remover</link> that strips some of the typical superfluous |
| white-space around FreeMarker tags and comments. <emphasis>This |
| feature is on by default!</emphasis> Most probably this will not |
| cause problems if you generate white-space neutral output like |
| HTML. But if it does cause undesirable reformatting in output |
| you generate, you can disable it with |
| <literal>config.setWhitespaceStripping(false)</literal>. Also, |
| you can enable/disable it on a per-template basis with the new |
| <link linkend="ref.directive.ftl"><literal>ftl</literal></link> |
| directive.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Some new directives were introduced: |
| <literal>nested</literal>, <literal>import</literal>, |
| <literal>escape</literal>, <literal>noescape</literal>, |
| <literal>t</literal>, <literal>rt</literal>, |
| <literal>lt</literal>. This means that if you are unlucky and |
| the text of your template contains something like |
| <literal><nested></literal>, then that will be |
| misinterpreted as a directive. To prevent this kind of problem |
| in the future, we recommend everybody to switch from the old |
| syntax to the new syntax (<quote>strict syntax</quote>). The |
| strict syntax will be the the default syntax starting from some |
| of the later releases anyway. We plan to release a conversion |
| tool for converting old templates. For more information please |
| read: <xref linkend="ref_depr_oldsyntax"/></para> |
| </listitem> |
| |
| <listitem> |
| <para>The data-model created by the |
| <literal>FreemarkerServlet</literal> now uses automatic scope |
| discovery, so writing |
| <literal>Application.<replaceable>attrName</replaceable></literal>, |
| <literal>Session.<replaceable>attrName</replaceable></literal>, |
| <literal>Request.<replaceable>attrName</replaceable></literal> |
| is no longer mandatory; it's enough to write |
| <literal><replaceable>attrName</replaceable></literal> (for more |
| information <link linkend="topic.servlet.scopeAttr">read |
| this</link>). This may break an old template if that rely on the |
| non-existence of certain top-level variables.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>FreemarkerServlet</literal> now uses the encoding |
| of the template file for the output, unless you specify the |
| encoding in the <literal>ContentType</literal> init-param, such |
| as <literal>text/html; charset=UTF-8</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The format of template paths is now more restricted than |
| before. The path must not use <literal>/</literal>, |
| <literal>./</literal> and <literal>../</literal> and |
| <literal>://</literal> with other meaning as they have in URL |
| paths (or in UN*X paths). The characters <literal>*</literal> |
| and <literal>?</literal> are reserved. Also, the template loader |
| must not want paths starting with <literal>/</literal>. For more |
| information please read: <xref |
| linkend="pgui_config_templateloading"/></para> |
| </listitem> |
| |
| <listitem> |
| <para>Till now |
| <literal>TemplateTransformModel.getWriter</literal> has received |
| null as parameter map if the transform was called without |
| parameters. From now, it will receive an empty Map instead. Note |
| that the previous API documentation didn't state that it always |
| receives null if there are no parameters, so hopelessly only |
| very few classes exploit this design mistake.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes in FTL (FreeMarker Template Language)</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>User-defined directives: Transform and macro call syntax |
| has been unified; they can be called in the same way, as |
| user-defined directives. This also means that macros support |
| named parameters and nested content (like the -- now deprecated |
| -- <literal>transform</literal> directive did). For example, if |
| you have a macro called <literal>sect</literal>, you may call it |
| via <literal><@sect title="Blah" style="modern">Blah |
| blah...</@sect></literal>. For more information read: |
| <xref linkend="dgui_misc_userdefdir"/></para> |
| </listitem> |
| |
| <listitem> |
| <para>Macros are now plain variables. This significantly |
| simplifies FreeMarker semantics, while providing more |
| flexibility; for example you can pass macros as parameters to |
| other macros and transforms. As for the problem of clashing |
| commonly-used-macro and variable names, we provide a more |
| powerful solution: namespaces.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Namespaces: Names-spaces are invaluable if you want to |
| assemble collections (<quote>libraries</quote>) of macros and |
| transforms (and other variables), and then use them in any |
| template without worrying about accidental name clashes with the |
| application specific and temporary variables, or with the |
| variables of other collections you want to use in the same |
| template. This is extremely important if FreeMarker users want |
| to share their macro/transform collections. For more information |
| read: <xref linkend="dgui_misc_namespace"/></para> |
| </listitem> |
| |
| <listitem> |
| <para>With the introduction of namespaces our variable related |
| terminology changed. As a result, <literal>assign</literal> is |
| no longer synonymous with <literal>global</literal>. The |
| <literal>assign</literal> directive has been undeprecated, and |
| should be used instead of <literal>global</literal> almost |
| everywhere. In the new approach <literal>assign</literal> |
| creates variables in the current namespace, while |
| <literal>global</literal> creates a variable that is visible |
| from all namespaces (as if the variable were in the root of the |
| data-model). A variable created with <literal>assign</literal> |
| in the current namespace hides the variable of the same name |
| that was created with <literal>global</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>ftl</literal> directive: With this directive you |
| can give information about the template for FreeMarker, like the |
| encoding (charset) of the template, the used FTL syntax variant, |
| etc. Also, this directive helps you to write templates that are |
| less dependent on FreeMarker configuration settings, also it |
| helps third-party tools to identify and correctly parse |
| FreeMarker templates. For more information see: <link |
| linkend="ref.directive.ftl"><literal>ftl</literal> |
| directive</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>White-space stripping: FreeMarker now automatically |
| removes some of the typical superfluous white-spaces around |
| FreeMarker tags and comments, like the indentation spaces |
| before- and line-break after <literal><#if ...></literal> |
| tags. For more information read: <xref |
| linkend="dgui_misc_whitespace_stripping"/></para> |
| </listitem> |
| |
| <listitem> |
| <para>New directive to apply a common ("escaping") expression to |
| all interpolations in a block: <link |
| linkend="ref.directive.escape"><literal>escape</literal></link>. |
| The name comes from the common usage of this directive for |
| automatic HTML-escaping of interpolations.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The new and preferred way of number formatting with |
| <literal>string</literal> built-in is |
| <literal>foo?string(format)</literal>, instead of the less |
| natural <literal>foo?string[format]</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>string</literal> built-in works for boolean |
| values. For example: <literal>${spamFilter?string("enabled", |
| "disabled")}</literal>. For more information <link |
| linkend="ref_builtin_string_for_boolean">read the |
| reference</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The default strings for outputting boolean value using the |
| <literal>string</literal> built-in can be set using the |
| <literal>boolean_format</literal> setting.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Comments can be placed inside FTL tags and interpolations. |
| For example: <literal><#assign <#-- a comment --> x = |
| 3></literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>All letters and numbers are enabled in variable names, |
| also <literal>$</literal> is allowed (as in Java programming |
| language). Thus you can use accents, Arabic letters, Chinese |
| letters, etc.</para> |
| </listitem> |
| |
| <listitem> |
| <para>String literals can be quoted with apostrophe-quote. |
| <literal>"foo"</literal> and <literal>'foo'</literal> are |
| equivalent.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New <link linkend="ref_builtins_string">string |
| built-ins</link>: <literal>index_of</literal>, |
| <literal>last_index_of</literal>, |
| <literal>starts_with</literal>, <literal>ends_with</literal>, |
| <literal>replace</literal>, <literal>split</literal>, |
| <literal>chop_linebreak</literal>, |
| <literal>uncap_first</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New <link linkend="ref_builtins_sequence">sequence |
| built-ins</link>: <literal>sort</literal>, |
| <literal>sort_by</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-ins for experts to check the type of a variable. |
| See: <link |
| linkend="ref_builtin_isType"><literal>is_<replaceable>...</replaceable></literal> |
| built-ins</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-in for experts to create a variable of certain |
| Java <literal>TemplateModel</literal> implementation. See: <link |
| linkend="ref_builtin_new"><literal>new</literal> |
| built-in</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-in, <link |
| linkend="ref_builtin_namespace"><literal>namespace</literal></link>, |
| to get the namespace of a macro.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New expression type: special variable expression. To |
| prevent backward compatibility problems when we introduce new |
| predefined variables, from now <link |
| linkend="dgui_template_exp_var_special">special variable |
| expressions</link> are used to access them.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New directives: <literal>t</literal>, |
| <literal>rt</literal> and <literal>lt</literal> directives allow |
| you to do explicit white-space removal in extreme FTL |
| applications. For more information read <link |
| linkend="ref.directive.t">the reference</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>assign</literal>, <literal>local</literal> and |
| <literal>global</literal> now can capture the output generated |
| be the nested template fragment into the variable. This |
| deprecates <literal>capture_output</literal> transform. More |
| information: <link linkend="ref.directive.assign">assign |
| directive reference</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Bulk assignments (as <literal><#assign x=1, y=2, |
| z=3></literal>) no longer need colon to separate the |
| assignments (as <literal><#assign x=1 y=2 z=3></literal>), |
| although it is still allowed to preserve backward |
| compatibility.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Path that contains <literal>//:</literal> is considered as |
| absolute path.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>include</literal> and |
| <literal>transform</literal> directives no longer need a |
| semicolon to separate the template or transform name from the |
| parameter list, although it is still allowed to preserve |
| backward compatibility.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>#</literal>-less tag syntax is deprecated (but |
| still working). That is, you should write |
| <literal><#<replaceable>directive |
| ...</replaceable>></literal> instead of |
| <literal><<replaceable>directive |
| ...</replaceable>></literal>, and |
| <literal></#<replaceable>directive |
| ...</replaceable>></literal> instead of |
| <literal></<replaceable>directive |
| ...</replaceable>></literal>. For more info read: <xref |
| linkend="ref_depr_oldsyntax"/></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>foreach</literal> is depreciated (but still |
| working). Use <link |
| linkend="ref.directive.list"><literal>list</literal></link> |
| instead.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: Undefined variables in hash and sequence |
| constructors (as <literal>[a, b, c]</literal>) didn't caused |
| errors.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: String concatenation had performance problem if |
| there was multiple concatenations chained, as: |
| <literal>"a"+x+"a"+x+"a"+x+"a"+x+"a"+x</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Arbitrary JSP custom tags can be used as FreeMarker |
| transforms in <literal>FreemarkerServlet</literal>-driven |
| templates. More information: <xref |
| linkend="pgui_misc_servlet"/></para> |
| </listitem> |
| |
| <listitem> |
| <para>Various improvements for |
| <literal>BeansWrapper</literal>:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The <literal>BeansWrapper</literal> no longer exposes |
| arbitrary objects as |
| <literal>TemplateScalarModel</literal>s, only |
| <literal>java.lang.String</literal> and |
| <literal>Character</literal> objects. This way, number |
| objects wrapped through <literal>BeansWrapper</literal> are |
| subject to FreeMarker's number formatting machinery. As a |
| side effect, non-string and non-number objects that were |
| previously accepted in equality and inequality operations |
| (because they had a string representation) will now cause |
| the engine to throw exception on comparison attempt.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>java.lang.Character</literal> objects are |
| exposed as scalars through |
| <literal>BeansWrapper</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Experimental feature: With the |
| <literal>setSimpleMapWrapper</literal> method of |
| <literal>BeansWrapper</literal> you can configure it to wrap |
| <literal>java.util.Map</literal>-s as |
| <literal>TemplateHashModelEx</literal>-s, and do not expose |
| the methods of the object.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para><literal>TransformControl</literal> interface (was |
| experimental earlier): If the <literal>Writer</literal> returned |
| by <literal>TemplateTransformModel.getWriter</literal> |
| implements this interface, it can instruct the engine to skip or |
| to repeat evaluation of the nested content, and gets notified |
| about exceptions that are thrown during the nested content |
| evaluation. Note that the <literal>onStart</literal> and |
| <literal>afterBody</literal> methods now are allowed to throw |
| <literal>IOException</literal>. For more information please read |
| the API documentation.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Localized lookup can be disabled with the new |
| <literal>Configuration</literal> methods: |
| <literal>set/getLocalizedLookup</literal>, |
| <literal>clearTemplateCache</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>The new interface |
| <literal>freemarker.cache.CacheStorage</literal> allows users to |
| plug custom template caching strategies with the |
| <literal>cache_storage</literal> setting. The core package now |
| ships with two implementations: |
| <literal>SoftCacheStorage</literal> and |
| <literal>StrongCacheStorage</literal>. For more information |
| read: <xref linkend="pgui_config_templateloading"/></para> |
| </listitem> |
| |
| <listitem> |
| <para>You can set settings with string name and string value |
| with the new <literal>setSetting(String key, String |
| value)</literal> method of <literal>Configurable</literal> |
| super-classes (as <literal>Configuration</literal>). Also you |
| can load settings from <literal>.properties</literal> file with |
| the <literal>setSettings</literal> method.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Other new <literal>Configuration</literal> methods: |
| <literal>clearTemplateCache</literal>, |
| <literal>clearSharedVariables</literal>, |
| <literal>getTemplateLoader</literal>, and |
| <literal>clone</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Changes to <literal>TemplateTransformModel</literal> |
| interface: <literal>getWriter</literal> can throw |
| <literal>IOException</literal>, and can return |
| <literal>null</literal> if the transform does not support body |
| content.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Till now |
| <literal>TemplateTransformModel.getWriter</literal> has received |
| null as parameter map if the transform was called without |
| parameters. From now, it will receive an empty Map instead. Note |
| that the previous API documentation didn't state that it always |
| receives null if there are no parameters, so hopelessly only |
| very few classes exploit this design mistake.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Various improvements for |
| <literal>FreemarkerServlet</literal>:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The data-model now uses automatic scope discovery, so |
| writing |
| <literal>Application.<replaceable>attrName</replaceable></literal>, |
| <literal>Session.<replaceable>attrName</replaceable></literal>, |
| <literal>Request.<replaceable>attrName</replaceable></literal> |
| is no longer mandatory; it's enough to write |
| <literal><replaceable>attrName</replaceable></literal>. For |
| more information <link |
| linkend="topic.servlet.scopeAttr">read this</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>FreemarkerServlet</literal> now uses the |
| encoding of the template file for the output, unless you |
| specify the encoding in the <literal>ContentType</literal> |
| init-param, such as <literal>text/html; |
| charset=UTF-8</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>All <literal>Configuration</literal> level settings |
| can by set with Servlet init-params |
| (<literal>template_exception_handler</literal>, |
| <literal>locale</literal>, <literal>number_format</literal>, |
| etc.).</para> |
| </listitem> |
| |
| <listitem> |
| <para>The object wrapper the servlet internally uses is now |
| set as the default object wrapper for its |
| <literal>Configuration</literal> instance.</para> |
| </listitem> |
| |
| <listitem> |
| <para>It no longer forces session creation for requests that |
| don't belong to an existing session, improving |
| scalability.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>JDOM independent XML-wrapping: |
| <literal>freemarker.ext.xml.NodeListModel</literal> is a |
| re-implementation of |
| <literal>freemarker.ext.jdom.NodeListModel</literal> that does |
| not rely on JDOM; you don't need JDOM .jar anymore. The new |
| <literal>NodeListModel</literal> automatically uses W3C DOM, |
| dom4j, or JDOM, depending on which library is available (that |
| is, depending on what object do you pass to its |
| constructor).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: <literal>WebappTemplateLoader</literal>: Template |
| updating didn't worked correctly with Tomcat due the caching of |
| resources. Now <literal>WebappTemplateLoader</literal> tries to |
| access the resources directly as <literal>File</literal>, if it |
| is possible, thus bypasses the caching.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Various bug-fixes for |
| <literal>FreemarkerServlet</literal>:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The servlet now loads the correct template if it was |
| called through |
| <literal>RequestDispatcher.include</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The caching of <literal>HttpServletRequest</literal> |
| objects is now compliant with the servlet |
| specification.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>TemplateException</literal>s was suppressed |
| in certain situations resulting in half-rendered pages |
| without error message.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: FreeMarker didn't work if the |
| <literal>javax.servlet</literal> classes was not available, |
| because <literal>Configuration</literal> explicitly referred to |
| <literal>javax.servlet.ServletContext</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: classes may were not found if they was available |
| only in the <literal>WEB-INF</literal>, and FreeMarker tried to |
| load the class dynamically.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: the <literal>Template</literal> constructor (and |
| thus <literal>Configuration.getTemplate</literal>) sometimes |
| threw <literal>TokenMgrError</literal> (a non-checked exception) |
| instead of <literal>ParseException</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Other changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The Web application related examples has been |
| replaced.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>The history of the releases before the final version</title> |
| |
| <section> |
| <title>Differences between the final and RC2 releases</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>You can load settings from |
| <literal>.properties</literal> file with the |
| <literal>setSettings</literal> method of |
| <literal>Configuration</literal> and other |
| <literal>Configurable</literal> subclasses.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New string built-in: |
| <literal>uncap_first</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: When exposing an XML document to a template and |
| accessing it with XPath using Jaxen a |
| <literal>ClassCastException</literal> has occurred.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: The template cache has loaded templates with bad |
| <literal>Configuration</literal> instance in certain |
| situations if you use not the static default |
| <literal>Configuration</literal> instance.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the RC2 and RC1 releases</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Non backward compatible change!: |
| <literal>FreemarkerServlet</literal> now uses the encoding of |
| the template file for the output, unless you specify the |
| encoding in the <literal>ContentType</literal> init-param, |
| such as <literal>text/html; charset=UTF-8</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Non backward compatible change compared to RC1!: The |
| <literal>capture_output</literal> transform creates variable |
| in the current namespace (as <literal>assign</literal> |
| directive) with the <literal>var</literal> parameter, not a |
| global variable.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The new and preferred way of number formatting with |
| <literal>string</literal> built-in is |
| <literal>foo?string(format)</literal>, instead of the less |
| natural <literal>foo?string[format]</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>string</literal> built-in works for boolean |
| values. For example: <literal>${spamFilter?string("enabled", |
| "disabled")}</literal>. For more information <link |
| linkend="ref_builtin_string_for_boolean">read the |
| reference</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The default strings for outputting boolean value using |
| the <literal>string</literal> built-in can be set using the |
| <literal>boolean_format</literal> setting.</para> |
| </listitem> |
| |
| <listitem> |
| <para>String literals can be quoted with apostrophe-quote. |
| <literal>"foo"</literal> and <literal>'foo'</literal> are |
| equivalent.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The new interface |
| <literal>freemarker.cache.CacheStorage</literal> allows users |
| to plug custom template caching strategies with the |
| <literal>cache_storage</literal> setting. The core package now |
| ships with two implementations: |
| <literal>SoftCacheStorage</literal> and |
| <literal>StrongCacheStorage</literal>. For more information |
| read: <xref linkend="pgui_config_templateloading"/></para> |
| </listitem> |
| |
| <listitem> |
| <para>You can set settings with string name and string value |
| with the new <literal>setSetting(String key, String |
| value)</literal> method of <literal>Configurable</literal> |
| super-classes (as <literal>Configuration</literal>).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Other new <literal>Configuration</literal> methods: |
| <literal>getTemplateLoader</literal>, |
| <literal>clone</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>assign</literal>, <literal>local</literal> and |
| <literal>global</literal> now can capture the output generated |
| be the nested template fragment into the variable. This |
| deprecates <literal>capture_output</literal> transform. More |
| information: <link linkend="ref.directive.assign">assign |
| directive reference</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Other new <literal>Configuration</literal> methods: |
| <literal>getTemplateLoader</literal>, |
| <literal>clone</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Changes to <literal>TemplateTransformModel</literal> |
| interface: <literal>getWriter</literal> can throw |
| <literal>IOException</literal>, and can return |
| <literal>null</literal> if the transform does not support body |
| content.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Till now |
| <literal>TemplateTransformModel.getWriter</literal> has |
| received null as parameter map if the transform was called |
| without parameters. From now, it will receive an empty Map |
| instead. Note that the previous API documentation didn't state |
| that it always receives null if there are no parameters, so |
| hopelessly only very few classes exploit this design |
| mistake.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Changes to <literal>TemplateControl</literal> interface: |
| <literal>onStart</literal> and <literal>afterBody</literal> |
| methods are now allowed to throw |
| <literal>IOException</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Path that contains <literal>//:</literal> is considered |
| as absolute path.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New <link linkend="ref_builtins_string">string |
| built-ins</link>: <literal>index_of</literal>, |
| <literal>last_index_of</literal>, |
| <literal>starts_with</literal>, <literal>ends_with</literal>, |
| <literal>replace</literal>, <literal>split</literal>, |
| <literal>chop_linebreak</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New <link linkend="ref_builtins_sequence">sequence |
| built-ins</link>: <literal>sort</literal>, |
| <literal>sort_by</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>All <literal>Configuration</literal> level settings can |
| by set with Servlet init-params |
| (<literal>template_exception_handler</literal>, |
| <literal>locale</literal>, <literal>number_format</literal>, |
| etc.).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: classes may were not found if they was available |
| only in the <literal>WEB-INF</literal>, and FreeMarker tried |
| to load the class dynamically.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: <literal>setLocalizedLookup(false)</literal> of |
| <literal>Configuration</literal> was overridden when you have |
| called <literal>setTemplateLoader</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: String concatenation had performance problem if |
| there was multiple concatenations chained, as: |
| <literal>"a"+x+"a"+x+"a"+x+"a"+x+"a"+x</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: white-space stripping was not worked with tags |
| spanning over multiple lines.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: Removing several dependencies on JDK 1.3, so |
| FreeMarker can be build for JDK 1.2.2.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Preview 2 and RC1 releases</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>ftl</literal> is now stricter, and does not |
| allow custom parameters. To associate custom attributes to |
| templates, we may add a new directive later, if there is a |
| demand for it.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>escape</literal> directive does not affect |
| numerical interpolations |
| (<literal>#{<replaceable>...</replaceable>}</literal>) |
| anymore, as it has caused errors with string escapes as |
| <literal>?html</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>normalizeName</literal> method of |
| <literal>freemarker.cache.TemplateLoader</literal> has been |
| removed, because it has caused too many complications. |
| Instead, normalization happens on a single point in the |
| <literal>TempateCache</literal>. In consequence, FreeMarker is |
| now stricter about the format of template paths, as things |
| like <literal>/../</literal> are interpreted by the |
| core.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Experimental feature: With the |
| <literal>setSimpleMapWrapper</literal> method of |
| <literal>BeansWrapper</literal> you can configure it to wrap |
| <literal>java.util.Map</literal>-s as |
| <literal>TemplateHashModelEx</literal>-s, and do not expose |
| the methods of the object.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New <literal>Configuration</literal> methods: |
| <literal>set/getLocalizedLookup</literal>, |
| <literal>clearTemplateCache</literal>, |
| <literal>clearSharedVariables</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>More cleanups in the <literal>Environment</literal> |
| API.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Better JSP standard compliance: JSP page-scope variables |
| are the global variables that were created in the template |
| (not the variables of the data-model).</para> |
| </listitem> |
| |
| <listitem> |
| <para>JDOM independent XML-wrapping: |
| <literal>freemarker.ext.xml.NodeListModel</literal> is a |
| re-implementation of |
| <literal>freemarker.ext.jdom.NodeListModel</literal> that does |
| not rely on JDOM; you don't need JDOM .jar anymore. The new |
| <literal>NodeListModel</literal> automatically uses W3C DOM, |
| dom4j, or JDOM, depending on which library is available (that |
| is, depending on what object do you pass to its |
| constructor).</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: <literal>WebappTemplateLoader</literal>: |
| Template updating didn't worked correctly with Tomcat due the |
| caching of resources. Now |
| <literal>WebappTemplateLoader</literal> tries to access the |
| resources directly as <literal>File</literal>, if it is |
| possible, thus bypasses the caching.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: Templates loaded with |
| <literal>MultiTemplateLoader</literal> subclasses was removed |
| from the template cache after the template update delay has |
| elapsed (5 seconds by default) even if the template file was |
| unchanged. This can cause lot of extra load for a high-traffic |
| server if you have many templates or if the template update |
| delay was set to 0 second.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: Undefined variables in hash and sequence |
| constructors (as <literal>[a, b, c]</literal>) didn't caused |
| errors.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the Preview 1 and Preview 2 |
| releases</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>All 16-bit Unicode letters and numbers are allowed in |
| identifiers, as well as the <literal>$</literal> character (as |
| in Java programming language). Thus you can use accented |
| letters, Arabic letters, Chinese letters, etc. as identifiers |
| in templates</para> |
| </listitem> |
| |
| <listitem> |
| <para>Macros now can create loop variables for the nested |
| content. For more information <link |
| linkend="dgui_misc_userdefdir_loopvar">read |
| this</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New directives: <literal>t</literal>, |
| <literal>rt</literal> and <literal>lt</literal> directives |
| allow you to do explicit white-space removal in extreme FTL |
| applications. For more information read <link |
| linkend="ref.directive.t">the reference</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The syntax of assignment-with-namespace has changed from |
| <literal><#assign foo=123 namespace=myLib></literal>) to |
| <literal><#assign foo=123 in myLib></literal>, since the |
| previous syntax was confusing because its similarity to a |
| bulk-assignment.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bulk assignments (as <literal><#assign x=1, y=2, |
| z=3></literal>) no longer need colon to separate the |
| assignments (as <literal><#assign x=1 y=2 |
| z=3></literal>), although it is still allowed to preserve |
| backward compatibility.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Positional parameter passing is supported for macro |
| calls as shorthand form of normal named parameter passing. For |
| more details read <link |
| linkend="ref_directive_userDefined_positionalParam">read the |
| reference</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New built-in, <literal>namespace</literal>, to get the |
| namespace of the currently executing macro.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>TransformControl</literal> interface (was |
| experimental earlier): If the <literal>Writer</literal> |
| returned by |
| <literal>TemplateTransformModel.getWriter</literal> implements |
| this interface, it can instruct the engine to skip or to |
| repeat evaluation of the nested content, and gets notified |
| about exceptions that are thrown during the nested content |
| evaluation. For more information please read the API |
| documentation.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Jython wrapper can now wrap arbitrary Java objects, not |
| only <literal>PyObject</literal>-s. If an object is passed to |
| the wrapper that is neither a |
| <literal>TemplateModel</literal>, nor a |
| <literal>PyObject</literal>, it is first coerced into a |
| <literal>PyObject</literal> using Jython's own wrapping |
| machinery, and then wrapped into a |
| <literal>TemplateModel</literal> as any other |
| <literal>PyObject</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Some cleanups in the <literal>Environment</literal> |
| API.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The Web application related examples has been |
| replaced.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: Templates loaded with |
| <literal>URLTemplateLoader</literal> subclasses was removed |
| from the template cache after the template update delay has |
| elapsed (5 seconds by default) even if the template file was |
| unchanged. This can cause lot of extra load for a high-traffic |
| server if you have many templates or if the template update |
| delay was set to 0 second.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: <literal>FreeMarkerServlet</literal> has thrown |
| <literal>ServletException</literal> even if a debug |
| <literal>TemplateException</literal> handler was in use (so |
| you may got Error 500 page instead of debug |
| information).</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_1_5"> |
| <title>2.1.5</title> |
| |
| <para>Date of release: 2003-02-08</para> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bugfix: Fixed a bug that forced the cache to frequently |
| reload templates accessed through URL and multi template |
| loaders: Templates loaded with |
| <literal>URLTemplateLoader</literal> subclasses and |
| <literal>MultiTemplateLoader</literal> was removed from the |
| template cache after the template update delay has elapsed (5 |
| seconds by default) even if the template file was unchanged. |
| This can cause lot of extra load for a high-traffic server if |
| you have many templates or if the template update delay was set |
| to 0 second.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: Many anomalies in the |
| <literal>JythonWrapper</literal> were resolved, making the |
| integration with Jython much smoother: Jython wrapper can now |
| wrap arbitrary Java objects, not only |
| <literal>PyObject</literal>-s. If an object is passed to the |
| wrapper that is neither a <literal>TemplateModel</literal>, nor |
| a <literal>PyObject</literal>, it is first coerced into a |
| <literal>PyObject</literal> using Jython's own wrapping |
| machinery, and then wrapped into a |
| <literal>TemplateModel</literal> as any other |
| <literal>PyObject</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_1_4"> |
| <title>2.1.4</title> |
| |
| <para>Date of release: 2002-12-26</para> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bugfix: Log4J is now found when automatically discovering |
| the logging library to use.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: An exception is no longer thrown in the static |
| initializer of the <literal>Configuration</literal> if the |
| directory specified in the <literal>"user.dir"</literal> system |
| property is not readable.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_1_3"> |
| <title>2.1.3</title> |
| |
| <para>Date of release: 2002-12-09</para> |
| |
| <section> |
| <title>Changes on the FTL side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bugfix: <literal>cap_first</literal> built-in did what |
| <literal>double</literal> built-in does.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Other changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The official extension of FreeMarker template files is |
| <literal>ftl</literal> from now, not <literal>fm</literal>. |
| (This is the name of the template language; FTL, for FreeMarker |
| Template Language.) Of course you can use any extensions, since |
| FreeMarker does not deal with the file extension. But we |
| recommend <literal>ftl</literal> extension as default.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Web application examples got tweaked again, as under JDK |
| 1.4 a class in an explicit (named) package can no longer import |
| classes from the default (unnamed) package. Our webapp example |
| was using classes in the default package, they are now moved |
| into named packages.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_1_2"> |
| <title>2.1.2</title> |
| |
| <para>Date of release: 2002-11-28</para> |
| |
| <section> |
| <title>Changes in FTL (FreeMarker Template Language)</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>FreeMarkerServlet</literal> now has a setting for |
| the <literal>Content-Type</literal> header of the response, |
| defaulting to <literal>text/html</literal>. Previously it set no |
| content type, which made it not play nicely when integrated with |
| software that expected it (i.e. OpenSymphony SiteMesh).</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>FreeMarkerServlet</literal> now works correctly |
| when mapped to an URL extension instead of URL path |
| prefix.</para> |
| </listitem> |
| |
| <listitem> |
| <para>You can emulate <literal>include</literal> directive call |
| within Java code by calling |
| <literal>Environment.include(<replaceable>templateName</replaceable>, |
| <replaceable>charset</replaceable>, |
| <replaceable>parse</replaceable>)</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bugfix: When <literal>Template.process()</literal> was |
| called from another template processing, it set |
| <literal>currentEnvironment</literal> to null when it returned, |
| thus crashed the parent template processing.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: the <literal>_descendant</literal> key in JDOM |
| support incorrectly left the document root element out of the |
| result when applied to a Document node.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: because we incorrectly assumed certain behavior of |
| JDK 1.4 Beans introspector, calls to public interface methods on |
| non-public classes that implement the interface were causing |
| exceptions on JDK 1.4</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Other changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Various minor supplements to the manual.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Documentation HTML pages don't try to load the SourceForge |
| logo from the Internet anymore.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The default ant target is <literal>jar</literal>, not |
| <literal>dist</literal>.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_1_1"> |
| <title>2.1.1</title> |
| |
| <para>Date of release: 2002-11-04</para> |
| |
| <section> |
| <title>Changes in FTL (FreeMarker Template Language)</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Multi-type variables that are both string and number or |
| string and date are now output using their number or date value |
| instead of the string value when used in the |
| <literal>${...}</literal> interpolation. This practically makes |
| the string part of a string/number or a string/date variables |
| useless.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: operator <quote>or</quote> (<literal>||</literal>) |
| worked wrongly when its left operand was a composite expression |
| (e.g., the second <literal>||</literal> in <literal>false || |
| true || false</literal>; this was evaluated to |
| <literal>false</literal>, but it should be |
| <literal>true</literal>)</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: Less-than sign inside comments confused the FTL |
| parser (e.g. <literal><#-- blah < blah --></literal>); |
| it commented out everything after the problematic |
| comment.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: Comparing two numerical constants (e.g. <literal>3 |
| == 3</literal>) caused internal error in the FTL parser, and |
| aborted template processing with error.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Experimental date/time type support was removed, since it |
| seems that this initial implementation was misguided. FreeMarker |
| 2.2 will certainly support data/time.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Bugfix: <literal>Number</literal>s wrapped with |
| <literal>BEANS_WRAPPER</literal> was displayed with the |
| <literal>toString()</literal> method of wrapped object. Now they |
| are rendered according to the <literal>number_format</literal> |
| setting, because multi-type variables that are both string and |
| number are now output using their number value instead of the |
| string value.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Experimental date/time type support was removed, since it |
| seems that this initial implementation was misguided. FreeMarker |
| 2.2 will certainly support data/time.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_1"> |
| <title>2.1</title> |
| |
| <para>Date of release: 2002-10-17</para> |
| |
| <para>Templates and the Java API are <emphasis>not</emphasis> fully |
| compatible with 2.0 releases. You will need to revisit existing code |
| and templates, or use 2.1 for new projects only. Sorry for this |
| inconvenience; FreeMarker has undergone some revolutionary changes |
| since the 1.x series. We hope things will soon be sufficiently mature |
| for us to offer (almost) backward-compatible releases. Note that there |
| is a backward-compatibility flag that can be set via |
| <literal>Configuration.setClassicCompatible(true)</literal> that |
| causes the new FreeMarker to emulate most of FreeMarker 1.x's |
| quirks.</para> |
| |
| <section> |
| <title>Changes in FTL (FreeMarker Template Language)</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>More strict, reveals accidental mistakes in the templates, |
| prevents showing incorrect information when something went |
| wrong:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>An attempt to access an undefined variable causes an |
| error and aborts template processing (by default at least; |
| see later). In earlier versions undefined variables were |
| silently treated as empty (zero-length) strings. However, |
| you can handle undefined variables in the template with some |
| new built-ins. For example, |
| <literal>${foo?if_exists}</literal> is equivalent with the |
| <literal>${foo}</literal> of earlier versions. Another way |
| of looking at this is that null values no longer exist from |
| the viewpoint of a template designer. Anything referenced |
| must be a defined variable.</para> |
| |
| <para>Note however that the programmer can configure |
| FreeMarker so that it ignores certain errors (say, undefined |
| variables), and continues template processing by skipping |
| the problematic part. This <quote>loose</quote> policy |
| should be used only for sites that don't show critical |
| information.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New variable type: <link |
| linkend="gloss.boolean">boolean</link>. Conditions in |
| <literal>if</literal>/<literal>elseif</literal> and operands |
| of logical operators (<literal>&&</literal>, |
| <literal>||</literal>, <literal>!</literal>) must be |
| booleans. Empty strings are no longer treated as a logical |
| false.</para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>Local and global variables. More info: <xref |
| linkend="dgui_misc_var"/></para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Local variables for macros. You can create/replace |
| local variables in macro definition bodies with the <link |
| linkend="ref.directive.local"><literal>local</literal> |
| directive</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>You can create/replace global (non-local) variables |
| with the <link |
| linkend="ref.directive.global"><literal>global</literal> |
| directive</link></para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>The <link |
| linkend="ref.directive.include"><literal>include</literal></link> |
| directive now by default treats the passed filename as being |
| relative to the including template's path. To specify absolute |
| template paths, you now have to prepend them with a |
| slash.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <link |
| linkend="ref.directive.include"><literal>include</literal></link> |
| directive can now use the <emphasis>acquisition |
| algorithm</emphasis> (familiar from the Zope system) to look up |
| the template to include. Basically, if a template is not found |
| where it is looked up first, it is looked up in parent |
| directories. This is however not a default behavior, rather it |
| is triggered by a new syntactic element.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Strict syntax mode: Allows you to generate arbitrary SGML |
| (XML) without worrying about clashes with FreeMarker directives. |
| For more information read: <xref |
| linkend="ref_depr_oldsyntax"/></para> |
| </listitem> |
| |
| <listitem> |
| <para>Terse comments: you can use <literal><#-- |
| <replaceable>...</replaceable> --></literal> instead of |
| <literal><comment><replaceable>...</replaceable></comment></literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Directive that you can use to change the locale (and other |
| settings) inside the template: <link |
| linkend="ref.directive.setting"><literal>setting</literal></link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Directive to explicitly flush the output buffer: <link |
| linkend="ref.directive.flush"><literal>flush</literal></link></para> |
| </listitem> |
| |
| <listitem> |
| <para>The top-level (root) hash is available via the variable |
| <literal>root</literal>, which is now a reserved name.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The misnamed <literal>function</literal> directive has |
| been renamed to <literal>macro</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>String literals support various new <link |
| linkend="topic.escapeSequence">escape sequences</link>, |
| including UNICODE escapes |
| (<literal>\x<replaceable>CODE</replaceable></literal>)</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <link |
| linkend="ref.directive.compress"><literal>compress</literal></link> |
| directive is now more conservative in removing line |
| breaks.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Built-in to capitalize the first word: <link |
| linkend="ref_builtin_cap_first"><literal>cap_first</literal></link></para> |
| </listitem> |
| |
| <listitem> |
| <para>Built-in to generate on-the-fly templates: <link |
| linkend="ref_builtin_interpret"><literal>interpret</literal></link></para> |
| </listitem> |
| |
| <listitem> |
| <para><link |
| linkend="ref.directive.stop"><literal>stop</literal></link> |
| directive has an optional parameter to describe the reason of |
| termination</para> |
| </listitem> |
| |
| <listitem> |
| <para>Better error messages.</para> |
| </listitem> |
| |
| <listitem> |
| <para>New variable type: date. <emphasis>Date support is |
| experimental. It can change substantially in the future. Keep |
| this in mind if you use it.</emphasis></para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes on the Java side</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para><literal>ObjectWrapper</literal>: You can put |
| non-<literal>TemplateModel</literal> objects directly into |
| hashes, sequences and collections, and they will be |
| automatically wrapped with the appropriate |
| <literal>TemplateModel</literal> implementation. The API of |
| objects that are exposed to templates |
| (<literal>Simple<replaceable>XXX</replaceable></literal>) has |
| been changed according to this, for example in |
| <literal>SimpleHash</literal> the old <literal>put(String key, |
| TemplateModel value)</literal> is now <literal>put(String key, |
| Object object)</literal>. Also, you can pass any kind of object |
| as data-model to <literal>Template.process</literal>. The |
| alternative reflection based <literal>ObjectWrapper</literal> |
| can expose the members of any Java object automatically for the |
| designer. More information: <link |
| linkend="pgui_datamodel_objectWrapper">Object wrapping</link>, |
| <link linkend="pgui_misc_beanwrapper">Bean wrapper</link>, <link |
| linkend="pgui_misc_jythonwrapper">Jython wrapper</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>Configuration</literal> object was introduced |
| as a central point to hold all your FreeMarker-related global |
| settings, as well as commonly used variables that you want to |
| have available from any template. Also it encapsulates the |
| template cache and can be used to load templates. For more |
| information read <xref linkend="pgui_config"/>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>TemplateLoader</literal>: pluggable template |
| loader, separates caching from template loading</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>TemplateNumberModel</literal>-s do not control |
| their formatting anymore. They just store the data (i.e. a |
| number). Number formatting is done by the FreeMarker core based |
| on the <literal>locale</literal> and |
| <literal>number_format</literal> settings. This logic applies to |
| the new experimental date type as well.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>TemplateBooleanModel</literal> introduced: Only |
| objects that implements this interface can be used as a boolean |
| in true/false conditions. More info: <xref |
| linkend="pgui_datamodel_scalar"/></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>TemplateDateModel</literal> introduced: objects |
| that implements this interface are recognized as dates and can |
| be locale-sensitively formatted. <emphasis>Date support is |
| experimental in FreeMarker 2.1. It can change substantially in |
| the future. Keep this in mind if you use it.</emphasis></para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>TemplateModelRoot</literal> interface was |
| deprecated. As of FreeMarker 2.1, you can simply use any |
| instance of <literal>TemplateHashModel</literal> instead. This |
| actually is due to a significant architectural change. Variables |
| set or defined in a template are stored in a separate |
| <literal>Environment</literal> object that only exists while the |
| template is being rendered. Thus, the template doesn't modify |
| the root hash.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Changes to transformations</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Completely rewritten |
| <literal>TemplateTransformModel</literal> interface. More |
| flexible, and does not impose output holding. More |
| information: <xref |
| linkend="pgui_datamodel_directive"/></para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>transform</literal> directive now takes |
| an optional set of key/value pairs. <literal><transform |
| myTransform; |
| <replaceable>key1</replaceable>=<replaceable>value1</replaceable>, |
| <replaceable>key2</replaceable>=<replaceable>value2</replaceable> |
| <replaceable>...</replaceable>></literal>. More |
| information: <link |
| linkend="ref.directive.transform"><literal>transform</literal> |
| directive</link></para> |
| </listitem> |
| |
| <listitem> |
| <para>The transforms that ship with the FreeMarker core are |
| now available by default to all templates - i.e. |
| <literal><transform html_escape></literal> will invoke |
| the |
| <literal>freemarker.template.utility.HtmlEscape</literal> |
| transform. More information: <xref |
| linkend="pgui_config_sharedvariables"/></para> |
| </listitem> |
| </itemizedlist> |
| </listitem> |
| |
| <listitem> |
| <para>User-defined <literal>TemplateModel</literal> objects now |
| can access the runtime environment (read and set variables, get |
| the current locale, etc.) using an |
| <literal>Environment</literal> instance, which can be obtained |
| by the static |
| <literal>Environment.getCurrentEnvironment()</literal> method. |
| As a result, <literal>TemplateScalarModel.getAsString</literal> |
| has been changed: it has no locale parameter.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>TemplateExceptionHandler</literal>-s make it |
| possible to define your own rules on what to do when a runtime |
| error occurs (e.g. accessing a non existing variable) during |
| template processing. For example, you can abort template |
| processing (recommended for most sites), or skip the problematic |
| statement and continue template processing (similar to old |
| behavior). DebugMode has been removed, use |
| <literal>TemplateExceptionHandler.DEBUG_HANDLER</literal> or |
| <literal>HTML_DEBUG_HANDLER</literal> instead.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Logging: FreeMarker logs certain events (runtime errors |
| for example). For more information read <xref |
| linkend="pgui_misc_logging"/>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>SimpleIterator</literal> was removed, but we |
| provide a <literal>TemplateCollectionModel</literal> |
| implementation: <literal>SimpleCollection</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Arithmetic engine is pluggable |
| (<literal>Configuration.setArithmeticEngine</literal>). The core |
| distribution comes with two engines: |
| <literal>ArithmeticEngine.BIGDECIMAL_ENGINE</literal> (the |
| default) that converts all numbers to |
| <literal>BigDecimal</literal> and then operates on them, and |
| <literal>ArithmeticEngine.CONSERVATIVE_ENGINE</literal> that |
| uses (more-or-less) the widening conversions of Java language, |
| instead of converting everything to |
| <literal>BigDecimal</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Changes to <literal>freemarker.ext.beans</literal> |
| package: The JavaBeans adapter layer has suffered several major |
| changes. First, <literal>BeansWrapper</literal> is no longer a |
| static utility class - you can now create instances of it, and |
| every instance can have its own instance caching policy and |
| security settings. These security settings are also new - you |
| can now create JavaBeans wrappers that hide methods that are |
| considered unsafe or inappropriate in a templating environment. |
| By default, you can no longer call methods like |
| <literal>System.exit()</literal> from the template (although you |
| can manually turn off these safeguards). The |
| <literal>StaticModel</literal> and |
| <literal>StaticModels</literal> classes are gone; their |
| functionality is now replaced with the |
| <literal>BeansWrapper.getStaticModels()</literal> method.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>freemarker.ext.jython</literal> package: |
| FreeMarker can now directly use Jython objects as data-models |
| using the <link linkend="pgui_misc_jythonwrapper">Jython |
| wrapper</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Changes to <literal>freemarker.ext.jdom</literal> package: |
| The package now uses the <emphasis>Jaxen</emphasis> package |
| instead of its predecessor, the |
| <emphasis>werken.xpath</emphasis> package to evaluate XPath |
| expressions. Since <emphasis>Jaxen</emphasis> is a successor to |
| <emphasis>werken.xpath</emphasis>, this can be considered to be |
| an upgrade. As a consequence, namespace prefixes are now |
| recognized in XPath expressions and the overall XPath |
| conformance is better.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Better error reporting: If the processing of a template is |
| aborted by a <literal>TemplateException</literal> being thrown, |
| or using a <literal><#stop></literal> directive, |
| FreeMarker will now output an execution trace with line and |
| column numbers relative to the template source.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The output is written to a simple |
| <literal>Writer</literal>; no more |
| <literal>PrintWriter</literal>. This redesign causes FreeMarker |
| to no longer swallow <literal>IOException</literal>s during |
| template processing.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Various API cleanups, primarily the removing of |
| superfluous constructor and method overloads.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Other changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Documentation has been rewritten from scratch</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Differences between the RC1 and final release</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Added the support for date models and locale-sensitive |
| date formatting. <emphasis>Date support is experimental in |
| FreeMarker 2.1. It can change substantially in the future. Keep |
| this in mind if you use it.</emphasis></para> |
| </listitem> |
| |
| <listitem> |
| <para>Added the <literal>default</literal> built-in which makes |
| it possible to specify default values for undefined |
| expressions.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>SimpleIterator</literal> has been removed, |
| <literal>SimpleCollection</literal> has been introduced</para> |
| </listitem> |
| |
| <listitem> |
| <para>Arithmetic engine is pluggable. The core now contains two |
| arithmetic engines: |
| <literal>ArithmeticEngine.BIGDECIMAL_ENGINE</literal> and |
| <literal>ArithmeticEngine.CONSERVATIVE_ENGINE</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>BeansWrapper</literal> supports a new exposure |
| level: <literal>EXPOSE_NOTHING</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>Constants</literal> interface was removed. |
| <literal><replaceable>...</replaceable>_WRAPPER</literal> |
| constants have been moved from <literal>Constants</literal> to |
| <literal>ObjectWrapper</literal>, |
| <literal>EMPTY_STRING</literal> constant was moved to |
| <literal>TemplateScalarModel</literal>, |
| <literal>NOTHING</literal> constant was moved to |
| <literal>TemplateModel</literal>, <literal>TRUE</literal> and |
| <literal>FALSE</literal> constants were moved to |
| <literal>TemplateBooleanModel</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>JAVABEANS_WRAPPER</literal> was renamed to |
| <literal>BEANS_WRAPPER</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>Configuration.get</literal> and |
| <literal>put</literal>, <literal>putAll</literal> were renamed |
| to <literal>getSharedVariable</literal> and |
| <literal>setSharedVariable</literal>, |
| <literal>setAllSharedVariables</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>Configuration.getClassicCompatibility</literal>, |
| <literal>setClassicCompatibility</literal> were renamed to |
| <literal>isClassicCompatible</literal>, |
| <literal>setClassicCompatible</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>Template.process</literal> method overloads with |
| <literal>useReflection</literal> parameter was removed. But now |
| we have <literal>setObjectWrapper</literal> method in the |
| <literal>Configuration</literal>, so you can set the preferred |
| root-object wrapper there.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Some superfluous method overloads were removed; these |
| changes are backward compatible with RC1</para> |
| </listitem> |
| |
| <listitem> |
| <para>Various minor JavaDoc and Manual improvements</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: <literal>include</literal> directive has |
| calculated the base path of relative paths wrongly</para> |
| </listitem> |
| |
| <listitem> |
| <para>Bugfix: We have accidentally used a J2SE 1.3 class, but |
| FreeMarker 2.1 must able to run on J2SE 1.2</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_01"> |
| <title>2.01</title> |
| |
| <para>The main improvement is in error reporting. Now exceptions are |
| much more informative since they come with complete line number and |
| column information.</para> |
| |
| <para>The only API change between 2.0 and 2.01 was the elimination of |
| the CacheListener/CacheEvent API. Now, if the updating of a template |
| file fails, the exception is thrown back to the caller to handle. If |
| you want logging to occur when a template file is updated |
| successfully, you can override the logFileUpdate() method in |
| FileTemplateCache.</para> |
| </section> |
| |
| <section xml:id="versions_2_0"> |
| <title>2.0</title> |
| |
| <para>FreeMarker 2.0 final was released on 18 April 2002. The changes |
| with respect to the previous release, 2.0 RC3 are fairly minor.</para> |
| |
| <section> |
| <title>Bugfixes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>There were a couple of bugs in handling null values, where |
| Lazarus did not do the same thing as FreeMarker Classic. |
| Traditionally, in FreeMarker, nulls were treated as being |
| equivalent to an empty string in the appropriate context. At |
| this point, to the best of our knowledge, there is backward |
| compatibility with FreeMarker Classic in this respect.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Literal strings can now include line breaks. This was a |
| backward compatibility issue with FreeMarker Classic that has |
| been fixed.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes to the Template language</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>You can use the extra built-in of |
| <literal>myString?web_safe</literal> to convert a string to its |
| "web-safe" equivalent, where problematic characters such as |
| '<' are converted to &lt;.</para> |
| </listitem> |
| |
| <listitem> |
| <para>In displaying numbers with a fractional part, the |
| rendering apparatus now respects the decimal separator of the |
| template's locale, so that, for example, in continental Europe, |
| you would see 1,1 and in the U.S. locale, 1.1.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes to the API</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The <literal>getAsString()</literal> method in the |
| <literal>TemplateScalarModel</literal> interface now takes a |
| <literal>java.util.Locale</literal> as a parameter. For the most |
| part, this is a hook for later use. In the default |
| implementation, <literal>SimpleScalar</literal>, this parameter |
| is unused. If you are implementing this interface yourself, your |
| implementation may ignore the parameter. However, it will be |
| appealing for certain implementations.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The constructors of <literal>FileTemplateCache</literal> |
| have changed. If you are using an absolute directory on the file |
| system as the location of your templates, you need to pass in an |
| instance of <literal>java.io.File</literal> to indicate the |
| location. If you use the constructors that take a string, this |
| is taken to mean relative to the classloader classpath.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Miscellany</title> |
| |
| <para>The ant build script build.xml now contains a target that |
| builds a .war file containing the Hello, World and Guestbook |
| examples. It builds a fmexamples.war. For example, if you are using |
| Tomcat in its out-of-the-box configuration, you would place this |
| under <TOMCAT_HOME>/webapps and then you would use |
| http://localhost:8080/fmexamples/servlet/hello and |
| http://localhost:8080/fmexamples/servlet/guestbook for the Hello, |
| World and Guestbook examples respectively.</para> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_0RC3"> |
| <title>2.0 RC3</title> |
| |
| <para>FreeMarker 2.0 RC3 was released on 11 April 2002. This release |
| was primarily devoted to fixing bugs that were reported in RC2.</para> |
| |
| <section> |
| <title>Bug Fixes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Variables defined in an <include...> were not |
| available in the enclosing page. This has been fixed.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The JavaCC parser was not configured to handle Unicode |
| input correctly. Now, Unicode support is working.</para> |
| </listitem> |
| |
| <listitem> |
| <para>There was a bug when comparing a number with null. It |
| should have returned false, but threw an exception instead. This |
| has been fixed.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Changes to the Template Language</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The syntax of the include directive has changed. To |
| indicate an unparsed include file, you do as follows:</para> |
| |
| <programlisting role="template"><include "included.html" ; parsed="n" ></programlisting> |
| |
| <para>You can also indicate the encoding of the included file |
| this way:</para> |
| |
| <programlisting role="template"> <include "included.html" ; encoding="ISO-8859-5"></programlisting> |
| </listitem> |
| |
| <listitem> |
| <para>The built-in myString?trim was added for trimming the |
| leading and trailing white-space from strings.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>API changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The TemplateEventAdapter machinery was taken out. This was |
| never set up in a very useful manner and we anticipate that |
| version 2.1 will have more complete support for logging |
| events.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The template caching mechanism was streamlined and |
| simplified.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The FileTemplateCache can now be configured to load files |
| relative to a class loader, using the Class.getResource() call. |
| This allows templates to be bundled up in .jar files or in a |
| .war file for easy deployment of web-based apps.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_0RC2"> |
| <title>2.0 RC2</title> |
| |
| <para>FreeMarker 2.0 RC 2 was released on 4 April 2002. Here is a |
| summary of changes wrt to the first release.</para> |
| |
| <section> |
| <title>Changes to Template Language</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Certain built-in functionality is provided via a new |
| operator, '?'. Thus, <literal>myList?size</literal> provides the |
| number of elements in a list. Similarly, |
| <literal>myString?length</literal> provides the length of a |
| string, <literal>myString?upper_case</literal> puts the string |
| all in capital letters, and <literal>myHash?keys</literal> |
| provides a sequence containing the keys in the hash. See <xref |
| linkend="ref_builtins"/> for list of all available |
| built-ins.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Numerical comparisons can now be made using the "natural" |
| operators < and > but there are also "web-safe" |
| alternatives, such as <emphasis>\lt</emphasis> and |
| <emphasis>\gt</emphasis>, since the use of these characters may |
| confuse HTML editors and parsers. Note that these changed |
| between rc1 and rc2, they now start with a backslash. A little |
| asymmetry is the fact that if you use the natural greater-than |
| or greater-than-or-equals operators (i.e. > or >=) the |
| expression must be in parentheses. With any other operator, the |
| parentheses are optional.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Within an iteration loop -- i.e. a |
| <literal>foreach</literal> or a <literal>list</literal> block -- |
| the current count in the loop is available as the special |
| variable |
| <literal><replaceable>index</replaceable>_count</literal>. where |
| <replaceable>index</replaceable> is the name of the variable in |
| the iteration. A boolean variable called |
| <literal><replaceable>index</replaceable>_has_next</literal> is |
| also defined that indicates whether there are any more items in |
| the iteration after this one. Note that the index starts at |
| zero, so you will often be adding one to it in practice.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal><#break></literal> directive can now be |
| used to break out of a <literal><#foreach...></literal> or |
| a <literal><list...></literal> loop. (Prior to this |
| version, it only worked within a switch-case block.) There is a |
| new directive called <literal><#stop></literal> that, when |
| encountered, simply halts processing of the template. This can |
| be useful for debugging purposes.</para> |
| </listitem> |
| |
| <listitem> |
| <para>When invoking java methods that have been exposed to the |
| page, using the code in freemarker.ext.*, there are built-ins |
| that allow you to indicate the numerical type that you wish to |
| pass as the value. For instance, if you had two methods, one |
| that takes an int and another that takes a long, and you wanted |
| to pass in a value, you would have to specify which method. |
| <literal>myMethod(1?int)</literal> or |
| <literal>myMethod(1?long)</literal>. This is unnecessary if |
| there is only one method of the given name.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Ranges can be used to get the sublist from a list or the |
| substring of a string. For example: |
| <literal>myList[0..3]</literal> will return items 0 through 3 of |
| the list in question. Or, for example, you could get all the |
| elements of the list except for the first and last ones via: |
| <literal>myList[1..(myList?size-2)]</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Or we could get the first 6 characters of a string via |
| <literal>myString[0..5]</literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>Lists can be concatenated using the '+' operator. |
| Previously, this overloading of '+' only applied to |
| strings.</para> |
| </listitem> |
| |
| <listitem> |
| <para>An attempt to compare a number to a string now throws an |
| exception, since it is indicative of a coding error. Note that |
| there is a backward compatibility mode that can be set (see |
| below) that loosens this up in order to be able to process |
| legacy templates.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>API Changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The <literal>TemplateSequenceModel</literal> interface now |
| has a <literal>size()</literal> method for getting the number of |
| elements in the sequence in question.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>TemplateModelIterator</literal> interface now |
| has a <literal>hasNext()</literal> method.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The default sequence and hash implementations, |
| <literal>freemarker.template.SimpleSequence</literal> and |
| <literal>freemarker.template.SimpleHash</literal> are now |
| unsynchronized. If you need the methods to be synchronized, you |
| can get a synchronized wrapper via the |
| <literal>synchronizedWrapper()</literal> in either class.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>freemarker.utility.ExtendedList</literal> and |
| <literal>freemarker.utility.ExtendedHash</literal> classes were |
| removed, since all of the extra keys that it defined are now |
| available using the appropriate '?' built-in operation, i.e. |
| <literal>myHash?keys</literal> or <literal>myList?size</literal> |
| or <literal>myList?last</literal>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>There is a method in |
| <literal>java.freemarker.Configuration</literal> named |
| <literal>setDebugMode()</literal> which allows you to decide |
| whether stack traces are simply output to the web client (the |
| best situation in development) or thrown back to the caller to |
| be handled more gracefully (the best situation in |
| production).</para> |
| </listitem> |
| |
| <listitem> |
| <para>There is a flag that can be set to turn on a processing |
| mode that is more backward-compatible with FreeMarker Classic. |
| This is off by default, but you can set it via |
| <literal>Template.setClassicCompatibility(true)</literal>. What |
| this does is that it allows scalars to be treated as a |
| single-item list in a list directive. Also, it allows somewhat |
| more looseness about types. In FreeMarker 1.x, <literal><#if |
| x=="1"></literal> and <literal><#if x==1></literal> |
| were in fact equivalent. This meant that legacy templates might |
| tend to be slack about this. If classic compatibility is not |
| set, an attempt to compare the string "1" with the number 1 will |
| result in an exception being thrown. (Note that it is preferable |
| to get your templates working without the backward compatibility |
| flag, since it usually will require only minor changes. However, |
| for people with a lot of templates and no time to check over |
| them, this flag may be of use.)</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section xml:id="versions_2_0RC1"> |
| <title>2.0 RC1</title> |
| |
| <para>The first public release of FreeMarker 2.0 was on 18 March 2002. |
| Here is a summary of the changes in the Lazarus release, with respect |
| to the last stable release of FreeMarker Classic.</para> |
| |
| <para><emphasis>NOTA BENE</emphasis>:</para> |
| |
| <para>Despite the changes delineated above, the Lazarus release is |
| almost entirely backward-compatible with FreeMarker Classic. We |
| believe that <emphasis>most</emphasis> existing code and templates |
| that work under FreeMarker Classic will continue working under |
| Lazarus, with at most minimal changes. In practice, the most common |
| cases where legacy template code is broken will be where assumptions |
| were made about numbers and strings being equivalent. Note that in |
| FreeMarker 2, 2 + 2 does not result in "22". The String "1" and the |
| number 1 are entirely different animals and thus, any code will be |
| broken if it relies on the boolean expression ("1"==1) being true. |
| There is a "classic compatibility mode" that can be set via: |
| <literal>Template.setClassCompatibility()</literal> that can be set so |
| that Lazarus emulates some of the quirky behavior of FreeMarker |
| Classic. However, any code that relied on the above "features" of |
| FreeMarker classic really should be reworked. You are less likely to |
| run into the other incompatibilities that are listed above. If you |
| come across any other anomalies, please do tell us about them.</para> |
| |
| <section> |
| <title>Support for Numerical operations, both arithmetic and |
| boolean, as well as numerical ranges.</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Scalars can now be either strings or numbers. (In |
| FreeMarker Classic all scalars were strings.) The basic |
| operations allowed are addition, subtraction, multiplication, |
| division, and modulus using the <literal>+</literal>, |
| <literal>-</literal>, <literal>*</literal>, |
| <literal>/</literal>, and <literal>%</literal> operators |
| respectively. Arbitrary-precision arithmetic with integers and |
| floating point numbers are provided. Though our goal is |
| definitely to follow the principle of least surprise, for |
| backward compatibility, the <literal>+</literal> operator still |
| is used for string concatenation. If either the left hand side |
| or the right hand side of <literal>lhs + rhs</literal> is |
| non-numerical, we revert to interpreting this as string |
| concatenation. Thus, in FreeMarker 2, 2+2 evaluates to the |
| number 4, while any of "2"+2 or 2+"2" or "2"+"2" evaluate to the |
| string "22". In FreeMarker Classic, rather embarrassingly, all |
| of the above, including 2+2, evaluated to the string "22". An |
| attempt to use any other arithmetic operator besides the |
| <literal>+</literal> with non-numerical operands will cause an |
| exception to be thrown.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Output of a numerical expression can be made explicit via |
| the alternative <literal>#{....}</literal> syntax. If the |
| expression within the curly parentheses does not evaluate to a |
| numerical value, an exception is thrown. The older ${....} |
| syntax can evaluate to either a number or a string. In general, |
| if, for logical reasons, the output <emphasis>must</emphasis> be |
| numerical, it is preferable to use the #{...} syntax, since it |
| adds an extra sanity check. Note that if, by some miracle, the |
| character sequence "#{" occurs in your template, you will have |
| to use a workaround to prevent problems. (The <noparse> |
| directive is one possibility.)</para> |
| </listitem> |
| |
| <listitem> |
| <para>In this release, there is a facility for specifying the |
| number of digits to show after the decimal point. The following |
| code specifies to show at least 3 digits after the decimal point |
| but not more than 6. This is optional. This option is only |
| available if you use the #{...} syntax.</para> |
| |
| <programlisting role="template">#{foo + bar ; m3M6} </programlisting> |
| |
| <para>(Note that the above is something of a stopgap measure. |
| Future releases will move toward supporting fully |
| internationalization and localization of number and currency |
| formatting.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Numerical expressions can be used in boolean expressions |
| via the comparison operators: <literal>lt</literal>, |
| <literal>gt</literal>, <literal>lte</literal>, and |
| <literal>gte</literal>. In the web space, where FreeMarker is |
| most used in practice, using the more natural operators such as |
| < and > would tend to confuse HTML-oriented editors. An |
| attempt to compare non-numerical expressions using these |
| operators leads to a <literal>TemplateException</literal> being |
| thrown. If, by some coincidence, you have variables named "lt", |
| "gt", "lte", or "gte", you will have to change their names, |
| since they are now keywords in the language.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Numerical ranges are supported.</para> |
| |
| <programlisting role="template"><#list 1990..2001 as year> |
| blah blah in the year ${year} blah |
| </#list> </programlisting> |
| |
| <para>The left hand and right hand sides of the |
| <literal>..</literal> operator must be numerical, or an |
| exception is thrown. They also need not be literal numbers, but |
| can be more complex expressions that evaluate to a numerical |
| scalar value. Note that it is also possible to write a range |
| that descends in value:</para> |
| |
| <programlisting role="template"><#list 2001..1990 as year> |
| blah blah in the year ${year} blah blah |
| </#list> </programlisting> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>API Changes</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The <literal>TemplateNumberModel</literal> interface and |
| the <literal>SimpleNumber</literal> implementation were added to |
| support exposing numerical values.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The <literal>TemplateListModel</literal> API in FreeMarker |
| Classic had some design problems -- particularly in terms of |
| supporting thread-safe code. It has been deprecated in favor of |
| the following API's: <literal>TemplateCollectionModel</literal> |
| and <literal>TemplateSequenceModel</literal>. The |
| <literal>SimpleList</literal> class was refactored to implement |
| the above interfaces (and paradoxically, does not implement the |
| TemplateListModel interface.) Code that uses the deprecated |
| <literal>TemplateListModel</literal> should be |
| refactored.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The Expose Package by Attila Szegedi has been made an |
| integral part of the FreeMarker distribution and is now under |
| the freemarker.ext.* hierarchy. This package provides advanced |
| models for representing arbitrary Java objects as template |
| models, for representing XML documents as template models, as |
| well as classes to facilitate the integration of FreeMarker with |
| servlets and Ant.</para> |
| </listitem> |
| |
| <listitem> |
| <para>In FreeMarker Classic, there were some utility classes |
| such as <literal>freemarker.template.utility.Addition</literal> |
| etcetera that existed as workarounds for the lack of numerical |
| operations in FreeMarker. Those have been removed and will |
| probably not be missed.</para> |
| </listitem> |
| |
| <listitem> |
| <para>In FreeMarker Classic, the <literal>SimpleScalar</literal> |
| object was mutable, it had a <literal>setValue</literal> method. |
| This was fairly obviously a design mistake. Any code that relied |
| on this must be refactored. Note that in this release, both |
| <literal>SimpleScalar</literal> and the newly introduced |
| <literal>SimpleNumber</literal> are both immutable and |
| final.</para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| |
| <section> |
| <title>Syntactical Miscellany</title> |
| |
| <itemizedlist> |
| <listitem> |
| <para>The if-elseif-else syntax was introduced. FreeMarker |
| classic only had if-else. This construct should probably (in the |
| opinion of the author of this document -- Revusky) be used in |
| preference to switch-case since the switch-case with |
| fall-through is a notoriously error-prone construct for most |
| mortal men.</para> |
| </listitem> |
| |
| <listitem> |
| <para>You can now do a multiple assignment in one |
| <assign...> directive. For example: <literal><assign x |
| = 1, y = price*items, message="foo"></literal></para> |
| </listitem> |
| |
| <listitem> |
| <para>A scalar will no longer be interpreted as a one-item list |
| in a <list...> or <#foreach...> block. If you have |
| code that relied on this feature, there is an easy workaround, |
| since you can simply define a list literal with exactly one |
| item.</para> |
| |
| <programlisting role="template"> <assign y=[x]> |
| <emphasis>and then...</emphasis> |
| <list y as item>...</list> </programlisting> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| </appendix> |
| |
| <appendix xml:id="app_install"> |
| <title>Installing FreeMarker</title> |
| |
| <indexterm> |
| <primary>install</primary> |
| </indexterm> |
| |
| <para>No real installation is needed. Simply ensure that |
| <literal>freemarker.jar</literal> is somewhere where your Java |
| application's class-loader will find it. In web application this usually |
| means putting <literal>freemarker.jar</literal> into the |
| <literal>WEB-INF/lib</literal> directory of your web application. (If |
| you want to use FreeMarker with JSP Model-2 style (which also means that |
| you can use custom JSP taglibs in the templates), some extra steps |
| needed. For more information please see <link |
| linkend="pgui_misc_servlet">the chapter about servlets</link>.)</para> |
| |
| <para>FreeMarker has no required dependencies. But to use certain |
| <emphasis>optional</emphasis> FreeMarker features, the related party |
| libraries have to be available for the class-loader:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Jaxen (recommended, <link |
| xlink:href="http://jaxen.org/">download here</link>) or Apache Xalan |
| is needed for XML XPath support. Please use at least Jaxen |
| 1.1-beta-8, not older versions! Apache Xalan classes are included in |
| a package-relocated form in Sun/Oracle J2SE 1.4-1.8 (maybe later |
| too), and FreeMarker will use those if it doesn't find Jaxen or |
| Xalan elsewhere. But as Oracle can change these internal packages |
| anytime, it's still recommended to use an external Jaxen or |
| Xalan.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Obviously, <literal>javax.servlet</literal> classes are needed |
| for <literal>FreemarkerServlet</literal>. Servlet version 2.2 or |
| later is needed.</para> |
| </listitem> |
| |
| <listitem> |
| <para>For the custom JSP taglib support, you will need JSP 2.0 API |
| or later avilable. No JSP implementation is needed, just the API. |
| This is already present in pretty much every servlet container. For |
| more information please see <link linkend="pgui_misc_servlet">the |
| chapter about servlets</link>.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Jython 2.0 or later classes are needed for the Jython |
| wrapper.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Pre-1.0 JDOM is needed for the long deprecated |
| <literal>freemarker.ext.jdom</literal> package. (When it was |
| created, there was no JDOM 1.0 yet.)</para> |
| </listitem> |
| </itemizedlist> |
| </appendix> |
| |
| <appendix xml:id="app_legal"> |
| <title>Legal</title> |
| |
| <section xml:id="app_license"> |
| <title>License</title> |
| |
| <indexterm> |
| <primary>license</primary> |
| </indexterm> |
| |
| <programlisting role="unspecified"> |
| Apache License |
| Version 2.0, January 2004 |
| http://www.apache.org/licenses/ |
| |
| TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
| |
| 1. Definitions. |
| |
| "License" shall mean the terms and conditions for use, reproduction, |
| and distribution as defined by Sections 1 through 9 of this document. |
| |
| "Licensor" shall mean the copyright owner or entity authorized by |
| the copyright owner that is granting the License. |
| |
| "Legal Entity" shall mean the union of the acting entity and all |
| other entities that control, are controlled by, or are under common |
| control with that entity. For the purposes of this definition, |
| "control" means (i) the power, direct or indirect, to cause the |
| direction or management of such entity, whether by contract or |
| otherwise, or (ii) ownership of fifty percent (50%) or more of the |
| outstanding shares, or (iii) beneficial ownership of such entity. |
| |
| "You" (or "Your") shall mean an individual or Legal Entity |
| exercising permissions granted by this License. |
| |
| "Source" form shall mean the preferred form for making modifications, |
| including but not limited to software source code, documentation |
| source, and configuration files. |
| |
| "Object" form shall mean any form resulting from mechanical |
| transformation or translation of a Source form, including but |
| not limited to compiled object code, generated documentation, |
| and conversions to other media types. |
| |
| "Work" shall mean the work of authorship, whether in Source or |
| Object form, made available under the License, as indicated by a |
| copyright notice that is included in or attached to the work |
| (an example is provided in the Appendix below). |
| |
| "Derivative Works" shall mean any work, whether in Source or Object |
| form, that is based on (or derived from) the Work and for which the |
| editorial revisions, annotations, elaborations, or other modifications |
| represent, as a whole, an original work of authorship. For the purposes |
| of this License, Derivative Works shall not include works that remain |
| separable from, or merely link (or bind by name) to the interfaces of, |
| the Work and Derivative Works thereof. |
| |
| "Contribution" shall mean any work of authorship, including |
| the original version of the Work and any modifications or additions |
| to that Work or Derivative Works thereof, that is intentionally |
| submitted to Licensor for inclusion in the Work by the copyright owner |
| or by an individual or Legal Entity authorized to submit on behalf of |
| the copyright owner. For the purposes of this definition, "submitted" |
| means any form of electronic, verbal, or written communication sent |
| to the Licensor or its representatives, including but not limited to |
| communication on electronic mailing lists, source code control systems, |
| and issue tracking systems that are managed by, or on behalf of, the |
| Licensor for the purpose of discussing and improving the Work, but |
| excluding communication that is conspicuously marked or otherwise |
| designated in writing by the copyright owner as "Not a Contribution." |
| |
| "Contributor" shall mean Licensor and any individual or Legal Entity |
| on behalf of whom a Contribution has been received by Licensor and |
| subsequently incorporated within the Work. |
| |
| 2. Grant of Copyright License. Subject to the terms and conditions of |
| this License, each Contributor hereby grants to You a perpetual, |
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
| copyright license to reproduce, prepare Derivative Works of, |
| publicly display, publicly perform, sublicense, and distribute the |
| Work and such Derivative Works in Source or Object form. |
| |
| 3. Grant of Patent License. Subject to the terms and conditions of |
| this License, each Contributor hereby grants to You a perpetual, |
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
| (except as stated in this section) patent license to make, have made, |
| use, offer to sell, sell, import, and otherwise transfer the Work, |
| where such license applies only to those patent claims licensable |
| by such Contributor that are necessarily infringed by their |
| Contribution(s) alone or by combination of their Contribution(s) |
| with the Work to which such Contribution(s) was submitted. If You |
| institute patent litigation against any entity (including a |
| cross-claim or counterclaim in a lawsuit) alleging that the Work |
| or a Contribution incorporated within the Work constitutes direct |
| or contributory patent infringement, then any patent licenses |
| granted to You under this License for that Work shall terminate |
| as of the date such litigation is filed. |
| |
| 4. Redistribution. You may reproduce and distribute copies of the |
| Work or Derivative Works thereof in any medium, with or without |
| modifications, and in Source or Object form, provided that You |
| meet the following conditions: |
| |
| (a) You must give any other recipients of the Work or |
| Derivative Works a copy of this License; and |
| |
| (b) You must cause any modified files to carry prominent notices |
| stating that You changed the files; and |
| |
| (c) You must retain, in the Source form of any Derivative Works |
| that You distribute, all copyright, patent, trademark, and |
| attribution notices from the Source form of the Work, |
| excluding those notices that do not pertain to any part of |
| the Derivative Works; and |
| |
| (d) If the Work includes a "NOTICE" text file as part of its |
| distribution, then any Derivative Works that You distribute must |
| include a readable copy of the attribution notices contained |
| within such NOTICE file, excluding those notices that do not |
| pertain to any part of the Derivative Works, in at least one |
| of the following places: within a NOTICE text file distributed |
| as part of the Derivative Works; within the Source form or |
| documentation, if provided along with the Derivative Works; or, |
| within a display generated by the Derivative Works, if and |
| wherever such third-party notices normally appear. The contents |
| of the NOTICE file are for informational purposes only and |
| do not modify the License. You may add Your own attribution |
| notices within Derivative Works that You distribute, alongside |
| or as an addendum to the NOTICE text from the Work, provided |
| that such additional attribution notices cannot be construed |
| as modifying the License. |
| |
| You may add Your own copyright statement to Your modifications and |
| may provide additional or different license terms and conditions |
| for use, reproduction, or distribution of Your modifications, or |
| for any such Derivative Works as a whole, provided Your use, |
| reproduction, and distribution of the Work otherwise complies with |
| the conditions stated in this License. |
| |
| 5. Submission of Contributions. Unless You explicitly state otherwise, |
| any Contribution intentionally submitted for inclusion in the Work |
| by You to the Licensor shall be under the terms and conditions of |
| this License, without any additional terms or conditions. |
| Notwithstanding the above, nothing herein shall supersede or modify |
| the terms of any separate license agreement you may have executed |
| with Licensor regarding such Contributions. |
| |
| 6. Trademarks. This License does not grant permission to use the trade |
| names, trademarks, service marks, or product names of the Licensor, |
| except as required for reasonable and customary use in describing the |
| origin of the Work and reproducing the content of the NOTICE file. |
| |
| 7. Disclaimer of Warranty. Unless required by applicable law or |
| agreed to in writing, Licensor provides the Work (and each |
| Contributor provides its Contributions) on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| implied, including, without limitation, any warranties or conditions |
| of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
| PARTICULAR PURPOSE. You are solely responsible for determining the |
| appropriateness of using or redistributing the Work and assume any |
| risks associated with Your exercise of permissions under this License. |
| |
| 8. Limitation of Liability. In no event and under no legal theory, |
| whether in tort (including negligence), contract, or otherwise, |
| unless required by applicable law (such as deliberate and grossly |
| negligent acts) or agreed to in writing, shall any Contributor be |
| liable to You for damages, including any direct, indirect, special, |
| incidental, or consequential damages of any character arising as a |
| result of this License or out of the use or inability to use the |
| Work (including but not limited to damages for loss of goodwill, |
| work stoppage, computer failure or malfunction, or any and all |
| other commercial damages or losses), even if such Contributor |
| has been advised of the possibility of such damages. |
| |
| 9. Accepting Warranty or Additional Liability. While redistributing |
| the Work or Derivative Works thereof, You may choose to offer, |
| and charge a fee for, acceptance of support, warranty, indemnity, |
| or other liability obligations and/or rights consistent with this |
| License. However, in accepting such obligations, You may act only |
| on Your own behalf and on Your sole responsibility, not on behalf |
| of any other Contributor, and only if You agree to indemnify, |
| defend, and hold each Contributor harmless for any liability |
| incurred by, or claims asserted against, such Contributor by reason |
| of your accepting any such warranty or additional liability. |
| |
| END OF TERMS AND CONDITIONS |
| |
| APPENDIX: How to apply the Apache License to your work. |
| |
| To apply the Apache License to your work, attach the following |
| boilerplate notice, with the fields enclosed by brackets "[]" |
| replaced with your own identifying information. (Don't include |
| the brackets!) The text should be enclosed in the appropriate |
| comment syntax for the file format. We also recommend that a |
| file or class name and description of purpose be included on the |
| same "printed page" as the copyright notice for easier |
| identification within third-party archives. |
| |
| Copyright [yyyy] [name of copyright owner] |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| |
| ============================================================================== |
| END LICENSE |
| |
| |
| Historical notes |
| ---------------- |
| |
| FreeMarker 1.x was released under the LGPL license. Later, by |
| community consensus, we have switched over to a BSD-style license. As |
| of FreeMarker 2.2pre1, the original author, Benjamin Geer, has |
| relinquished the copyright in behalf of Visigoth Software Society. |
| |
| With FreeMarker 2.3.21 the license has changed to Apache License, |
| Version 2.0, and the owner has changed from Visigoth Software Society |
| to three of the FreeMarker 2.x developers, Attila Szegedi, Daniel |
| Dekany, and Jonathan Revusky. |
| |
| After FreeMarker 2.3.24-pre01 (2015-09-02), the owner changes to the |
| Apache Software Foundation.</programlisting> |
| </section> |
| |
| <section xml:id="app_eccn"> |
| <title>Export Control</title> |
| |
| <para>The FreeMarker source code doesn't include cryptography. |
| Furthermore its binary (downloadable) forms don't include any |
| cryptography software. Hence, FreeMarker has no Export Control |
| Classification Number (ECCN). Where an ECCN should be filled, the |
| label "not subject to EAR" could be used.</para> |
| |
| <para>FreeMarker itself doesn't add any exporting limitations.</para> |
| </section> |
| </appendix> |
| </part> |
| |
| <glossary xml:id="gloss"> |
| <glossentry xml:id="gloss.startTag"> |
| <glossterm>Start-tag</glossterm> |
| |
| <glossdef> |
| <para><link linkend="gloss.tag">Tag</link>, which indicates that the |
| following content is under the element, up to the <link |
| linkend="gloss.endTag">end-tag</link>. The start-tag may also |
| specifies <link linkend="gloss.attribute">attributes</link> for the |
| element. An example of a start-tag: <literal><body |
| bgcolor=black></literal></para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.boolean"> |
| <glossterm>Boolean</glossterm> |
| |
| <glossdef> |
| <para>This is a variable type. A boolean variable represents a logical |
| true or false (yes or no). For example, if the visitor has been logged |
| in or not. There are only two possible boolean values: |
| <literal>true</literal> and <literal>false</literal>. Typically, you |
| will use booleans with an <literal><#if |
| <replaceable>...</replaceable>></literal> directive when you want |
| to display text based on some condition, say, you show a certain part |
| of the page only for visitors who has logged in.</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.c"> |
| <glossterm>c</glossterm> |
| |
| <glossdef> |
| <para>In the context of FreeMarker, this usually refers to the <link |
| linkend="ref_builtin_c"><literal>c</literal> built-in</link>, or |
| <quote>computer format</quote> in general.</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.c_format"> |
| <glossterm>c_format</glossterm> |
| |
| <glossdef> |
| <para><literal>c_format</literal> (aka. <literal>cFormat</literal>, |
| <quote>c format</quote>) is a <link |
| linkend="pgui_config_settings">configuration setting</link> that |
| specifies how to format values for <quote>computer |
| consumption</quote>, that is, if the target is some computer language, |
| or other simpler parser, and not a human reader. The value of this |
| setting is usually a computer language, like <quote>JSON</quote>, or |
| <quote>Java</quote>. The name refers to the <link |
| linkend="ref_builtin_c"><literal>c</literal> built-in</link>, which is |
| the typical way of formatting simple values for such output (e.g. |
| <literal><a href="/product/${product.id?c}"></literal>). To |
| understand the topic more, see: <xref |
| linkend="dgui_misc_computer_vs_human_format"/></para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.character"> |
| <glossterm>Character</glossterm> |
| |
| <glossdef> |
| <para>A symbol that people use in writing. Examples of characters: |
| Latin capital letter A (<quote>A</quote>), Latin small letter A |
| (<quote>a</quote>), digit four (<quote>4</quote>), number sign |
| (<quote>#</quote>), colon (<quote>:</quote>)</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.charset"> |
| <glossterm>Charset</glossterm> |
| |
| <glossdef> |
| <para>A charset is a rule (algorithm) for transforming a sequence of |
| <link linkend="gloss.character">characters</link> (text) to a sequence |
| of bits (or in practice, to a sequence of bytes). Whenever a character |
| sequence is stored on a digital media, or sent through a digital |
| channel (network), a charset must be applied. Examples of charsets are |
| ISO-8859-1, ISO-8859-6, Shift_JIS , UTF-8.</para> |
| |
| <para>The capabilities of different charsers are different, that is, |
| not all charsets can be used for all languages. For example ISO-8859-1 |
| can't represent Arabic letters, but ISO-8859-6 can, however it can't |
| represent the accented letters that that ISO-8859-1 can. Most charsets |
| are highly restrictive regarding the allowed characters. UTF-8 allows |
| virtually all possible characters, but most text editors can't handle |
| it yet (2004).</para> |
| |
| <para>When different software components exchange text (as the HTTP |
| server and the browser, or the text editor you use for saving |
| templates and FreeMarker who loads them), it's very important that |
| they agree in the charset used for the binary encoding of the text. If |
| they don't, then the binary data will be misinterpreted by the |
| receiver (loader) component, which usually results in the distortion |
| of the non-English letters.</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.outputEncoding"> |
| <glossterm>Output encoding</glossterm> |
| |
| <glossdef> |
| <para>Means output <link linkend="gloss.charset">charset</link>. In |
| the Java world the term <quote>encoding</quote> is commonly (mis)used |
| as a synonym to charset.</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.templateEncoding"> |
| <glossterm>Template encoding</glossterm> |
| |
| <glossdef> |
| <para>Means template <link linkend="gloss.charset">charset</link>. In |
| the Java world the term <quote>encoding</quote> is commonly (mis)used |
| as a synonym to charset.</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.collectionVariable"> |
| <glossterm>Collection</glossterm> |
| |
| <glossdef> |
| <para>A variable that (in conjunction with the <literal>list</literal> |
| directive) can spit out a series of variables.</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.dataModel"> |
| <glossterm>Data-model</glossterm> |
| |
| <glossdef> |
| <para>Something that holds the information the template has to show |
| (or use in some other ways) when the template processor assembles the |
| output (e.g. a Web page). In FreeMarker this is best visualized as a |
| tree.</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.directive"> |
| <glossterm>Directive</glossterm> |
| |
| <glossdef> |
| <para>Instructions to FreeMarker used in <link |
| linkend="gloss.FTL">FTL</link> <link |
| linkend="gloss.template">templates</link>. They are invoked by <link |
| linkend="gloss.FTLTag">FTL tags</link>.</para> |
| |
| <glossseealso otherterm="gloss.predefinedDirective"/> |
| |
| <glossseealso otherterm="gloss.userDefinedDirective"/> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.element"> |
| <glossterm>Element</glossterm> |
| |
| <glossdef> |
| <para>Elements are the most fundamental building pieces of <link |
| linkend="gloss.SGML">SGML</link> documents; an SGML document is |
| basically a tree of elements. Example of elements used in HTML: body, |
| head, title, p, h1, h2.</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.endTag"> |
| <glossterm>End-tag</glossterm> |
| |
| <glossdef> |
| <para><link linkend="gloss.tag">Tag</link>, which indicates that the |
| following content is not under the element. Example: |
| <literal></body></literal>.</para> |
| |
| <glossseealso otherterm="gloss.startTag"/> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.environment"> |
| <glossterm>Environment</glossterm> |
| |
| <glossdef> |
| <para>An <literal>Environment</literal> object stores the runtime |
| state of a single template <link |
| linkend="gloss.templateProcessingJob">template processing job</link>. |
| That is, for each |
| <literal>Template.process(<replaceable>...</replaceable>)</literal> |
| call, an <literal>Environment</literal> instance will be created, and |
| then discarded when <literal>process</literal> returns. This object |
| stores the set of temporary variables created by the template, the |
| value of settings set by the template, the reference to the data-model |
| root, etc. Everything that is needed to fulfill the template |
| processing job.</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.XML"> |
| <glossterm>Extensible Markup Language</glossterm> |
| |
| <glossdef> |
| <para>A subset (restricted version) of <link |
| linkend="gloss.SGML">SGML</link>. This is less powerful than SGML, but |
| it easier to learn and much easier to process with programs. If you |
| are an HTML author: XML documents are similar to HTML documents, but |
| the XML standard doesn't specify the usable elements. XML is a much |
| more general-purpose thing than HTML. For example you can use XML to |
| describe Web pages (like HTML) or to describe non-visual information |
| like a phone book database.</para> |
| |
| <glossseealso otherterm="gloss.SGML">SGML</glossseealso> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.FTL"> |
| <glossterm>FreeMarker Template Language</glossterm> |
| |
| <glossdef> |
| <para>Simple programming language designed to write text file |
| templates, especially HTML templates.</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry> |
| <glossterm>FTL</glossterm> |
| |
| <glosssee otherterm="gloss.FTL"/> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.FTLTag"> |
| <glossterm>FTL tag</glossterm> |
| |
| <glossdef> |
| <para><link linkend="gloss.tag">Tag</link>-like text fragment used to |
| invoke FreeMarker <link linkend="gloss.directive">directives</link> in |
| <link linkend="gloss.FTL">FTL</link> <link |
| linkend="gloss.template">templates</link>. These are similar to HTML |
| or XML tags at the first glance. The most prominent difference is that |
| the tag name is started with <literal>#</literal> or |
| <literal>@</literal>. Another important difference is that FTL tags do |
| not use <link linkend="gloss.attribute">attributes</link>, but a |
| substantially different syntax to specify parameters. Examples of FTL |
| tags: <literal><#if newUser></literal>, |
| <literal></#if></literal>, <literal><@menuitem |
| title="Projects" link="projects.html"/></literal></para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.functionDefinitionBody"> |
| <glossterm>Function definition body</glossterm> |
| |
| <glossdef> |
| <para>The template fragment between the <literal><#function |
| <replaceable>...</replaceable>></literal> and |
| <literal></#function></literal>. This template fragment will be |
| executed when you call the function (for example as |
| <literal>myFuction(1, 2)</literal>).</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.hashVariable"> |
| <glossterm>Hash</glossterm> |
| |
| <glossdef> |
| <para>A variable that acts as a container that stores sub variables |
| that can be retrieved via a string that is a lookup name.</para> |
| |
| <glossseealso otherterm="gloss.sequenceVariable"/> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.lineBreak"> |
| <glossterm>Line break</glossterm> |
| |
| <glossdef> |
| <para>Line break is a special character (or a sequence of special |
| characters) that causes a line breaking when you see the text as plain |
| text (say, when you read the text with Windows notepad). Typically you |
| type this character by hitting ENTER or RETURN key. The line break is |
| represented with different characters on different platforms (to cause |
| incompatibility and confusion...): <quote>line feed</quote> character |
| on UNIX-es, <quote>carriage return</quote> character on Macintosh, |
| <quote>carriage return</quote> + <quote>line feed</quote> (two |
| characters!) on Windows and DOS. Note that line breaks in HTML do not |
| have a visual effect when viewed in a browser; you must use markup |
| such as <literal><BR></literal> for that. This manual never |
| means <literal><BR></literal> when it says |
| <quote>line-break</quote>.</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.macroDefinitionBody"> |
| <glossterm>Macro definition body</glossterm> |
| |
| <glossdef> |
| <para>The template fragment between the <literal><#macro |
| <replaceable>...</replaceable>></literal> and |
| <literal></#macro></literal>. This template fragment will be |
| executed when you call the macro (for example as |
| <literal><@myMacro/></literal>).</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.markupOutputValue"> |
| <glossterm>Markup output value</glossterm> |
| |
| <glossdef> |
| <para>A value with FTL type <quote>markup output</quote>. This type is |
| related to <link linkend="dgui_misc_autoescaping">auto-escaping |
| mechanism</link>; you can <link |
| linkend="dgui_misc_autoescaping_movalues">read about this type |
| there</link>. But in short, this is a value that stores text that's |
| already in the output markup format (like HTML, XML, RTF, etc.), and |
| hence must not be auto-escaped.</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.methodVariable"> |
| <glossterm>Method</glossterm> |
| |
| <glossdef> |
| <para>A variable that calculates something based on parameters you |
| give, and returns the result.</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.MVC"> |
| <glossterm>MVC pattern</glossterm> |
| |
| <glossdef> |
| <para>MVC stands for Model View Controller. It's a design pattern |
| started his life in the 70's as a framework developer by Trygve |
| Reenskaug for Smalltalk, and was used primary for for UI-s (user |
| interfaces). MVC considers three roles:</para> |
| |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>Model: Model represents application (domain) specific |
| information in a non-visual way. For example, an array of product |
| objects in the memory of your computer is the part of the |
| model.</para> |
| </listitem> |
| |
| <listitem> |
| <para>View: View displays the model and provides UI. For example, |
| it's the task of the view component to render the array of product |
| objects to a HTML page.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Controller: The controller handles user input, modifies the |
| model, and ensures that the view is updated when needed. For |
| example it is the task of controller to take the incoming HTTP |
| requests, parse the received parameters (forms), dispatch the |
| requests to the proper business logic object, and chose the right |
| template for the HTTP response.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>The most important thing for us when applying MVC for Web |
| applications is the separation of View from the other two roles. This |
| allows the separation of designers (HTML authors) from programmers. |
| Designers deal with the visual aspects, programmers deal with the |
| application logic and other technical issues; everybody works on what |
| he is good at. Designers and programmers are less dependent on each |
| other. Designers can change the appearance without programmers having |
| to change or recompile the program.</para> |
| |
| <para>For more information I recommend reading <link |
| xlink:href="http://java.sun.com/blueprints/guidelines/designing_enterprise_applications_2e/web-tier/web-tier5.html">chapter |
| 4.4</link> of Designing Enterprise Applications with the J2EE Platform |
| blueprint.</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.parseTimeError"> |
| <glossterm>Parse-time error</glossterm> |
| |
| <glossdef> |
| <para>An error occurring during the template parsing phase, as opposed |
| to the later template execution phase (see more explanation below). |
| The presence of a such error prevents the execution of the whole |
| template, even if the execution wouldn't use the part where the error |
| is. This is seen as an advantage, as it helps early (before |
| deployment, ideally in-editor) error detection.</para> |
| |
| <para>A FreeMarker template is processed in two phases. First the |
| <emphasis>whole</emphasis> template is analyzed syntactically, which |
| is called parsing. The result of the parsing is a |
| <literal>Template</literal> Java object, which is usually cached for |
| fast reuse. Later, the already parsed template can be executed for |
| unlimited times to produce output based on the content of a <link |
| linkend="gloss.dataModel">data-model</link>. Errors occurring during |
| the parsing are called parse-time errors.</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.predefinedDirective"> |
| <glossterm>Predefined directive</glossterm> |
| |
| <glossdef> |
| <para>Directive what is defined by FreeMarker, thus always available. |
| Example of predefined directives: <literal>if</literal>, |
| <literal>list</literal>, <literal>include</literal></para> |
| |
| <glossseealso otherterm="gloss.userDefinedDirective"/> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.scalarVariable"> |
| <glossterm>Scalar</glossterm> |
| |
| <glossdef> |
| <para>A scalar variable stores a single value. A scalar is either a |
| string or a number or a date/time or a <link |
| linkend="gloss.boolean">boolean</link>.</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.sequenceVariable"> |
| <glossterm>Sequence</glossterm> |
| |
| <glossdef> |
| <para>A sequence is a variable that contains a sequence of sub |
| variables. The sequence's sub variables are accessible via numerical |
| index, where the index of the very first object is 0, the index of the |
| second objects is 1, the index of the third object is 2, etc.</para> |
| |
| <glossseealso otherterm="gloss.hashVariable"/> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.regularExpression"> |
| <glossterm>Regular expression</glossterm> |
| |
| <glossdef> |
| <para>A regular expression is a string that specifies a set of strings |
| that matches it. For example, the regular expression |
| <literal>"fo*"</literal> matches <literal>"f"</literal>, |
| <literal>"fo"</literal>, <literal>"foo"</literal>, etc. Regular |
| expressions are used in several languages and other tools. In |
| FreeMarker, the usage of them is a <quote>power user</quote> option. |
| So if you have never used them before, there is no need to worry about |
| not being familiar with them. But if you are interested in regular |
| expressions, you can find several Web pages and books about them. |
| FreeMarker uses the variation of regular expressions described at: |
| <link |
| xlink:href="http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html">http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html</link></para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry> |
| <glossterm>SGML</glossterm> |
| |
| <glosssee otherterm="gloss.SGML"/> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.SGML"> |
| <glossterm>Standard Generalized Markup Language</glossterm> |
| |
| <glossdef> |
| <para>This is an international standard (ISO 8879) that specifies the |
| rules for the creation of platform-independent markup languages. HTML |
| is a markup language created with SGML. <link |
| linkend="gloss.XML">XML</link> is a subset (restricted version) of |
| SGML.</para> |
| |
| <glossseealso otherterm="gloss.XML">XML</glossseealso> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.string"> |
| <glossterm>String</glossterm> |
| |
| <glossdef> |
| <para>A sequence of <link linkend="gloss.character">characters</link> |
| such as <quote>m</quote>, <quote>o</quote>, <quote>u</quote>, |
| <quote>s</quote>, <quote>e</quote>.</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.tag"> |
| <glossterm>Tag</glossterm> |
| |
| <glossdef> |
| <para>Text fragment indicating the usage of an element in SGML. |
| Examples of tags: <literal><body bgcolor=black></literal>, |
| <literal></body></literal></para> |
| |
| <glossseealso otherterm="gloss.startTag"/> |
| |
| <glossseealso otherterm="gloss.endTag"/> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.template"> |
| <glossterm>Template</glossterm> |
| |
| <glossdef> |
| <para>A template is a text file with some special character sequences |
| embedded into it. A template processor (e.g. FreeMarker) will |
| interpret special character sequences and it outputs a more or less |
| different text from the original text file, where the differences are |
| often based on a <link linkend="gloss.dataModel">data-model</link>. |
| Thus, the original text acts as a template of the possible |
| outputs.</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.templateProcessingJob"> |
| <glossterm>Template processing job</glossterm> |
| |
| <glossdef> |
| <para>A template processing job is the process during which FreeMarker |
| merges the main (top-level) template with a data-model to produce the |
| output. Because templates can <literal>include</literal> and |
| <literal>import</literal> other templates, this may involves the |
| processing of multiple templates, but those will all belong to the |
| same template processing job, which was started with the processing of |
| the main template. A template-processing job only exists for the short |
| time period until the processing of the main template is finished, and |
| then it vanishes with all the variables created during the process |
| (variables created with <literal>assign</literal>, |
| <literal>macro</literal>, <literal>global</literal>, etc. |
| directives).</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.transformVariable"> |
| <glossterm>Transform</glossterm> |
| |
| <glossdef> |
| <para>This term refers to user-defined directives that are implemetned |
| with the now obsolete <literal>TemplateTransformModel</literal> Java |
| interface. The feature was originally made for implementing output |
| filters, hence the name.</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.threadSafe"> |
| <glossterm>Thread-safe</glossterm> |
| |
| <glossdef> |
| <para>An object is thread-safe if it is safe to call its methods from |
| multiple threads, even in parallel (i.e. multiple threads execute the |
| methods of the object at the same time). Non-thread-safe objects may |
| behave unpredictably in this situation, and generate wrong results, |
| corrupt internal data structures, etc. Thread-safety is typically |
| achieved in two ways with Java: with the usage |
| <literal>synchronized</literal> statement (or |
| <literal>synchronized</literal> methods), and with the immutability of |
| encapsulated data (i.e. you can't modify the field after you have |
| created the object).</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.userDefinedDirective"> |
| <glossterm>User-defined directive</glossterm> |
| |
| <glossdef> |
| <para>Directive that is not defined by the FreeMarker core, but by the |
| user. These are typically application domain specific directives, like |
| pull-down menu generation directives, HTML form handling |
| directives.</para> |
| |
| <glossseealso otherterm="gloss.predefinedDirective"/> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.UCS"> |
| <glossterm>UCS</glossterm> |
| |
| <glossdef> |
| <para>This is international standard (ISO-10646) that defines a huge |
| set of <link linkend="gloss.character">characters</link> and assigns a |
| unique number for each character (<quote>!</quote> is 33, ..., |
| <quote>A</quote> is 61, <quote>B</quote> is 62, ..., Arabic letter |
| hamza is 1569... etc.). This character set (not charset) contains |
| almost all characters used today (Latin alphabet, Cyrillic alphabet, |
| Chinese letters, etc.). The idea behind UCS is that we can specify any |
| character with a unique number, not mater what the platform or the |
| language is.</para> |
| |
| <glossseealso otherterm="gloss.unicode"/> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.unicode"> |
| <glossterm>Unicode</glossterm> |
| |
| <glossdef> |
| <para>De-facto standard developed by Unicode organization. It deals |
| with the classification of the characters in <link |
| linkend="gloss.UCS">UCS</link> (which is letter, which is digit, which |
| is uppercase, which is lowercase, etc.), and with other problems of |
| processing text made from the characters of UCS (e.g. |
| normalization).</para> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.whiteSpace"> |
| <glossterm>White-space</glossterm> |
| |
| <glossdef> |
| <para>Characters that are totally transparent but have impact on the |
| visual appearance of the text. Examples of white-space characters: |
| space, tab (horizontal and vertical), line breaks (CR and LF), form |
| feed.</para> |
| |
| <glossseealso otherterm="gloss.lineBreak"/> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry> |
| <glossterm>XML</glossterm> |
| |
| <glosssee otherterm="gloss.XML"/> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.attribute"> |
| <glossterm>Attribute</glossterm> |
| |
| <glossdef> |
| <para>In connection with <link linkend="gloss.XML">XML</link> or HTML |
| (or <link linkend="gloss.SGML">SGML</link> in general), attributes are |
| the named values associated with elements. For example, in |
| <literal><body bgcolor=black |
| text=green><replaceable>...</replaceable></body></literal>, |
| the attributes are <literal>bgcolor=black</literal> and |
| <literal>text=green</literal>. On the left side of |
| <literal>=</literal> is the name of the attribute, while on the right |
| side is the value of the attribute. Note that in XML, the values must |
| be quoted (for example: <literal><body bgcolor="black" |
| text='green'></literal>), while in HTML it is optional for certain |
| values.</para> |
| |
| <glossseealso otherterm="gloss.startTag"/> |
| </glossdef> |
| </glossentry> |
| |
| <glossentry xml:id="gloss.fullQualifiedName"> |
| <glossterm>Full-qualified name</glossterm> |
| |
| <glossdef> |
| <para>... of nodes (XML node or other FTL node variable): The |
| full-qualified name of a node specifies not only the node name |
| (<literal><replaceable>node</replaceable>?node_name</literal>), but |
| also the node namespace |
| (<literal><replaceable>node</replaceable>?node_namespace</literal>), |
| this way it unambiguously identify a certain kind of node. The format |
| of the full-qualified name is |
| <literal><replaceable>nodeName</replaceable></literal> or |
| <literal><replaceable>prefix</replaceable>:<replaceable>nodeName</replaceable></literal>. |
| The prefix is shorthand to identify the node namespace (the a node |
| namespace is usually specified with a long ugly URI). In FTL, prefixes |
| are associated with the node namespaces with the |
| <literal>ns_prefixes</literal> parameter of <link |
| linkend="ref.directive.ftl">the <literal>ftl</literal> |
| directive</link>. In XML files, prefixes are associated with the node |
| namespaces with the |
| <literal>xmlns:<replaceable>prefix</replaceable></literal> attributes. |
| The lack of the prefix means that the node uses the default node |
| namespace, if a default node namespace is defined; otherwise it means |
| that the node does not belong to any node namespace. The default node |
| namespace is defined in FTL by registering reserved prefix |
| <literal>D</literal> with the <literal>ns_prefixes</literal> parameter |
| of the <literal>ftl</literal> directive. In XML files it is defined |
| with attribute <literal>xmlns</literal>.</para> |
| |
| <para>... of Java classes: The full-qualified name of a Java class |
| contains both the class name and the name of the package the class |
| belongs to. This way it unambiguously specifies the class, regardless |
| of the context. An example of full-qualifed class name: |
| <literal>java.util.Map</literal> (as opposed to |
| <literal>Map</literal>).</para> |
| </glossdef> |
| </glossentry> |
| </glossary> |
| |
| <index xml:id="alphaidx"> |
| <title>Alphabetical Index</title> |
| </index> |
| </book> |