Synopsis
<#include path>
or<#include path options>
Where:
-
path
: 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,profile.baseDir + "/menu.ftl"
.) -
options
: One or more of these:encoding=encoding
,parse=parse
-
encoding
: Expression evaluates to string -
parse
: Expression evaluates to boolean (also accepts a few string values for backward compatibility) -
ignore_missing
: Expression evaluates to boolean
-
Description
Using include
directive is
almost always a bad practice, and you should consider
using the
import
directive instead! Even if using
import
adds some verbosity, on the long run it
can pay off. See the
reasons here...
You can use it to insert another FreeMarker template file
(specified by the path
parameter) into your template. The output from the included template
is inserted at the point where the include
tag
occurs. The included file shares the variables with the including
template, similarly like if it was copy-pasted into it. The
include
directive is not really replaced by the
content of the included file, instead it processes the included file
each time when FreeMarker reaches the include
directive in the course of template processing. So for example if
the include
is inside a list
loop, you can specify different file names in each cycle.
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" read this...
The path
parameter can be a relative path like "foo.ftl"
and "../foo.ftl"
, or an absolute like
"/foo.ftl"
. Relative paths are relative to the
directory of the template that contains the
import
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.
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
Configuration
object.
Always use /
(slash) to separate path
components, never \
(backslash). Even if you are
loading templates from your local file system and it uses
backslashes (like under. Windows), use /
.
Example:
Assume /common/copyright.ftl contains:
Copyright 2001-2002 ${me}<br> All rights reserved.
Then this:
<#assign me = "Juila Smith"> <h1>Some test</h1> <p>Yeah. <hr> <#include "/common/copyright.ftl">
will output this:
<h1>Some test</h1> <p>Yeah. <hr> Copyright 2001-2002 Juila Smith All rights reserved.
The supported
options
are:
-
parse
: If it istrue
, 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 totrue
. -
encoding
: 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 viaConfiguration.setTemplateConfigurations(...)
-s (which also overrides that you specify here). IfConfiguration.setTemplateConfigurations(...)
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. 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) -
ignore_missing
: Whentrue
, suppresses the error when the template to include is missing, instead<#include ...>
will print nothing. Whenfalse
, the template processing will stop with error if the template is missing. If you omit this option, then it defaults tofalse
. A more flexible approach to handle missing templates (such as if you need to do something when the template is missing) is using theget_optional_template
special variable.Note:If
ignore_missing
istrue
, yet theinclude
directive fails with "Template inclusion failed" error when the template is missing, that's often because your application uses a customfreemarker.cache.TemplateLoader
implementation, which incorrectly (against the API documentation) throws anIOException
in thefindTemplateSource
method instead of returningnull
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 causeIOException
in the Java stack trace to figure out which case it is.
Example:
<#include "/common/navbar.html" parse=false encoding="Shift_JIS">
Note, that it is possible to
automatically do the commonly used inclusions for all templates,
with the "auto includes" setting of
Configuration
.
Using acquisition
There's a special path component represented by an asterisk
(*
). It is interpreted as "this directory or
any of its parents". Therefore, if the template located in
/foo/bar/template.ftl
has the following
line:
<#include "*/footer.ftl">
then the engine will look for the template in following locations, in this order:
-
/foo/bar/footer.ftl
-
/foo/footer.ftl
-
/footer.ftl
This mechanism is called acquisition 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:
<#include "*/commons/footer.ftl">
then the engine would look for the template in following locations, in this order:
-
/foo/bar/commons/footer.ftl
-
/foo/commons/footer.ftl
-
/commons/footer.ftl
Finally, the asterisk needn't be the first element of the path:
<#include "commons/*/footer.ftl">
would cause the engine to look for the template in following locations, in this order:
-
/foo/bar/commons/footer.ftl
-
/foo/bar/footer.ftl
-
/foo/footer.ftl
-
/footer.ftl
However, there can be at most one asterisk in the path. If you specifying more asterisks, the template won't be found.
Localized lookup
A locale is a language and an optional country or dialect
identifier (plus also maybe a further variant identifier, like
"MAC"). 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 locale
setting is set to, and
that's usually for the locale of the top-level template.
Suppose your template was loaded with locale
en_US
, which means U.S. English. When you
include another template:
<#include "footer.ftl">
the engine will in fact look for several templates, in this order:
-
footer_en_US.ftl
, -
footer_en.ftl
-
footer.ftl
and it will use the first one that exists.
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. You can disable localized lookup with the
localized_lookup
setting
(Configuration.setLocalizedLookup(boolean)
).
Also, you can define your own sequence of deduced template names
with the template_lookup_strategy
setting
(Configuration.setTemplateLookupStrategy(TemplateLookupStrategy)
).
When you use both acquisition (i.e., *
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
/foo/bar/template.ftl
:
<#include "*/footer.ftl">
the engine will look for these templates, in this order:
-
/foo/bar/footer_en_US.ftl
-
/foo/footer_en_US.ftl
-
/footer_en_US.ftl
-
/foo/bar/footer_en.ftl
-
/foo/footer_en.ftl
-
/footer_en.ftl
-
/foo/bar/footer.ftl
-
/foo/footer.ftl
-
/footer.ftl
Why import
should be used instead of
include
Generally, using the
import
directive is a better practice
than using include
.
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 include
to insert a common fragment
of output (e.g. page footer) into multiple templates. The
import
directive has no output, so it's clearly
not a direct replacement. But, it's usually a better practice to
put those output fragments
into macros, 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 import
.
So if you have collection of macros, functions and other
variables in a template, this is why import
is
generally a better choice:
-
Imported templates are processed only when first requested. To compare with
include
, let's say templatetop.ftl
includescommons.ftl
, andtables.ftl
. Iftables.ftl
also includescommons.ftl
, then nowcommons.ftl
will be processed twice. On the other hand, importingcommons.ftl
for the second time just gives back the namespace that was already initialized during the first import. -
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.
-
If you have several collections of useful macros/functions/constants (say,
commons.ftl
,form.ftl
,report.ftl
, 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. -
import
never prints to the output, whileinclude
might prints unwanted output, like some whitespace that wasn't removed by the automatic whitespace removal.