# The pp Hash

Page contents

Alphabetical index of keys:

The pp hash is a variable that is always present in the data model. This contains the built-in, standard variables of FMPP.

### sourceFile

Type: string

The 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: string

The 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: string

The filename of the current source file.

### sourceEncoding

Type: string

The encoding (charset) of the source file, e.g. ISO-8859-1. It is always a concrete charset name, never host.

### sourceRoot

Type: string

The 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: string

The absolute real path of the current source file. As it is a real path, it uses the native path format.

### realSourceDirectory

Type: string

The 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.

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: string

The 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: string

The 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: string

The filename of the current output file.

### outputEncoding

Type: string

The encoding (charset) of the output file, e.g. ISO-8859-1. It is always a concrete charset name, never host or source.

### outputRoot

Type: string

The 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: string

The absolute real path of the current output file. As it is a real path, it uses the native path format.

### realOutputDirectory

Type: string

The 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: directive
Supports 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: directive Supports 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: directive Supports 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: directive Supports 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: directive Supports 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: directive Supports nested content: no Parameters: • encoding: string. The name of the charset, e.g. ISO-8859-2. It understands the special values source and host. 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: method Result type: string Parameters: 1. 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: string

Same 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: method Result type: string Parameters: 1. 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: method Result type: string Parameters: 1. 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: method Result type: string Parameters: 1. 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: string The platform dependent slash character used in native paths. This will be backslash (\) on Windows. ### urlEnc Type: method Result type: string Parameters: 1. 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: method
Result type: string
Parameters:
1. 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: method
Result type: number
Parameters:
1. 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: method
Result type: date (date+time)
Parameters:
1. 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: method
Result type: boolean
Parameters:
1. file path: string. The virtual path of the file in the source file system.

Tells if the file exists or not.

### outputFileSize

Type: method
Result type: number
Parameters:
1. 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: method
Result type: date (date+time)
Parameters:
1. 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: method
Result type: boolean
Parameters:
1. file path: string. The virtual path of the file in the output file system.

Tells if the file exists or not.

### realFileSize

Type: method
Result type: number
Parameters:
1. 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: method
Result type: date (date+time)
Parameters:
1. 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: method
Result type: boolean
Parameters:
1. 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()>
<#assign b = a>
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()>
<#assign b = pp.newWritableSequence(a)>
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: method
Result type: writable sequence
Parameters:
1. 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: method
Result type: writable hash
Parameters:
1. 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: Use newWritableSequence 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.)

Type: directive
Supports 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: directive
Supports 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: directive
Supports 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: directive
Supports 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: directive
Supports 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: directive
Supports nested content: yes
Parameters: none

All text generated inside the nested content of this directive will be thrown away.

### locale

Type: string

The currently used locale in the usual format. For example: ar_SA, ar_IQ, en_US, en_UK, es_ES, ...etc.

Type: method
Result type: any
Parameters:
2. 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

### sessionStart

Type: date (date+time)

Returns the date and time of the processing session starting.

### s

Type: writable hash

Stands 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: node

This 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: string

This is the version number of the FMPP engine.

### freemarkerVersion

Type: string

This is the version number of the FreeMarker the FMPP engine currently uses.