The pp hash is a variable that is always present in the data model. This contains the built-in, standard variables of FMPP.
Note: For more information about variable types, directives, etc. in general, please read the FreeMarker Manual.
Information about the source
sourceFile
Type: stringThe path of the current source file (includes the file name), relatively to the source root directory. It does not start with slash. Uses UN*X path format.
sourceDirectory
Type: stringThe path of the directory of the current source file, relatively to the source root directory. It is finished with a slash, except if the directory is the source root directory itself, in which case the result is an empty (0 length) string. The result never starts with slash. Uses UN*X path format.
sourceFileName
Type: stringThe filename of the current source file.
sourceEncoding
Type: stringThe encoding (charset) of the source file, e.g. ISO-8859-1
. It is always a concrete charset name, never host
.
sourceRoot
Type: stringThe absolute real path of the source root directory, finished with a "native slash" (i.e. maybe a backslash). As it is a real path, it uses the native path format.
realSource
Type: stringThe absolute real path of the current source file. As it is a real path, it uses the native path format.
realSourceDirectory
Type: stringThe absolute real path of the directory of the current source file, finished with a "native slash" (i.e. maybe a backslash). As it is a real path, it uses the native path format.
Information about the output
Note that as the output file name and directory, and the output encoding can be changed during the execution of template, the value of these variables can change during the execution of the template, to reflect the current situation.
outputFile
Type: stringThe path of the current output file (includes the file name), relatively to the output root directory. It does not start with slash. Uses UN*X path format.
outputDirectory
Type: stringThe path of the directory of the current output file, relatively to the output root directory. It is finished with a slash, except if the directory is the output root directory itself, in which case the result is an empty (0 length) string. The result never starts with slash. Uses UN*X path format.
outputFileName
Type: stringThe filename of the current output file.
outputEncoding
Type: stringThe encoding (charset) of the output file, e.g. ISO-8859-1
. It is always a concrete charset name, never host
or source
.
outputRoot
Type: stringThe absolute real path of the output root directory, finished with a "native slash" (i.e. maybe a backslash). As it is a real path, it uses the native path format.
realOutput
Type: stringThe absolute real path of the current output file. As it is a real path, it uses the native path format.
realOutputDirectory
Type: stringThe absolute real path of the directory of the current output file, finished with a "native slash" (i.e. maybe a backslash). As it is a real path, it uses the native path format.
Changing the output file
changeOutputFile
Type: directiveSupports nested content: no
Parameters:
- name: string. The new virtual path of the output file. The path can point into a different directory than the directory of the current output file.
- append=false: boolean. If this is true, then if a file with the same name as the name of the new output file already exists, it will be continued, rather then overwritten. If the file does not already exist, then this parameter has no effect.
Closes the current output file, and starts a new output file with the new name. All further output goes into the new file. If the name of the new output file is the same as the current output file, then nothing happens.
A word of warning: Don't forget that the path that you specifiy is interpreted relatively to the current output file. So using a relative path like products/${productName}.html
( instead of an absolute path like /shop/products/${productName}.html
) inside a loop is most certainly not what you want, because then 2nd product will go into the /shop/products/products/${productName}.html
directory, the 3rd into /shop/products/products/products/${productName}.html
, and so on. Of course this problem doesn't occur if the relative path is just a file name, like ${productName}.html
.
renameOutputFile
Type: directiveSupports nested content: no
Parameters:
- name: string. The new virtual path of the output file. The path can point into a different directory than the directory of the current output file.
- extension: string. Replaces the extension (the part after the last dot in the file name) of the current output file, with the value of this parameter. If the file name has no extension (there is no dot in it), then a dot and the new extension is added to the end of the file name. (The parameter value should never contain the starting dot.)
Changes the name of the current output file, or moves the output file if neccessary. If a file with the same name already exists, this will overwrite that file without warning. If the new name is the same as the name of the current output file, then nothing happens.
Either the name
or the extension
parameter must be specified. You can't use both together.
dropOutputFile
Type: directiveSupports nested content: no
Parameters: none
Deletes the current output file, and drops all further output that would go into this file. Call this directive at the beginning of templates that need to be processed, but you don't want any output files from them. (Of course, you can call this directive even at the end of the template, just that's slower...)
Note that this directive can be neutralized with directive pp.restartOutputFile
.
restartOutputFile
Type: directiveSupports nested content: no
Parameters: none
Empties the current output file (but doesn't delete the file). The next character sent to the output will be the first character of the output file. Also, the charset of the output file can be safely set, exactly like if you were at the beginning of the output file creation.
Note that this directive neutralizes the effect of directive pp.dropOutputFile
.
nestOutputFile
Type: directiveSupports nested content: yes
Parameters:
- name: string. The new virtual path (includes the file name) of the output file. The path can point into a different directory than the directory of the current output file.
- append=false: boolean. If this is true, then if a file with the same name as the name of the new output file already exists, it will be continued, rather then overwritten. If the file does not already exist, then this parameter has no effect.
This is similar to changeOutputFile
, but it writes only the content generated in its nested content into the new file, and then it restores things, so the output will go into the same output file as before the calling of the directive. For example:
The 1st line of the original file. <@pp.nestOutputFile name="new.txt"> The 1st line of new.txt. </@pp.nestOutputFile> The 2nd line of the original file. <@pp.nestOutputFile name="new.txt" append=true> The 2nd line of new.txt. </@pp.nestOutputFile> The 3rd line of the original file.
A file can be nested into itself. For example:
<@pp.nestOutputFile name='1.txt'> The 1st line of 1.txt <@pp.nestOutputFile name='2.txt'> The 1st line of 2.txt <@pp.nestOutputFile name='1.txt'> The 2nd line of 1.txt </@pp.nestOutputFile> The 2nd line of 2.txt </@pp.nestOutputFile> The 3rd line of 1.txt </@pp.nestOutputFile>
Note that append=true
was not needed for adding the 2nd line to the 1.txt
, since the directive just switched back to the already opened 1.txt
.
setOutputEncoding
Type: directiveSupports nested content: no
Parameters:
- encoding:
string.
The name of the charset, e.g.
ISO-8859-2
. It understands the special valuessource
andhost
.
Sets the encoding of the output. This will die with error if the output file is already partially written to the disk. Thus, if you want to change the output encoding, do it as early as possible. FMPP buffers the output for the output file in the memory until the buffer size reaches 160 characters, but after that it starts to flush the buffer to the disk. Also, directives that change the current output file may flush the buffer. When you start a new file (say, with changeOutputFile
), it starts a new buffer in the memory, so you can set the encoding of the new file.
Utilities for paths
pathTo
Type: methodResult type: string
Parameters:
- destination: string. The virtual path in the output file system to the destination file or directory. The destination file or directory need not exist.
This method returns the relative virtual path that leads from the directory of the current output file, to the destination file or directory. For example, if you want to create a link that points to <outputroot>/products/index.html
, then you can write:
<a href="${pp.pathTo('/products/index.html')}">Product index</a>
and the link will always point to that file, does not mater where the file that contains the above link is.
The returned path never starts with /
; it is always a relative path.
If the destination path is finished with slash, then, and only then, the resulting path will be also finished with slash, except if the only character in the result would be that slash, in which case the result will be an empty (0 length) string instead.
home
Type: stringSame as what pp.pathTo('/')
would return. That is, the virtual path to the output root directory, from the current output file. It is finished with a slash, except if the current output file is directly in the output root directory, in which case the result is an empty (0 length) string. The result never starts with slash. So the possible values are something like: ../../
Example: The src
will always point to the file in the img
directory of the output root, does not mater if you move the HTML file in the directory hierarchy:
<img src="${pp.home}img/logo.jpg" alt="Logo">
outputRootRelativePath
Type: methodResult type: string
Parameters:
- file path: string. The virtual output path to convert. The output file pointed by the path need not exist.
Converts a virtual output path to a virtual output path that is relative to the output root directory. The resulting path will not start with slash.
sourceRootRelativePath
Type: methodResult type: string
Parameters:
- file path: string. Same as the parameter of outputRootRelativePath, but it uses the the source file system.
Same as outputRootRelativePath, but it uses the source root directory and the current source file respectively.
sourcePathTo
Type: methodResult type: string
Parameters:
- destination: string. Same as the parameter of pathTo, but it uses the source file system.
Same as pathTo, but it uses the source root directory and the current source file respectively.
slash
Type: stringThe platform dependent slash character used in native paths. This will be backslash (\
) on Windows.
urlEnc
Type: methodResult type: string
Parameters:
- string to encode: string. The string to encode.
Deprecated: use the url
built-in of FreeMarker instead. For example: ${"a+b/c"?url}
.
Encodes a string with URL encoding. For example the result of pp.urlEnc("a+b/c")
will be a%2Bb%2Fc
, if the output charset is an US-ASCII based charset.
urlPathEnc
Type: methodResult type: string
Parameters:
- string to encode: string. The string to encode.
Same as FreeMarker's url
built-in (?url
), except that it does not encode slash characters. For example the result of pp.urlPathEnc("new products/bálna.html")
will be new%20products/b%E1lna.html
, if the output charset is ISO-8859-1.
Utilities for files
sourceFileSize
Type: methodResult type: number
Parameters:
- file path: string. The virtual path of the file in the source file system.
Returns the size of the file in bytes. If the file does not exist, it returns 0.
sourceFileLastModified
Type: methodResult type: date (date+time)
Parameters:
- file path: string. The virtual path of the file in the source file system.
Tells the last modification date+time of file. If the file does not exist, it raises an error.
sourceFileExists
Type: methodResult type: boolean
Parameters:
- file path: string. The virtual path of the file in the source file system.
Tells if the file exists or not.
outputFileSize
Type: methodResult type: number
Parameters:
- file path: string. The virtual path of the file in the output file system.
Returns the size of the file in bytes. If the file does not exist, it returns 0.
outputFileLastModified
Type: methodResult type: date (date+time)
Parameters:
- file path: string. The virtual path of the file in the output file system.
Tells the last modification date+time of file. If the file does not exist, it raises an error.
outputFileExists
Type: methodResult type: boolean
Parameters:
- file path: string. The virtual path of the file in the output file system.
Tells if the file exists or not.
realFileSize
Type: methodResult type: number
Parameters:
- file path: string.
The real path (native path) of the file. The file can be outside all root directories. FMPP passes the resolving of relative paths to the host OS, so it is not defined by FMPP what the end result will be. In general, it is better to use absolute paths here.
Windows users: According to the syntactical rules of FTL, you must use double backslashes in string literals:"C:\\work\\foo\\bar.txt"
, or use raw strings:r"C:\work\foo\bar.txt"
. Also, according to the Windows API rules, you can simply use slash:"C:/work/foo/bar.txt"
, which is probably the best solution.
Returns the size of the file in bytes. If the file does not exist, it returns 0.
realFileLastModified
Type: methodResult type: date (date+time)
Parameters:
- file path: string. The real path (native path) of the file. The rules are the same as with realFileSize.
Tells the last modification date+time of file. If the file does not exist, it raises an error.
realFileExists
Type: methodResult type: boolean
Parameters:
- file path: string. The real path (native path) of the file. The rules are the same as with realFileSize.
Tells if the file exists or not.
Writable hashes and sequences
Writable sequences and hashes are an FMPP specific extension to FreeMarker, as FreeMarker does not support the modification of sequences and hashes. (This has good reasons in the on-the-fly dynamic page generation segment that FreeMarker mostly targets, but it can be a problem in extreme FreeMarker applications as FMPP.) To read the variables of these sequences and hashes, you can use the same expressions as with plain sequences and hashes. But, to modify the contents of them, you have to use the directives described below, since predefined directives as <#assign ...>
can't modify subvariables. Unfortunately, sequence addition, sub-sequence operator (like seq[5..10]
) and ?reverse
do not copy the original sequence, just wraps it (for efficiency), so the resulting sequence will change if the original sequence is changed later (this is basically an abnormal aliasing effect). The same problem exists with the result of hash addition; 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 like: <#assign b = pp.newWritableSequence(a[5..10])>
and <#assign c = pp.newWritableHash(hashA + hashB)>
). Of course this is easy to miss... so rather try to build the data model so you will not need to modify collections. Keeping templates simple and moving complex calculations out to custom data loaders or BeanShell scripts (see the bsh
function of localData
here...) is advisable anyway.
Note that only the sequences that were made with the newWritableSequence
method are writable. Also, only the hashes that were made with the newWritableHash
method are writable. You can't modify plain sequences or hashes with the below directives.
Also note that writable sequences and hashes suffer from the effect called aliasing (that most programmers will find natural). This effect, explained with an example, looks like this:
<#assign a = pp.newWritableSequence()> <@pp.add seq=a value="red" /> <#assign b = a> <@pp.add seq=b value="green" /> a: <#list a as i>${i} </#list> b: <#list b as i>${i} </#list>
Here the output will be:
a: red green b: red green
That is, FreeMarker variables just store a reference (pointer) to the sequence or hash, not the sequence or hash itself. So both a
and b
points to the same single sequence object, which floats somewhere in the memory. This fact becomes significant because you modify that object, otherwise you wouldn't notice it. To create individual copies, use newWritableSequence
or newWritableHash
, for example:.
<#assign a = pp.newWritableSequence()> <@pp.add seq=a value="red" /> <#assign b = pp.newWritableSequence(a)> <@pp.add seq=b value="green" /> a: <#list a as i>${i} </#list> b: <#list b as i>${i} </#list>
Here b
is a new sequence whose initial content is the same as the content of a
. Thus, the output will be:
a: red b: red green
newWritableSequence
Type: methodResult type: writable sequence
Parameters:
- initial content: sequence, optional.
Creates a new empty writable sequence. However, if called with parameter then adds the items in the parameter sequence to this new sequence (known as "shallow copy" among programmers). Example:
<#assign a = pp.newWritableSequence()> <#assign b = pp.newWritableSequence(['red', 'green', 'blue'])> ${a?size} ${b?size}
The output will be:
0 3
newWritableHash
Type: methodResult type: writable hash
Parameters:
- initial content: hash, optional.
Creates a new empty writable hash. However, if called with parameter then adds the items in the parameter hash to this new hash (known as "shallow copy" among programmers). Example:
<#assign a = pp.newWritableHash()> <#assign b = pp.newWritableHash({'red':'FE0000', 'green':'10F000', 'blue':'0007FF'})> ${a?size} ${b?size}
The output will be:
0 3
copyWritable
Deprecated: UsenewWritableSequence
and newWritableHash
instead.Type: method
Result type: writable hash or writable sequence
Parameters: none
Copies a writable hash or sequence. (It is used to prevent aliasing effect. The result is a "shallow copy" of the original hash or sequence.)
add
Type: directiveSupports nested content: no
Parameters:
- seq: writable sequence. The sequence to modify.
- index=seq?size: number. The index where you want to insert the subvariable into the sequence. The index of the first subvariable is 0.
- value: any. The new value of the subvariable.
Inserts a new subvariable into the sequence, at the specified index. Shifts the subvariable currently at that position (if any) and any subsequent subvariables to the right (adds one to their indices). If you do not use the index
parameter, or if its value is 1 higher than the index of the last subvariable, then it appends the new subvariable at the end of the sequence.
set
Type: directiveSupports nested content: no
Parameters:
- seq: writable sequence. The sequence to modify.
- index: number. The index of subvariable to set. The index of the first subvariable is 0.
- hash: writable hash. The hash to modify.
- key: string. The name of the subvariable that you want to add to the hash, or that you want to replace.
- value: any. The value of the new subvariable.
This can be used for two purposes, depending on if you use the seq
or the hash
parameter:
- For sequences: Sets an already existing subvariable of the sequence or hash. The index must be the index of an existing subvariable, or an error will occur.
- For hashes: Adds a new subvariable to the hash with the name specified with the
key
parameter, or replaces the subvariable with the same name if that already exists.
remove
Type: directiveSupports nested content: no
Parameters:
- seq: writable sequence. The sequence to modify.
- index: number. The index of the subvariable to remove.
- hash: writable hash. The hash to modify.
- key: string. The name of the subvariable that you want to remove from the hash.
This can be used for two purposes, depending on if you use the seq
or the hash
parameter:
- For sequences: Removes the subvariable on the specified index, and shifts any subsequent subvariables to the left (subtracts one from their indices). The
index
must denote an existing subvariable, or an error will be raised. - For hashes: Removes the subvariable with the name specified with the
key
parameter, or does nothing if no such subvariable exists.
clear
Type: directiveSupports nested content: no
Parameters:
- seq: writable sequence. The sequence to clear.
- hash: writable hash. The hash to clear.
Removes all subvariables of the sequence or hash.
Miscellaneous
warning
Type: directiveSupports nested content: no
Parameters:
- message: string. The warning message.
Issues a warning message. It depends on the concrete front-end in use and the settings, but usually the message will be displayed on the screen and/or will be added to the log file. The processing will not stop if you issue a warning. To stop processing with error message you should use <#stop "message">
.
ignoreOutput
Type: directiveSupports nested content: yes
Parameters: none
All text generated inside the nested content of this directive will be thrown away.
locale
Type: stringThe currently used locale in the usual format. For example: ar_SA
, ar_IQ
, en_US
, en_UK
, es_ES
, ...etc.
loadData
Type: methodResult type: any
Parameters:
- loader name: string. The name of the data loader.
- arguments...: any. The arguments to the data loader. These are 0 or more arguments.
Loads data using data loaders, and returns the loaded data as the result of the method call. For example this:
<#assign foo = pp.loadData('csv', 'foo.txt', {'separator':',', 'encoding':'UTF-8'})>
does something similar as when you use the below in an FMPP configuration file:
data: {foo:csv(foo.txt, {separator:',', encoding:UTF-8})}
The difference is that with the pp.loadData
, you load the data on demand, and into a temporary variable that will be available only for a single template processing.
The get
data loader can't be invoked with this method.
now
Type: date (date+time)Returns the current date and time.
For example this:
Current date and time: ${pp.now} Current time: ${pp.now?time} Current date: ${pp.now?date} Current day of week: ${pp.now?string("EEEE")} <#setting datetime_format="yyyy-MM-dd HH:mm:ss zzzz"> Current date and time: ${pp.now}
will output something like this:
Current date and time: Apr 12, 2003 5:28:50 PM Current time: 5:28:50 PM Current date: Apr 12, 2003 Current day of week: Saturday Current date and time: 2003-04-12 17:28:50 Central European Summer Time
For more information about using date/time values, please read the FreeMarker Manual.
sessionStart
Type: date (date+time)Returns the date and time of the processing session starting.
s
Type: writable hashStands for "shared". This is a writable hash that keeps its content during the whole processing session. That is, if you add a subvariable to it during the execution of a template, then that subvariable will be visible for all templates processed later in the same session. An example of the usage of pp.s
can be found in <FMPP>/docs/examples/session
doc
Type: nodeThis variable exists only while an XML file is processed in renderXml
processing mode (see the documentation of the modes
setting). This variable stores the source file (the XML file) as a node variable that corresponds to the W3C DOM document object.
An example that uses renderXml
processing mode and pp.doc
is <FMPP>/docs/examples/xml_rendering
version
Type: stringThis is the version number of the FMPP engine.
freemarkerVersion
Type: stringThis is the version number of the FreeMarker the FMPP engine currently uses.