iftpl
(see iftpl), which you can use to process templates. iftpl
is designed to work with configuration files. The Ionflux Tools Class Library also provides a class for handling these (see Ionflux::Tools::ConfigTree and Configuration file I/O).
iftpl
or Ionflux::Tools::Template on a template and set of data. A template consists of a combination of arbitrary text and template tags, which may be stored in a file or a buffer in memory. Template tags are used as special instructions to the template processor. For example, a tag may instruct the template processor to substitute the value of a variable in place of the tag, or to execute a part of the template only if a special condition is satisfied. Some tags, like foreach
and if
, may be nested to achieve special results.
myvar
In a configuration file, you can assign values to tree nodes:
myvar = foo
Subscripts are allowed and may either consist of a numeric index or a name:
myvar[1] = foo
myvar['foo'] = 42
You can also use the resolution operator to access child nodes of a node:
myvar.foo = bar
Actually, resolution in this way is handled the same way as a subscript, so it doesn't really matter which variant you use.
Finally, you can use the contents of a node as a name for a subscript or resolution operand:
foo = 1
bar = baz
myvar[.foo] = 2
myvar.(.bar) = 3
is the same as:
myvar[1] = 2
myvar['baz'] = 3
Note that, in this case, a leading resolution operator is needed to distinguish between a node reference and a subscript by name.
__i[<depth>]
Iteration counter for nesting level depth
(starting from 0). __n[<depth>]
Total number of iterations for nesting level depth
. __template_file
The name of the template file (set by iftpl
). __config_file
The name of the configuration file (set by iftpl
).__template_file
and __config_file
are available only if you are using iftpl
to process a template.
{include <file>}
This tag is replaced by the contents of another file (which may or may not be a template file itself). file
can be an absolute path or a path relative to the current working directory of the application using the template processor (for example iftpl
). Any template data included in this way will be treated by the template processor as if it had been there in the template being processed in the first place.
{$<path>[|<filter> ...]}
{.<path>[|<filter> ...]}
{<path>[|<filter> ...]}
This tag is replaced by the value contained in the variable path
. Optionally, a string filter is applied to the value before the substitution actually takes place (see String Filters). (By the way, it doesn't matter which of the various variants specified above you use in your template. All of them are valid variable substitution tags and behave exactly the same.)
{$<path> = <expr>}
{.<path> = <expr>}
{<path> = <expr>}
Assign the value resulting from evaluating expr
to the variable specified by path
.
{foreach <iterator> in <path>} ... [{empty} ... ] {/foreach}
A foreach
block will process the template section enclosed within its tags once for each element in path
. The current element is assigned to the variable iterator
. foreach
will process data entries of path
first, child nodes second. If there are no iterations (i.e. there are neither data entries nor child nodes), an optional empty
block will be processed instead of the main foreach block. The value of the iteration counter is made available in the special variable __i[<depth>]
, where depth
is the nesting level of the iteration block, starting from 0. The total number of iterations, including all data entries and child nodes, is made available in the special variable __n[<depth>]
(see Special Variables).
{first} ... {/first}
A first
block is processed only on the first iteration of an iteration block (such as foreach). Outside of an iteration block, the first
block simply does nothing. The tag also doesn't do anything if there is but a single element in the iteration, i.e. the total number of iterations is 1 (see single). Each iteration block may have an arbitrary amount of first
blocks, and it doesn't matter where they are placed within the iteration block.
{mid} ... {/mid}
A mid
block is processed on all but the first and last iteration of an iteration block (such as foreach). Outside of an iteration block, the mid
block simply does nothing. The tag also doesn't do anything if there is but a single element in the iteration, i.e. the total number of iterations is 1 (see single). Each iteration block may have an arbitrary amount of mid
blocks, and it doesn't matter where they are placed within the iteration block.
{last} ... {/last}
A last
block is processed only on the last iteration of an iteration block (such as foreach). Outside of an iteration block, the last
block simply does nothing. The tag also doesn't do anything if there is but a single element in the iteration, i.e. the total number of iterations is 1 (see single). Each iteration block may have an arbitrary amount of last
blocks, and it doesn't matter where they are placed within the iteration block.
{single} ... {/single}
A single
block is processed only if there is but a single iteration in an iteration block (such as foreach). Outside of an iteration block, the single
block simply does nothing. Each iteration block may have an arbitrary amount of single
blocks, and it doesn't matter where they are placed within the iteration block.
{notfirst} ... {/notfirst}
A notfirst
block is processed only if the current iteration is not the first iteration in an iteration block (such as foreach). Outside of an iteration block, the notfirst
block simply does nothing. Each iteration block may have an arbitrary amount of notfirst
blocks, and it doesn't matter where they are placed within the iteration block.
{notmid} ... {/notmid}
A notmid
block is processed only if the current iteration is not one of the inner iterations (i.e. it is either the first or the last iteration) in an iteration block (such as foreach). Outside of an iteration block, the notmid
block simply does nothing. Each iteration block may have an arbitrary amount of notmid
blocks, and it doesn't matter where they are placed within the iteration block.
{notlast} ... {/notlast}
A notlast
block is processed only if the current iteration is not the last iteration in an iteration block (such as foreach). Outside of an iteration block, the notlast
block simply does nothing. Each iteration block may have an arbitrary amount of notlast
blocks, and it doesn't matter where they are placed within the iteration block.
{notsingle} ... {/notsingle}
A notsingle
block is processed only if there is more than one iteration in an iteration block (such as foreach). Outside of an iteration block, the notsingle
block simply does nothing. Each iteration block may have an arbitrary amount of notsingle
blocks, and it doesn't matter where they are placed within the iteration block.
{if <condition>} ... [{else} ... ] {/if}
An if
block is processed only if condition
evaluates to true
, i.e. is not equal to zero. If the optional else
tag is also present, the corresponding block will be processed instead of the if
block if condition
evaluates to false
. You can use most operators and data types in the conditional expression. Data type conversion is performed automatically as necessary to evaluate the expression. Operands will be converted to the data type that most accurately represents the result of an operation. If an operator cannot reasonably be applied to a pair of operands, and they cannot be converted to suitable types either, the template processor will issue a warning.
{swrap <lineWidth> ['<prefix>'] ['<lineTerm>']}
Soft word wrapping is applied to the data resulting from processing the block enclosed in the swrap
tag. Wrapping takes place at whitespace boundaries in the input, with each resulting line no longer than lineWidth
, if at all possible. An optional prefix
is prepended to each line. The line terminator may be specified explicitly by supplying the optional lineTerm
argument.
{section <sectionName>}
A section is a part of the template that is not processed until it is referenced with the ref
tag. A section may be referenced an arbitrary number of times from within a template. It is also possible to reference a section from within itself, thus allowing for recursive template processing. Note that a section must be defined before it may be referenced.
{ref <referenceName> [restore]}
The ref
tag is used to reference a section within a template. The section will be processed in place of the ref
tag. If the optional resore
switch is specified, the environment will be restored after the section has been processed.