Things you must know about settings
The basic definition of the "setting" term is here...
The common characteristics of settings
The characteristics of a setting can be described with these attributes:
- Name: The name of the setting. This name is used in configuration files. Also, front-ends used to use this or similar name for the setting in their user interface.
- Type: The type of the value, such as string, integer, boolean, sequence or hash. If you specify the values in a configuration file, then the TDD syntax clearly specifies what syntax to use for which types. For the front-end specific user interface, it depends on the concrete front-end how you face with types. But, if the front-end wants you to enter the value for a single setting as simple text, then you have to enter scalar values (string, integer and boolean) as is (without any TDD quotation), but you have to use TDD syntax for non-scalar types as sequences and hashes. For setting that are sequences, sequence mode TDD is used (i.e. no
[
and]
needed), and for setting that are hashes hash mode TDD is used (i.e. no{
and}
needed). - Default: If the value of the setting was not set, the processing session will use this value. If the setting has no default value that doesn't mean that you are required to specify a value for it.
Notes:
- Settings of type "string (path)" are real paths.
- All settings are optional, unless explicitly noted otherwise.
The merging of setting values
Setting values can be specified in multiple layers. For example, it is possible that a setting is specified in the configuration file, and then again with a command-line argument of the command-line tool.
Setting layers has a priority order, for example, the setting layer defined by the command-line arguments has higher priority than the setting layer defined by the configuration file. When the value of the same setting is specified in two layers, then the value that comes from the layer with higher priority overrides the setting value comes from the lower layer. If the type of the setting is not map or sequence, then this simply means that the value from the higher layer will be used, and the other value will be totally hidden. But if the setting type is sequence or hash, then the sequence values will be merged:
When sequences are merged, the two sequences are concatenated, and the sequence with the higher priority will start the new concatenated sequence.
When hashes are merged, the union of the two hashes is constructed, and for clashing keys the values in the hash with higher priority will be used. The type of the value of the hash items is not considered when the merging happens, simply the item from the higher priority hash will be used in the resulting hash. Thus, hash merging is not "deep", becasue the value of clashing items with hash values are not merged. For example, if you merge
{x:{v:1}, y:2}
with{x:{w:2}}
, then the result will be{x:{w:2}, y:2}
, and not{x:{v:1, w:2}, y:2}
.
Logically, the rules described in this section can be applied for more than two layers of settings as well.
Directories
Name: sourceRoot
Type: string (path)
Default:
No default value
Command-line short name: S
Ant task attribute name alternative: srcdir
Name: outputRoot
Type: string (path)
Default:
No default value
Command-line short name: O
Ant task attribute name alternative: destdir
Name: dataRoot
Type: string (path)
Default:
the value of sourceRoot
Name: alwaysCreateDirectories
Type: boolean
Default:
false
Ant task attribute name alternative: alwaysCreateDirs
In the typical use case FMPP processes all files in the directory specified by sourceRoot
, and writes the result into the directory specified by the outputRoot
directory. These two root directories serve as the root directory of two virtual file systems that store the source files and the output files respectively. This means that all files that FMPP processes must be inside the source root directory (except data files - see later), and it is guaranteed that all output files will be inside the output root directory (as far as you do not by-pass FMPP intentionally with custom extensions). You can't leave the roots by moving upward with ..
-s. Also, when you refer to files or directories in the templates as the parameters of predefined directives, absolute paths like /example.html
are interpreted relatively to the source or output root directories (except if the parameter deals with data files - see later).
Note that both the source root and the output root must be defined before starting a processing session (but a front-end may assings a default value to them). Also, if you use the outputFile
setting these two settings always have a default value.
The directory specified by dataRoot
is interesting for data loaders only. If a data loader gets a relative path, then it should interpret that relatively to the data root directory. If it gets an absolute path, it should interpret that as is. As you can see from this, data root directory does not try to mimic a file system root as the other two root directories. Data loaders can reach files outside the data root directory.
By default, the data root is the same as the source root. This encourages the practice where you store the data files in the, say, data
subdirectory of the source root, and then mark that directory with a ignoredir.fmpp
file (file content is irrelevant), so FMPP will not process the content of the directory. Thus, you keep all input together: data sources, templates and static files (as images).
By default, no empty subdirectories will be created in the output root directory. More precisely, directories are created only on demand, when actual output files have to be created in them, hence normally you don't have empty directories in the output. However, this behavior can be changed with alwaysCreateDirectories
; with that setting set to true
, each source directory will produce a corresponding output directory (unless it contains an ignoredir.fmpp
file). Also, if a source directory contains a file named createdir.fmpp
(file content is irrelevant) then the corresponding output directory will be created, regardless of the alwaysCreateDirectories
setting (unless, again, ignoredir.fmpp
is also present)
It is possible to tell FMPP to process only certain files and directories of the source root, not all of them; see the sources
setting.
Source and output files
Name: sources
Type: sequence (of paths)
Default:
No default value
Name: outputFile
Type: string (path)
Default:
No default value
Command-line short name: o
Be default FMPP processes all files in the source root directory. But if you use the sources
setting, FMPP will process only the files and/or directories listed there. Relative paths in this setting are resolved relatively to the source root directory, not to the configuration base (unless you use outputFile
setting).
If you use the outputFile
setting, then FMPP switches to single file mode. In this mode, it will process only 1 files, and store its output in the file specified by the outputFile
setting. You must use sources
, and it must list exactly 1 file. If a relative path is given in the sources
, it is resolved relatively to configuration base, not to the source root. If you didn't specified outputRoot
or sourceRoot
, it will default to the parent directory of the output file or source file respectively.
The user interface of front-ends tend to require you to use some special way to specify the value sources
setting. Please read the documentation of the front-end you use about this. Note that configuration files are front-end independent, so there you always simply set sources
be assigning value to the sources
key.
Text encoding issues
Name: sourceEncoding
Type: string
Default:
ISO-8859-1
Command-line short name: E
Name: outputEncoding
Type: string
Default:
source
Name: urlEscapingCharset
Type: string
Default:
output
People use different encodings to store text in binary form, often referred as charsets. Examples of charsets are: ISO-8859-1
, ISO-8859-2
, CP852
, CP1250
, Shift_JIS
, UTF-8
. FMPP internally uses UNICODE everywhere, but when it has to read a text file or write a text file, it must deal with charsets to correctly decode/encode the text.
To read text files, FMPP uses the source encoding. This is be default ISO-8859-1. Also, a FreeMarker template has the ability to tell its own encoding with <#ftl encoding="something">
, and this overrides the source encoding for the individual template file.
To write text files, FMPP uses the output encoding. This is be default holds the special value source
, which means that FMPP will use the encoding of the source text file (template file). If you change the value of the setting to a concrete charset, such as UTF-8, then text files will be always written with that encoding. However, templates can set the encoding of the output file with <@pp.setOutputEncoding encoding="something"/>
, and this overrides the encoding dictated by the settings.
The urlEscapingCharset
specifes the name of the charset (encoding) used for URL escaping. It defaults to output
, which means that the output encoding will be used for URL escaping. URL escaping happens for example when you use FreeMarker's url
built-in (e.g. <a href="foo.cgi?id=${id?url}">
) or the pp.urlPathEnc
method.
All of these settings understands the special charset host
, which means the default encoding of the host operating system.
The set of supported charsets (and their preciese names) depends on the Java platfrom implementation you run FMPP on.
Processing mode choosing
Name: modes
Type: sequence (of function calls)
Default:
empty
Command-line short name: M
Name: ignoreCvsFiles
Type: boolean
Default:
true
Name: ignoreSvnFiles
Type: boolean
Default:
true
Name: ignoreTemporaryFiles
Type: boolean
Default:
true
When FMPP has to process a file, it has to decide how to process that. That is, it has to choose a "processing mode" for the file. The processing mode can be one of:
- execute: Execute the file as FreeMarker template (FTL)
- copy: Copy the file as is. Uses binary copy; charset does not mater here.
- renderXml: Parse the file as XML, and then render the XML document to output file(s) using a FreeMarker template. The template file is choosen for the XML file based on the
xmlRenderings
setting. For more information read about XML rendering... - ignore: Skip the file.
First, if the ignoreCvsFiles
setting is true, and the file name is .cvsignore
or matches .#?*
, or the file is inside a sub-directory of the source root that is called CVS
, then it chooses the "ignore" processing mode. Also, if the ignoreSvnFiles
setting is true, and the file is inside a sub-directory of the source root that is called .svn
, then it chooses the "ignore" processing mode (note that it doesn't ignore conflict files, i.e., *.mine
and *.rnumber
). Also, if ignoreTemporaryFiles
setting is true, and the file name matches ?*~
or ~?*
or #?*#
or %?*%
or _.?*
, or the extension (the part after the last dot in the file name) after converting to lowercase matches bak
or ~*
or *~
then it chooses the "ignore" processing mode. Note that the FMPP Ant task always sets these settings to false
, so it does not interfere with the defaultExcludes
parameter of Ant.
Then, the processing mode is chosen with a sequence of path patterns, which is defined by the modes
setting. The first path pattern in the sequence that matches the virtual path of the file, chooses the processing mode. If no matching path were found, then FMPP chooses the processing mode automatically:
- If the file extension after converting to lowercase is
xml
and thexmlRenderings
is not an empty sequence, then it chooses the "renderXml" mode. - If the file extension after converting to lowercase is known by FMPP as belonging to a binary format, then it chooses the "copy" processing mode. The list of these file extensions is hard-coded into FMPP.
If the
recommendedDefaults
setting is 0.9.15 (the minimum), then the list is this:ace
,arc
,arj
,avi
,bmp
,bz
,bz2
,cab
,chm
,class
,com
,dll
,doc
,exe
,fli
,gif
,gz
,ico
,jar
,jpeg
,jpg
,lha
,lzh
,mov
,mp3
,mpeg
,mpg
,msi
,pcx
,pdf
,png
,ps
,rar
,swf
,tar
,taz
,tga
,tgz
,tiff
,tz
,wav
,wma
,xls
,zip
. If therecommendedDefaults
setting is 0.9.16 or greater, then the list is this:3g2
,3gp
,7z
,acc
,ace
,aif
,aiff
,apk
,arc
,arj
,avi
,bin
,bmp
,bz
,bz2
,cab
,cda
,chm
,class
,com
,deb
,der
,dll
,dmg
,doc
,docm
,docx
,dot
,dotx
,eot
,exe
,flac
,fli
,flv
,fnt
,gif
,gz
,h264
,ico
,iso
,jar
,jpeg
,jpg
,lha
,lzh
,m4a
,m4v
,mkv
,mogg
,mov
,mp3
,mp4
,mpa
,mpeg
,mpg
,msi
,odg
,odg
,odm
,odp
,ods
,odt
,oga
,ogg
,otf
,otg
,oth
,otp
,ots
,ott
,pcx
,pdf
,pkg
,png
,pot
,potm
,potx
,pps
,ppt
,pptm
,pptx
,ps
,rar
,rpm
,svgz
,swf
,swf
,sys
,tar
,taz
,tb2
,tbz2
,tga
,tgz
,tif
,tiff
,ttf
,txz
,tz
,vcd
,wav
,webm
,webp
,wma
,wma
,wmv
,woff
,woff2
,xls
,xlsm
,xlsx
,xlt
,xltm
,xltx
,xlw
,xz
,z
,zip
. - Otherwise it chooses the "execute" processing mode.
The modes
setting is a list of TDD functions, where the function name is either execute
, copy
, renderXml
, or ignore
. The arguments to the functions are one or more path patterns of virtual paths in the source file system. For example this (in a configuration file):
modes: [ ignore(**/tmp/) copy(foo/**/*.html, foo/**/*.htm) execute(**/*.html, **/*.htm, **/*.xhtml) copy(**/*) ]
will produce this processing mode chooser sequence:
Path pattern | Processing mode |
---|---|
**/tmp/ | ignore |
foo/**/*.html | copy |
foo/**/*.htm | copy |
**/*.html | execute |
**/*.htm | execute |
**/*.xhtml | execute |
**/* | copy |
Note that processing modes are only applicable to files, not to directories. Say, you can't tell FMPP to ignore a directory, but to ignore all files in the directory (as **/tmp/
above). The end result will be that the directory will not be created, as it contains no output file.
Header and footer choosing
Name: borders
Type: sequence (of function calls)
Default:
empty
With these settings you can insert a header before templates, and insert a footer after templates (templates = files processed in "execute" processing mode). The insertion of header and footer happens only in the memory of the computer, and does not modify the source files. This can be used to add common headers and footers to the templates without actually typing them again and again. Also, you can change the header/footer of many templates at once.
The intent of headers and footers is not to show something at the top and bottom of pages. Rather it is to insert FTL directives that import or include commonly used macros, or to place the page inside a block, as <@myLayout>...</myLayout>
. For concrete examples please see <FMPP>/docs/examples/border
.
Note: Unfortunately the inserted header displace the error locations (column, row) in the error messages (I can't fix it in FMPP; FreeMarker improvements are needed to address this). However, if the header doesn't contain line-break, then this unwanted effect is limited to the first line of the template. So it's strongly recommended to not use line-break in headers.
Footers and headers are chosen with similar mechanism to processing modes (see modes
). There are two independent sequence of path-pattern to text entry mappings (so called "choosers"), one for choosing headers, and one for choosing footers. When FMPP loads a template file, it checks if the virtual path of the file matches to an entry in the header chooser sequence, and if so, it uses the header specified in the first such entry. Also, it does the same with the sequence of footers choosers, to choose a footer.
There is a single setting to build both sequences at once: borders
. You give a sequence of header
, footer
and border
functions in it. The first argument to header
and footer
functions is the text of header and footer respectively, and the further arguments are the path patterns of virtual paths in the source file system. If you omit the path patterns, that's the same as if you give **
(i.e. match all files). border
is convenience function: border(a, b, paths...)
is equivalent with header(a, paths...), footer(b, paths...)
. Example:
header("<#import '/lib/css.ftl' as css>", **/*.css) border("<#import '/lib/page.ftl' as p><@p.myLayout>", "</@p.myLayout>", **/*.html, **/*.htm)
This build these sequences:
- Header chooser sequence:
Path pattern Header **/*.css
<#import '/lib/css.ftl' as c>
**/*.html
<#import '/lib/page.ftl' as p><@p.myLayout>
**/*.htm
<#import '/lib/page.ftl' as p><@p.myLayout>
- Footer chooser sequence:
Path pattern Footer **/*.html
</@p.myLayout>
**/*.htm
</@p.myLayout>
Only the first matching entry of the sequence is used for a file, the later entries are ignored. But sometimes you want to choose multiple headers/footers for the same file. In that case, you can define multiple independent sequences, so said, layers. Layers are separated with layer()
. For example, modify the above example, so it imports /lib/common.ftl
at the top for all files, without disabling the other headers/footers:
# The 1st (implicit) layer starts here header("<#import '/lib/common.ftl' as c>", **/*.css, **/*.html, **/*.htm), layer() # The 2nd layer starts here header("<#import '/lib/css.ftl' as css>", **/*.css), border("<#import '/lib/page.ftl' as p><@p.myLayout>", "</@p.myLayout>", **/*.html, **/*.htm)
Here we have two independent header chooser sequences, so both CSS and HTLM files will import lib/common.ftl
, and additionally CSS files will import lib/css.ftl
, and HTML files will import lib/page.ftl
have the @p.myLayout
block. You can have any number of layers.
A header chosen from an earlier layer will be used earlier in the template file than headers chosen from later layers. A footer chosen from an earlier layer will be used later in the template file than footers chosen from later layers. For example:
borders: [ border('L1(', ')L1') layer() border('L2{', '}L2') layer() border('L3[', ']L3') ]
If the content of a template file is content
, its output will be:
L1(L2{L3[content]L3}L2)L1
Output file name deduction
Name: removeExtensions
Type: sequence (of strings)
Default:
empty
Command-line short name: R
Name: removePostfixes
Type: sequence (of strings)
Default:
empty
Name: replaceExtensions
Type: sequence (of strings)
Default:
empty
Name: removeFreemarkerExtensions
Type: boolean
Default from recommendedDefaults
0.9.15:
true
Since: FMPP 0.9.16
Initially the name of the output file is the same as the name of the source file. These settings allow you to change the output filename somewhat, by removing and replacing parts of it.
The precise meaning of the settings:
removeExtensions
: If the source file name ends with an exension in this sequence, then it will be removed from the output file name. For example, ifftl
is in the sequence (note that there is no dot before theftl
), then the output file forexample.html.ftl
will beexample.html
. The extension to remove can contain dots (astar.gz
).removePostfixes
: If the source file name before the first dot ends with a string in this sequence, then it will be removed from the output file name. For example, if_t
is in the sequence, then the output file forexample_t.html
will beexample.html
. If the file name does not contains dot, then it still works:example_t
will become toexample
.replaceExtensions
: This sequence is used to replace the file extensions with another extensions. For example, if the sequence is this:
ftlh, html, ftlx, xml
then theftlh
extension will be replaced withhtml
(i.e. the output file name for source filefoo.ftlh
will befoo.html
), and theftlx
extension will be replaced withxml
. The 1st, 3rd, 5th, etc. sequence elements are the extensions to replace, and the 2nd, 4th, 6th, etc. sequence elements are the new extensions (sohtml
extension will not be replaced withftlx
). Also, only one extension replacement will occur for the same file name, so in the case of
x, y, y, z
x
will not become toz
.removeFreemarkerExtensions
: When set totrue
, and the file extension is one of the standard FreeMarker template file extensions (ftl
,ftlh
, andftlx
) then the file extension is removed from the output file name. The typical usage is that you have file names likefoo.txt.ftl
orbar.html.ftlh
, and then the output file names will befoo.txt
andbar.html
respectively. You could achieve the same withremoveExtensions
too, but this is more convenient, and most importantly, ifrecommendedDefaults
is set to at least 0.9.16, this defaults totrue
.
These settings are applied in the order as they are listed above. Each setting is applied only once on the same file name.
Note that output file name deduction only applies to files, not to directories.
Skipping unchanged files
Name: skipUnchanged
Type: string
Default:
none
Command-line short name: -U
This setting specifies that the processing of which source files can be skipped, if the source file was not modified after the last modification time of the output file. The value of setting can be one of:
none
: Don't skip unchanged files.all
: Skip all unmodified files. Warning! It has the problem that if the data that the template displays was changed, or a file that is<#include ...>
-d or<#import ...>
-d by the template was changed, it will not re-generate the output, since the template file itself was not changed.static
: Skip only unmodified files that will be simply copied anyway (the files where themodes
chooses "copy" processing mode). Process all other files. This is the recommended setting for most projects.
If the output does not exist, the source file will be always processed.
This feature will not work for templates that rename or drop the original output file during the template execution, because in the next processing session FMPP will believe that the output files for those files are missing, and thus it will process them again.
Turn choosing
Name: turns
Type: sequence (of function calls)
Default:
empty sequence
When FMPP has to process multiple files in the same processing session (for example, when you process a whole directory), then the order in which the files will be processed, is undefined. This is a problem in certain use cases, where it must be ensured that certain files will be processed later than others. For example, if a page contains the alphabetic index of keywords occur in other pages, then that page must be processed for the last, because the information is collected during the processing of the other pages. This is what turns are about: to guarantee the order of the processing of files.
The processing session is divided up into, so called, turns. Turns are identified with the turn number, which is simply the order of the turn. The session starts with turn 1, then comes turn 2, and then comes turn 3, etc. FMPP puts all files that will be processed into exactly one of the turns, based on the turn chooser sequence.
The turn chooser sequence is a sequence of path-pattern -> turn-number pairs. For each source file, the virtual path of the source file is compared with these path patterns, and the first pattern of the sequence that matches determines the turn in which the file will be processed. If there is no matching pattern in the sequence for the file, then the file will be processed in turn 1.
For example, if config.fmpp
contains this line:
turns: [turn(3, main_idx.html), turn(2, **/*_idx.html)]
then all files where the file name ends with _idx.html
will be processed in turn 2, except main_idx.html
, which will be processed in turn 3. All other files will be processed in turn 1.
There is no upper limit of the turn number (except a technically limit, somewhere near 2 thousand million). Simply, the last turn will be the turn with the highest number, which is mentioned in the turn chooser sequence, or 1, if the sequence is empty. The first turn is always the turn 1. It is not a problem if a turn contains no file processing.
See <FMPP>/docs/examples/session
for a working example, or the FMPP task call in the build.xml
.
Data model building
Name: data
Type: hash
Default:
No default value
Command-line short name: D
Name: localData
Type: sequence
Default:
No default value
Name: templateData
Deprecated! Use localData
instead.
Type: string (Java class name)
Default:
No default value
As you may know from the FreeMarker manual, FreeMarker generates the output by merging a template with a data model, and the data model is a hash variable, the root hash. With FMPP terminology, it is usually just referred as "the data". In FMPP, the population of the root hash happens in two places:
- Session level data: Once per processing session, at the very beginning of it (before any file processing is stared), the root hash is filled with variables based on the
data
setting. This is what happened in the Quick Tour, when we have loaded the colors and the table of birds. These variables will be constant during the whole session, and visible for all templates. They must not be modified while the processing session is executing, even if you find a technical way to do that. Note that FreeMarker uses multiple variable layers, so you doesn't modify these variables with<#assign ...>
or<#global ...>
, just hide them for the time of the template execution, which is OK (the effect will not be visible for the files processed later). - Local data (file processing level data): For each processed file, just before FMPP starts to proccess the file, some extra variables are put into the root hash that are specific for that file. These variables will be present in the root hash only while that file is being processed (hence "local data"), so the next file processing will start with the original session level data in the root hash again. The local data is built in three steps, in this order: Variable added later will overwrite the variable of similar name added earlier. Also, variable that is local data will hide (seemingly overwrite) the variable of similar name that is session level data.
From the view point of FreeMarker templates, variables that are part of the session level data and the part of the local data are not different. They are equal parts of the data model.
More about the data
setting
When you use TDD syntax for defining the hash for data
, TDD function calls are interpreted as data loader invocations. For reminder, here is the relevant part of config.fmpp
from <FMPP>/docs/examples/qtour_step4
:
data: { tdd(data/style.tdd) birds: csv(data/birds.csv) }
TDD syntax makes it possible to enter values directly as well, without using data loaders. For example, you could directly enter the "birds" table with TDD (altoguh it is not too convenient):
data: { tdd(data/style.tdd) birds: [ { name: arctic-tern description: "Flies very long distances all years." favoriteFood: sardine } { name: house-sparrow description: "Don't you say you don't know it..." favoriteFood: sunflower } { name: sakeret description: "Great hunter of the sky." favoriteFood: pigeon } ] }
More about the localData
setting
Let's start with a simple example. We have a variable bgColor
in the session level data with value green
. We want to override this with value yellow
for the source files that are in directory sub
(or in its subdirectories, ...etc.):
data: { bgColor: green } localData: [ case(sub/**, {bgColor: yellow}) ]
Complicate it a bit... now set the bgColor
if the file is in directory sub
or sub2
:
localData: [ case(sub/**, sub2/**, {bgColor: yellow}) ]
Now do the same as earlier, except for files that are in directory sub/sky
, where the bgColor
is always blue
:
localData: [ case(sub/sky/**, {bgColor: blue}) case(sub/**, sub2/**, {bgColor: yellow}) ]
The rule is that the first case(...)
where one of the path patterns matches the source file path will specify the local data (specified as the last argument), and the further case(...)
-s are ignored. There can be any number of case(...)
-s listed (note that localData
is a sequence), and a case(...)
can have any number of path patterns (but 0).
Tricky example: do the same as earlier, but don't override the color if the file name starts with foo
:
localData: [ case(**/foo*, {}) case(sub/sky/**, {bgColor: blue}) case(sub/**, sub2/**, {bgColor: yellow}) ]
Assume that you want to set variable author
to Joe
for all files where the file name contains _j.
, and to Amy
for all files contains _a.
. But, you want to do this independently of setting bgColor
. In this case you have to use layers:
localData: [ # The 1st (implicit) layer starts here case(**/foo*, {}) case(sub/sky/**, {bgColor: blue}) case(sub/**, sub2/**, {bgColor: yellow}) layer() # The 2nd layer starts here case(**/*_j.*, {author: Joe}) case(**/*_a.*, {author: Amy}) ]
The rule is that layers are separated with a layer()
function call. You can have any number of layers. The case(...)
-list of each layer will be searched for the first match independently. If more layers put the same variable into the data model, the higher layer (earlier layer) wins (hence "layers"). Layers are calculated starting with the lowest layer. Empty layers are allowed (can be practical when you are using setting merging).
The last parameter of the case can be:
- An arbitrary TDD hash (as in the examples above). This behaves as the value of the
data
setting, so you can use any number of key-value pairs, and invoke data loaders. The value of hash is calculated at most once per processing session, when it is first needed. For the subsequent file processings where the samecase(...)
is choosen, the calculated value is reused, so the data loaders don't re-load the external resources. If thecase(...)
is never chosen during the session, the value of the TDD hash is not calculated at all. - A TDD function call. The supported functions are:
bsh
: Deduces the path of a BeanShell script file from the source file path, and executes that script to create local data. The path of the script file will be the same as the path of the source file, except that the file name part is modified according the options described later. The script must return ajava.util.Map
, which stores the variables (keys are the names of the variables, associated values are the values of the variables) that will be added to the local data. The following variables are accessible for the scripts:engine
, thefmpp.Engine
instance, andtemplateEnvironment
, thefmpp.TemplateEnvironment
instance. There is 1 parameter to this function (optional), a hash that can store the following options (each is optional):ending
: The string appended at the end of the source file name. Can't be 0 length string. It defaults to.bsh
.removeExtension
: Sets if the extension from the source file name should be removed before appending theending
. The extension is the part after the last dot of the file name. The dot itself is also removed. Defaults tofalse
.ignoreMissing
: Set if it will be ignored if no script file found for the source file (and the source file will be processed normally), rather than aborting the processing of the file with error. Defaults tofalse
.encoding
: The encoding of the script files. If it is not set then the value of thesourceEncoding
setting will be used.
- A string. In this case the string will be interpreted as BeanShell script that must evaluate to an object that implements
fmpp.LocalDataBuilder
. This let Java programmers to implement custom local data strategies. See the API documentation for more information. (The predefined strategies above are also implemented with this interface internally.)
Here's an example of using of the bsh
function: It will execute a BeanShell script file for each HTML to add local data. For example, the script file for source file foo/bar.html
should be foo/bar.html.bsh
. If there is no script for the HTML file, it will not consider that as an error.
modes: ignore(**/*.bsh) localData: [ case(**/*.htm, **/*.html, bsh({ignoreMissing})) ]
A possible .bsh
file, that adds local variables x
and y
:
res = new HashMap(); res.put("x", "Just for test: " + templateEnvironment.getData("author")); res.put("y", "Blah..."); return res;
For a working example see <FMPP>/docs/examples/local_data
.
Auto-escaping
Name: outputFormat
Type: string
Default:
"undefined"
Since: FMPP 0.9.16
Name: outputFormatsByPath
Type: sequence (of case function calls)
Default:
[]
Since: FMPP 0.9.16
Name: mapCommonExtensionsToOutputFormats
Type: boolean
Default from recommendedDefaults
0.9.15:
false
Default from recommendedDefaults
0.9.16:
true
Since: FMPP 0.9.16
Auto-escaping means that in values printed with interpolations (with ${expression}
, not with <@directive />
, nor with static text), the parts that have special meaning in the output format (like &
and <
have if the output format is HTML) are replaced with an escaped form (with &
, <
in this case).
What patterns will be escaped and how depends on the output format, like HTML
, XML
, RTF
, etc.
Output formats and auto-escaping is a FreeMarker template language feature. See the related section in the FreeMarker documentation for more details.
In FMPP, the output format of a template is decided as follows, in this order:
- If the file extension is
ftlh
orftlx
, and thefreemarkerIncompatibleImprovements
setting is at least 2.3.24 (ifrecommendedDefaults
is at least 0.9.16 then that's true by default), then template files withftlh
file extension will haveHTML
output format, and template files withftlx
file extension will haveXML
output format. This is enforced by FreeMarker, so the FMPP settings below can't override it. (Note that these file extensions can be removed/replaced in the output file names using theremoveExtensions
/replaceExtensions
settings.) - Otherwise, if an entry in
outputFormatsByPath
matches the template file path (see later), then the output format specified there is used. - Otherwise, if
mapCommonExtensionsToOutputFormats
istrue
(ifrecommendedDefaults
is at least 0.9.16 then that's true by default), and the template file extension (the part of the file name after the last dot, always case-insensitive) is one of the common extensions (see them later), then the output format associated with that extension is used. Furthermore, if the file name ends with.ftl
(always case-insensitive), then we ignore that ending, so for example forexample.rtf.ftl
we check ifrtf
is a common extension, not ifftl
is one. - Otherwise, if the
outputFormat
setting is set, then the output format specified there is used. - Otherwise, the output format will be the one called
"undefined"
, which doesn't do automatic escaping.
Example:
outputFormat: HTML outputFormatsByPath: [ case(legacy/, undefined) case(**/*.xfoo, **/*.xbar, XML) ]
With this all templates inside the legacy
directory will have undefined
output format, and template files that have xfoo
or xbar
file extension will have XML
output format. The output format is decided by the first matching case(...)
, so for example legacy/example.xfoo
will have undefined
output format, despite that it matches **/*.xfoo
. If there's no match in outputFormatsByPath
, and we assume for simplicity that mapCommonExtensionsToOutputFormats
is false
, then the output format will be HTML
according the outputFormat
setting.
The case
function in outputFormatsByPath
has 2 or more arguments. The last argument is the name of the output format. The arguments before that are the path patterns that will be matched against the virtual path of the template, in logical or
relation.
The valid output format names can be found in the FreeMarker documentation.
The common extension used by mapCommonExtensionsToOutputFormats
are the following (in this format: Associated output format: case-insensitive file extensions
):
- HTML output format:
html
,htm
- XHTML output format:
xhtml
,xhtm
,xht
- XML output format:
xml
,xsd
,xsl
,xslt
,svg
,wsdl
,dita
,ditamap
- RTF output format:
rtf
Locale
Name: locale
Type: string (locale)
Default:
en_US
Command-line short name: A
Set the locale (language, country) used in templates. It has significance because different countries write numbers differently, sort text differently, 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: en
, en_US
, en_US_MAC
. FreeMarker will try to use the most specific available locale, so if you specify en_US_MAC
but that is not known, then it will try en_US
, and then en
, and then the default locale of the computer.
Also, the special value host
can be used to ask FMPP to use the default locale of the host operating system. However, for most applications it is not recommended to depend on the host locale, since then the output will depend on where you run the generation (and not on what people will use the output).
If you don't know what your locale string would be, use the --print-locales
option of the command-line tool. Note that unfortunately, the codes printed here are far the superset of locales that Sun's Java platform implementation actually correctly handles.
Note that the initial value of the setting is en_US
, because it is the locale that formats things similarly as a programmer would expect.
Number format
Name: numberFormat
Type: string
Default:
0.############
This specifies the default format of numbers when FreeMarker has to convert numbers to strings. For example, if you change this setting to 0.00
then:
${1}, ${1.1}, ${1.245}
will print (if the locale setting is en_US
):
1.00, 1.10, 1.25
Note that you can override the effect of this setting in the templates with <#setting number_format="something">
, also you can override this for each interpolations with ?string("something")
.
The syntax and semantic of the format string is as java.text.DecimalFormat
defines it. For convenience I quote a part from the documentation of java.text.DecimalFormat
:
Pattern Syntax
pattern := pos_pattern{';' neg_pattern} pos_pattern := {prefix}number{suffix} neg_pattern := {prefix}number{suffix} number := integer{'.' fraction}{exponent} prefix := '\u0000'..'\uFFFD' - special_characters suffix := '\u0000'..'\uFFFD' - special_characters integer := min_int | '#' | '#' integer | '#' ',' integer min_int := '0' | '0' min_int | '0' ',' min_int fraction := '0'* '#'* exponent := 'E' '0' '0'* Notation: X* 0 or more instances of X { X } 0 or 1 instances of X X | Y either X or Y X..Y any character from X up to Y, inclusive S - T characters in S, except those in T
Special Pattern Characters
Many characters in a pattern are taken literally; they are matched during parsing and output unchanged during formatting. Special characters, on the other hand, stand for other characters, strings, or classes of characters. They must be quoted, unless noted otherwise, if they are to appear in the prefix or suffix as literals.
The characters listed here are used in non-localized patterns. Localized
patterns use the corresponding characters taken from this formatter's
DecimalFormatSymbols
object instead, and these characters lose
their special status. Two exceptions are the currency sign and quote, which
are not localized.
Symbol | Location | Localized? | Meaning |
---|---|---|---|
0 | Number | Y | Digit |
# | Number | Y | Digit, zero shows as absent |
. | Number | Y | Decimal separator or monetary decimal separator |
- | Number | Y | Minus sign |
, | Number | Y | Grouping separator |
E | Number | Y | Separates mantissa and exponent in scientific notation. Need not be quoted in prefix or suffix. |
; | Subpattern boundary | Y | Separates positive and negative subpatterns |
% | Prefix or suffix | Y | Multiply by 100 and show as percentage |
\u2030 | Prefix or suffix | Y | Multiply by 1000 and show as per mille |
¤ (\u00A4) | Prefix or suffix | N | Currency sign, replaced by currency symbol. If doubled, replaced by international currency symbol. If present in a pattern, the monetary decimal separator is used instead of the decimal separator. |
' | Prefix or suffix | N | Used to quote special characters in a prefix or suffix,
for example, "'#'#" formats 123 to
"#123" . To create a single quote
itself, use two in a row: "# o''clock" . |
Boolean format
Name: booleanFormat
Type: string
Default:
true,false
Since: FMPP 0.9.15
This setting specifies how boolean values will be converted to text or from text inside FreeMarker templates (not in data loaders). However, confusingly enough, when this is true,false
(the default) then something like ${myBoolean}
is an error, because FreeMarker denies using "true,false"
for implicit boolean to text conversion. So to utilize this setting, set it to something different, like Y,N
, and then it will work as expected. Where you want to print true
/false
, write ${myBoolean?c}
(note the ?c
), which will always print true
/false
, regardless of the booleanFormat
setting.
This setting directly correspond to the FreeMarker setting with similar name, so find the full documentation there: FreeMarker settings.
Example: "Yes,No"
means that ${myBoolean}
will print Yes
or No
.
Date/time format
Name: dateFormat
Type: string
Default:
No default value
Name: timeFormat
Type: string
Default:
No default value
Name: datetimeFormat
Type: string
Default:
No default value
Name: timeZone
Type: string
Default:
No default value
Name: sqlDateAndTimeTimeZone
Type: string
Default:
No default value
Since: FMPP 0.9.15
These settings specify how date/time/date-time values will be converted to text or from text inside FreeMarker templates (not in data loaders, unless said otherwise).
These settings directly correspond to the FreeMarker settings with similar name, so find their full documentation there: FreeMarker settings.
Examples of datetimeFormat
-s: "dd.MM.yyyy HH:mm:ss"
(where HH
means 0-23 hours) or "MM/dd/yyyy hh:mm:ss a"
(where a
means AM or PM, if the current language is English), "iso"
(ISO 8601:2004 format), "xs"
(XML Schema format).
Examples of timeZone
-s: "GMT"
, "GMT+2"
, "GMT-1:30"
, "CET"
, "PST"
, "America/Los_Angeles"
, "JVM default"
When a format setting isn't set, the default format of the current locale (country) will be used, which are specified by the Java installation you run FMPP on. If the timeZone
isn't set, the time zone of the host computer will be used (specified by the Operating System).
Handling errors
Name: stopOnError
Type: boolean
Default:
true
Command-line short name: s, c
Be default when FMPP encounters problem during the processing of a source file, it terminates the whole processing session with the error. It can be annoying if you have many bad files, because you have to restart the whole session and wait until the session reaches another bungled template (or other kind of problematic source file), again and again, until you have fixed all of them. If you change this setting to false
, FMPP will not stop on the errors, just skips the problematic source file and continues the processing session with the next source file. You should use logFile
together in this case, so you can later digest all problems occured during the processing session.
Note that this settings will only suppress errors that occur during the processing of source files. It will not suppress errors like, for example, bad data files (unless it's loaded in a template with pp.data
) or invalid setting values.
Expert mode
Name: expert
Type: boolean
Default:
false
Command-line short name: x
This setting is to enable suspicious situations, when the engine or the tool suspects that you have miss-configured something, and thus an accidental data loss can happen. It is recommended to leave this setting false, until it actually blocks something that you want to do.
Please note that overwriting a file in general is a normal situation for FMPP; no expert mode required to do that.
Case sensitive path comparison
Name: caseSensitive
Type: boolean
Default:
false
This setting tells if FMPP should differentiate upper- and lower-case letters when it compares paths for equality, or when it matches paths to path patterns. Regardless of this setting, FMPP always tries to keep the case of file names (i.e. the output of Foo.txt
will be Foo.txt
, and not foo.txt
or FOO.TXT
), as far as the host operating system does not prevent this.
Logging
Name: logFile
Type: string (path)
Default:
No default value
Command-line short name: L
Name: appendLogFile
Type: boolean
Default:
No default value
If these settings are supported or not, depends on the front-end you use. If a setting is not supported, the front-end must silently ignore it.
If the logFile
setting is set, the front-end should record information about the processing session into the file, such as the warning messages and errors occurred.
If appendLogFile
is false
, then already existing log file (possibly left from the previous processing session) is deleted and restarted. This is the recommended default behavior, however a front-end may chooses something different. If appendLogFile
is true
, then old log file should be continued.
Please read the documentation of the front-end you use for the precise behavior of these settings.
Showing the progress and other messages
Name: quiet
Type: string
Default:
No default value
Command-line short name: q, v, Q
Name: echoFormat
Type: string
Default:
No default value
Command-line short name: F
Name: columns
Type: integer
Default:
No default value
Name: printStackTrace
Type: boolean
Default:
false
Name: snip
Type: boolean
Default:
true
If these settings are supported or not, depends on the front-end you use. If a setting is not supported, the front-end must silently ignore it.
The quiet
setting tells the front-end if how much should it show the progress of the processing session on the screen. The accepted values are true
, false
(of type string or boolean), and reallyQuiet
. Also, empty string is equivalent with true
. (Values -1
, 0
, 1
are also supported for backward compatibility.) The precise meaning of values is front-end specific.
The echoFormat
setting specifies how to display the progress of the processing session on the screen. The meaning of values and the set of understood values are front-end specific, but values verbose
, normal
, terse
and quiet
should be understood, also the shorthands of them: v
, n
, t
and q
. The front-end must not stop with error if it doesn't understand the value that comes from a configuration file.
The columns
setting specifies the number of columns on the console (terminal), which is used for text wrapping. This is only applicable if you are using a command line interface for FMPP (or something similar). If you are using the provided shell script to invoke the command line interface, that will try to auto-detect the actual value (since 0.9.15), so you shouldn't set this setting, unless the auto-detection gives incorrect result.
The printStackTrace
setting specifies if the front-end should print stack trace to the screen on error, or a terser error description. snip
is deprecated, and now it's just the inverted alias of printStackTrace
.
Please read the documentation of the front-end you use for the precise behavior of these settings.
Meta settings
Name: configurationBase
Type: string (path)
Default:
No default value
Name: inheritConfiguration
Type: string (path)
Default:
No default value
These settings influence the interpretation of the configuration file they are stored in. Although front-ends may support the specification of these settings outside configuration files, with the front-end specific interface, the meta setting specified in this way is used to emulate that the setting is present in the configuration file the front-end loads.
The configurationBase
setting sets the configuration base for the setting values stored in the same configuration file. If the configurationBase
itself is a relative path, then it is resolved relatively to the directory of the configuration file.
If inheritConfiguration
is present in a configuration file, then the configuration will inherit the configuration file pointed by the value of this setting. If inheritConfiguration
is a relative path, then it is resolved relatively to the configuration base, which is already overridden by configurationBase
if that's persent in the configuration file.
XML related settings
Name: xmlCatalogFiles
Type: sequence (of paths)
Default:
No default value
Name: xmlCatalogPrefer
Type: string
Default:
public
Name: validateXml
Type: boolean
Default:
false
Name: xpathEngine
Type: string
Default:
dontSet
Name: xmlRenderings
Type: sequence (of hashes)
Default:
empty
Catalogs
Catalog files are (primarily) used to map public identifiers (and system identifiers) to local files. For example, you want to load an XML file that starts with this:
<?xml version="1.0"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
Whenever you try to load this XML file, the XML parser will need the DTD requested by the DOCTYPE, so it will try to download it from http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd
(and all other files the DTD will refer to), which is obviously a bad joke. The standard solution is that you obtain the DTD file (and the further files it refers to) and store it locally on your computer, and also you write a catalog file that maps public identifiers (as -//W3C//DTD XHTML 1.0 Transitional//EN
) to the local paths of the files. Then, you have to specify the catalog file(s) for FMPP with the xmlCatalogFiles
setting.
FMPP supports the "widely known" catalog formats: OASIS plain text TR9401 catalog files, OASIS XML Catalogs, and XCatalogs. Delegate entries are supported. Don't panic if you can't undestand a word of it! :) Just look at <FMPP>/docs/examples/xml_validating
. For most people it's enough to know (copy-paste...) what (s)he sees there. If you still need more information, please visit the Web page of the OASIS Entity Resolution Technical Committee: http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=entity.
The meaning of xmlCatalogPrefer
should be clean if you are familiar with OASIS catalogs. If you are not, just left it unchanged. The allowed values of this setting are system
, public
, and globalDefault
.
Both catalog related settings has a global (Java virtual machine level) default. Please find the documentation of org.apache.xml.resolver
package on the Internet about this. In the case of xmlCatalogFiles
, the global default will be appended at the end of the list of catalog files. In the case of xmlCatalogPrefer
, the global default is used when the value of the setting is globalDefault
. Attention! If you don't use the xmlCatalogFiles
FMPP setting, then the catalog feature is disabled, so you must specify this setting (even an empty sequence) to use the global defaults.
Validation
The validateXml
setting specifies if, by default, XML files are validated (i.e. checked against the DTD) or not. With "by default" I mean that this can be overridden for individual files, as with the validate
option of the xml data loader.
XPath engine
The xpathEngine
setting specifies which XPath engine will FreeMarker use when you access XML data (see XML dataloader). This setting accepts these values:
jaxen
: Use Jaxen. For this to work, you need to obtainjaxen.jar
(1.1-beta-8 or later!), and make it accessible for FMPP (e.g. copy it into thelib
directory of the FMPP installation, or if you use FMPP as Ant task, then into thelib
directory of Ant). Jaxen provides richer set of capabilities for FreeMarker templates than Xalan.xalan
: Use Apache Xalan. Xalan is accessible for sure if you are using Sun J2SE 1.4, but not in 1.5.default
: Let FreeMarker choose the XPath engine it prefers. In FreeMarker 2.3 it will be Xalan (if available).dontSet
: Don't set what XPath engine will be used. For most users it is the same asdefault
(see below). This is the default value of the setting.- All other values are interpreted as the full-qualified class name of an XPath engine adapter class, that is, a
freemarker.ext.dom.XPathSupport
implementation.
If you embed FMPP into your application, then you have to know that XPath engine choosing is a VM level setting (static field) of FreeMarker. Whenever you execute a processing session, FMPP will aggressively set this FreeMarker setting according the xpathEngine
FMPP setting. Thus, if you don't want FMPP to interfere with other FreeMarker dependent components in the same VM, you should keep value dontSet
.
XML rendering
XML rendering is similar to the typical XSLT usage pattern, if you know that. The source file, for which renderXml
processing mode is choosen (see the modes
setting), will be parsed as XML file. Then, this XML document will be rendered to one or more output files with a FreeMarker template, which is choosen based on the value of the xmlRenderings
setting. The template gets the XML documents with the pp.doc
variable. Since the template shouldn't be executed in itself, it should be an ignored file (for example it should be stored in a directory that has an ignoredir.fmpp
file).
For an example of this pattern check <FMPP>/docs/examples/xml_rendering
.
Note: Sometimes you rather want to handle XML files as data than as source files. In this case use data
, localData
, or pp.loadData
with the XML data loader, not XML rendering.
The xmlRenderings
setting stores a sequence of XML rendering configurations. An XML rendering configuration is a hash that stores the options of an XML rendering. The options are:
- Options specify which XML files should be processed with the configuration:
IfSourceIs
: Optional, defaults to an empty sequence. This option is a sequence of path patterns (strings), or a single path pattern. FMPP will not render the XML file with this configuration if its source root relative virtual path does not match a pattern in this sequence. If this sequence is empty, FMPP will not consider this condition, that is, it will not exclude any XML files because of their path.ifDocumentElementIs
: Optional, defaults to an empty sequence. This option is a sequence of element names (strings), or a single element name. FMPP will not render the XML file with this configuration if this sequence doesn't contain the document element (the root element) of the XML file. If this sequence is empty, FMPP will not consider this condition, that is, it will not exclude any XML files because of their document element. The element names can use name-space prefixes. The prefixes and the default name-space of elements can be specified with thexmlns
option of the configuration.
- Options specify how to load the XML file. These are exactly the same as the options of the XML data loader (
xmlns
,index
, ...etc.), except thatfalse
value fornamespaceAware
is not allowed. - Options for java programmers, to build extra local data based on the loaded XML file.
localDataBuilder
: Optional, defaults to an empty sequence. This is a sequence of strings, or a single string. Each string will be evaluated as BeanShell script (once perSettings.execute()
), which must return anfmpp.LocalDataBuilder
. The aim of these data builders is to do the complex or resource eager parts of the XML processing that you don't want to do in FTL, and expose the results as local data. The data loaders can get the loaded XML document withtemplateEnvironment.getXmlDocument()
, ortemplateEnvironment.getWrappedXmlDocument()
. These data builders will be invoked after the application of thelocalData
setting, and can replace earlier added local variables. They will be executed in the same order as they appear in the sequence.
- Options specify how to render the XML document to output file:
template
: Required ifcopy
isfalse
. This is the source root relative virtual path of a FreeMarker template, which will be invoked to render the output. (The template file itself should be an ignored file, as it doesn't produce output alone.) The template can access the XML document with thepp.doc
variable.copy
: Required iftemplate
is not specified, defaults tofalse
. This is a boolean value. If it istrue
, then the XML document will be copied to the output file (exact copy). In this case thetemplate
option can't be used.
Example:
xmlRenderings: [ { ifDocumentElementIs: product template: renderer/product.html xmlns: {D: http://example.com/xmlns/products} } { ifDocumentElementIs: book template: renderer/book.html index: { element: [part, chapter] attribute: ppFile numbering: hierarchical value: '%e_%n.html' } } ]
When renderXml
processing mode is chosen for a source file (see modes
), then the first matching XML rendering configuration of the sequence will be used. A configuration is matching if nor the ifSourceIs
, nor the ifDocumentElementIs
option excludes the XML file. (Thus, if a configuration doesn't use any of the if...
options, it will be used for all source files, unless an earlier configuration matches the source file too.)
FreeMarker links (external includes)
Name: freemarkerLinks
Type: hash (of sequence of paths)
Default:
No default value
FreeMarker links is a dirty hack to satisfy a frequent demand: <#include ...>
/<#import ...>
files that are outside the source root directory, as common FTL macro libraries used in multiple projects.
Assume you store your commonly used FreeMarker includes in the c:\user\freemarker\include
directory. But, this directory is outside the sourceRoot
, so you can't reach it with <#include ...>
/<#import ...>
. To solve this, add this to the FMPP configuration file:
freemarkerLinks: { inc: c:/user/freemarker/include }
Now you can include files of that external directory like this:
<#include "/@inc/foo.ftl">
Here, FreeMarker will actually read c:\user\freemarker\include\foo.ftl
. The seeming @inc
entry in the source root directory (seeming, as there is no such file or directory there in reality) acts as an alias, a transparent link to c:\user\freemarker\include
. (Note that in the configuration file I have used slash instead of backslash for convenience.)
It is important that link entries (as @inc
above) are visible only for the predefined FreeMarker directives that use template paths (in FreeMarker 2.3, these are <#include ...>
and <#import ...>
), or for user defined directives that internally use those predefined directives. They are not visible for anything else. Thus, they are not visible for the functions and directives of the pp
hash, nor FMPP will try to process the @inc
directory (since it doesn't see it at all).
As you have seen, a link is defined by associating a name (inc
in the last example, but you can use anything else you prefer) with a path. You can have more links with different names. The link is visible in the source root (never in its subdirectories) as a directory (or file) of name @name
(where name
is the link name). Regarding the associated path, the rules are the same as with sourceRoot
, outputRoot
, ...etc: it is a real path, so if it is relative, then it will be interpreted relatively to the configuration base.
For example, assume, that you also have project specific include files, and you store them outside the source root (because you have multiple source roots in your project), in the include
subdirectory of the same directory, where you stores the FMPP configuration files for your project. Use this in the FMPP configuration file:
freemarkerLinks: { inc: /home/joe/freemarker/include projInc: include }
Note that the path associated with projInc
is a relative path, so it will be resolved relatively to the directory of the configuration file (unless you have overridden the configuration base, of course...). Now you can do things like this:
<#include "/@projInc/header.html"> <#include "/@inc/foo.ftl"> <#import "/@projInc/forms.ftl" as f>
If the configuration file that contains the above is /home/joe/projects/foo/cfg3.fmpp
, then <#include '/@projInc/header.html'>
will read /home/joe/projects/foo/include/header.html
.
In the generic case, a FreeMarker link is associated with a list of paths. For example:
freemarkerLinks: { inc: [/home/joe/freemarker/include, /home/kate/freemarker/include] }
When you use <#include '/@inc/foo.ftl'>
in a template, then FMPP will check if /home/joe/freemarker/include/foo.ftl
exist, and if not, it will try /home/kate/freemarker/include/foo.ftl
.
Files that are really in the source root directory have priority over files that are accessible through FreeMarker links. For example, if you invoke <#include '/@inc/foo.ftl'>
, and the source root directory has a subdirectory called @inc
, and that subdirectory has a file called foo.ftl
, then that file will be used, without considering that the @inc
in the path possibly refers to a FreeMarker link. If a subdirectory called @inc
exists, but it doesn't contain foo.ftl
, then the inc
link will be used.
A FreeMarker link can point to files as well, not only to directories. For example:
freemarkerLinks: { footer: /home/joe/footers/gpl.html }
and then in a template you can do this:
<#include "@footer">
The merging of the freemarkerLinks
settings is differs a bit from the merging of other hash settings: when the two hashes to merge contains the same key (i.e. the same link name), then the lists of paths for that key will be concatenated. For example, if common.fmpp
is:
freemarkerLinks: { a: c:/user/fm/libs1 b: [inc1, inc2] }
and config.fmpp
is:
inheritConfiguration: common.fmpp ... freemarkerLinks: { a: c:/user/fm/libs2 b: [inc3, inc4] c: foo } ...
then the resulting setting value is equivalent with:
freemarkerLinks: { a: [c:/user/fm/libs2, c:/user/fm/libs1] b: [inc3, inc4, inc1, inc2] c: foo }
Note that the name of the links doesn't start with @
; the @
is used only to refer to the links. To protect users from mistakes regarding this, it is not allowed to start a link name with @
.
Activating fixes/improvements
Name: recommendedDefaults
Type: string (version number)
Default:
0.9.15
Since: FMPP 0.9.16
Name: freemarkerIncompatibleImprovements
Type: string (version number)
Default from recommendedDefaults
0.9.15:
2.3.0
Default from recommendedDefaults
0.9.16:
2.3.28
Since: FMPP 0.9.15
recommendedDefaults
influences the default value of other settings. The setting value defaults will be those recommended as of the specified FMPP version. When you start a new project, set it to the current FMPP version (0.9.16 currently). In older projects changing this setting can break things, so check how the defaults change:
- 0.9.15: This is the baseline (and the default)
- 0.9.16: The following defaults change (compared to 0.9.15):
freemarkerIncompatibleImprovements
to 2.3.28, thus, among many things, templates withftlh
andftlx
file extensions will useHTML
andXML
auto-escaping respectively.mapCommonExtensionsToOutputFormats
totrue
, thus, templates with common file extensions likehtml
,xml
etc. will have auto-escaping (legacy escaping, like#escape
, or?html
will fail in them).removeFreemarkerExtensions
totrue
, thus, theftl
,ftlh
, andftlx
file extensions are automatically removed from the output file name.objectWrapper
to afreemarker.template.DefaultObjectWrapper
, iffreemarkerIncompatibleImprovements
is at least 2.3.21. There are more details, but it's highly technical, so if you care, see the JavaDoc of thefmpp.Engine
constructor.
The lowest allowed recommendedDefaults
value is 0.9.15, and the highest allowed is the version of the FMPP release that you are using.
freemarkerIncompatibleImprovements
enables the FreeMarker fixes/improvements that are not 100% backward compatible, and were implemented in the FreeMarker version given in this setting. In older projects using the highest available 2.3.x
usually works fine, but check what changes in the documentation. New projects should definitely use the maximum, which is the version of the FreeMarker used (fmpp --version
will print that, also, the current FMPP version was built with FreeMarker 2.3.28). See Configuration(Version)
in the FreeMarker API for more information, such as what fixes/improvements are activated.
The format of both these settings is major.minor.micro
, where each part is a positive integer without padding 0-s.
Object wrapping
Name: objectWrapper
Type: string (BeanShell expression)
Default from recommendedDefaults
0.9.15:
"b = new BeansWrapperBuilder(freemarkerIncompatibleImprovements); b.setSimpleMapWrapper(true); return b.build();"
Default from recommendedDefaults
0.9.16:
"b = new DefaultObjectWrapper(freemarkerIncompatibleImprovements); ...; return b.build(); /* See fmpp.Engine constructor JavaDocs */"
The objectWrapper
setting is for FreeMarker "experts" who want to use a customized ObjectWrapper
. The value of the setting is a BeanShell expression that must result in an object whose class extends the freemarker.ext.beans.BeansWrapper
class. The value can be a simple expression like "new com.example.MyWrapper()"
, or multiple instructions ending with a return
statement.
The freemarker.template.ObjectWrapper
, freemarker.template.DefaultObjectWrapper
, freemarker.template.DefaultObjectWrapperBuilder
, freemarker.ext.beans.BeansWrapper
, and freemarker.ext.beans.BeansWrapperBuilder
classes are automatically imported, so you don't have to use full-qualified class name for them. Also, a non-null
freemarkerIncompatibleImprovements
value is exposed, which corresponds to the effective value of the similarly named FMPP setting.
The ObjectWrapper
is created before other setting values (or the fmpp.Engine
instance for that mater), so the BeanShell expression has no access to any setting values, except to freemarkerIncompatibleImprovements
, as it was shown.
The default value shown is actually only used when freemarkerIncompatibleImprovements
is at least 2.3.21
. For more information please consult the JavaDoc of the fmpp.Engine
constructor.
Template syntax
Name: tagSyntax
Type: string
Default:
angleBracket
The tagSyntax
setting determines the syntax of tags in the templates (angle bracket syntax like <#include "foo">
VS square bracket syntax like [#include "foo"]
) that has no ftl
directive in it. If the template uses ftl
directive (like it starts with <#ftl>
or [#ftl]
), then the syntax of the ftl
tag determines the syntax of the template, and the tagSyntax
setting is ignored.
The possible values of this setting are angleBracket
, squareBracket
and autoDetect
. The recommended value is autoDetect
, which will auto-detect the syntax of each template independently, by choosing the syntax of the first FreeMarker tag in the template. For example when it finds a [@
in the template, it will choose square bracket syntax.
Name: interpolationSyntax
Type: string
Default:
legacy
Since: FMPP 0.9.16
The interpolationSyntax
setting determines the syntax of the interpolations (where you insert a value, like ${name}
) in templates.
The possible values of this setting are legacy
(like ${expression}
and the deprecated #{numericExpression}
), dollar
(means ${expression}
only), and squareBracket
(like [=expression]
. The recommended value is dollar
, unless the ${
pattern clashes with the static parts that you need to generate (like when you generate JSP or shell script), in which case use squareBracket
. The default is legacy
(as far as that's the default of FreeMarker).