nstcl  >  Documentation  >  nstcl-templating  >  adp

Tcl Powered!



adp — The nstcl templating system


package require nstcl-templating ?1.0?
package require nstcl ?1.0?


The nstcl templating system is a re-implementation of the templating portions of the ArsDigita Community System's publishing system (as it existed in the ACS 4.2 Tcl version).


Variables server as placeholders for dynamic data. There are two types of variables: scalars and rows. A variable name may be made up of any alphanumeric character, plus the underscore, surrounded by @ signs. The columns of a row variable are referenced by separating the data source name and the column with a period. A handful of special variables (that the templating system automatically makes available in certain situtation) contain a colon.

A scalar variable looks like: @email_address@. When the template is processed the Tcl variable email_address will be substituted in place of @email_address@.

A list variable, inside of a <list> tag, looks like: @listname:item@.

A row variable looks like: @user.city@ @user.state@ @user.zipcode@, etc. This example could be a one row data source (in which case the templating system would look for the Tcl array user and substitute its contents), or a multirow datasource built up with either the multirow templating command, or obtained from a database with db_multirow, and used inside of either a <multirow> or <grid> templating tag.

With the exception of the special @datasource:rowcount@ variable, multirow and list variables may only be referenced inside a containing <multiple>, <grid>, or <list> tag.

Naturally an attempt to reference a variable that does not exist results in an error. You can use the <if> templating tag to check and see whether a variable exists or not.


The <multiple> tag is used to repeat a portion of the template (contained between <multiple> ... </multiple>), for every row in a specified datasource. It has one required parameter: the name of the multirow data source. Multirow datasources can be created with either the multirow command, or queried directly from a database with the db_multirow command.

EXAMPLE: Generating the datasource
    # In the Tcl datasource file
    db_multirow friends friends_query {
        select name, email, phone, flavor as favorite_ice_cream
          from friends
         order by favorite_ice_cream desc, name
EXAMPLE: In the adp template
    <!-- in the adp file, to render an HTML table -->
    <multiple name="friends">
The maxrows attribute may be used to limit the number of rows that are processed:
        <multiple name="foo" maxrows="10"> ... </multiple>
The startrow attribute may be used to skip some initial number of rows:
        <multiple name="bar" startrow="5"> ... </multiple>
You can determine the number of rows with @datasource:rowcount@. Along the same lines, the variable @datasource.rownum@ can be tested to determine the current row being evaluated.


The <group> tag is used inside of the body of a <multiple> tag to allow additional formatting control between rows of a multirow datasource. It is illegal to use this tag outside of a <multiple> tag.

The <group> tag takes the name of a column and repeats it's enclosed template section for every row as long as the value of the column does not change from row to row. For finer grained control <group> tags may be nested.

EXAMPLE: In the adp template
    <!-- in the adp file, assume same datasource as last example -->
    <h1>My Ice-Cream Loving Friends</h1>
    <multiple name="friends">
        <group column="favorite_ice_cream">
            <li>@friends.name@ (@friends.phone@)


The <grid> tag is simillar to the <multiple> tag--it iterates over the rows of a datasource--however, instead of iterating sequentially over each row (1, 2, 3, etc.) the <grid> tag iterates in column order. The <grid> tag has two required parameters: cols, the number of columns, along with the name of the multirow datasource.

If a datasource had 10 rows, and the number of columns was specified as 3, the rows would be output in this evaluated in this order: 1, 5, 9, 2, 6, 10, 3, 7, null (11), 4, 8, null (12). The two null rows are included since 10 is not evenly divisible by 3.

@datasource.rownum@ is equal to the current rownum in the datasource that is being processed. @datasource:rowcount@ is equal to the number of rows in the datasource. If the number of rows is not evenly divisible by the number of columns then there will be iterations when @datasource.rownum@ is greater than @datasource:rowcount@. Additionally, @datasource.row@ and @datasource.col@ are set to the current row and column number of the grid.


The <list> repeats a template section for each element of a list. It takes one parameter, name, which is the name of the list (a regular Tcl variable in the datasource).

    <list name="files">
        <li> @files:item@
@datasource:rownum@ is the current position within the list (the first element being 1, not 0), and @datasource:rowcount@ is equal to the number of elements in the list. @datasource:item@ is the element itself. Of these, only the @datasource:rownum@ may be used outside of the body of the <list> tag.


The <if> tag tests a condition and selectively evaluates a template section only when the condition is true. Any templating variable may be used in the <if>. Literal text which contains spaces should be enclosed in quotation marks.

Compound statements may be used be connected with the keywords and & or. There is no grouping mechanism that changes the order of operation. An <else> tag may be used following an <if> tag. As you would expect, the <else> tag is evaluated only when the condition is not true.

There are six unary operators: nil, defined, odd, even, true, and false.

There are six binary operators: gt (greater than), ge (greater than or equal to), lt (less than), le (less than or equal to), eq (equals), and ne (not equals).

There is one ternary operator: between.

There is one n-ary operator, in which, if used in a compound expression must come last.

Any operator can be negated by prepending the not keyword.

    <if @email@ eq "bgates@microsoft.com">
        You are a rich monopolist!

    <if @temperature@ lt 65>
        It's chilly.
        <if @temperature@ between 65 80>
            It's comfortable.
        <if @temperature@ not between 65 80>
            It's hot!

    <if @platform@ in Unix Macintosh Windows>
        You can run Tcl/Tk!

    <multiple name="datasource">
        <if @datasource.rownum@ odd and @datasource.rownum@ ne @datasource:rowcount@>
            Row #@datasource.rownum@ is odd, and it isn't the last row.

    <if @foo@ defined>
        This is true when the variable foo exists.

    <if @foo@ not defined>
        This is true when the variable foo does not exist.

    <if @foo@ not nil>
        This is true when the variable foo exists and it's value
        is not the empty string.

    <if @var@ nil>
        This is true when either the variable foo does not exist, or
        it does, but is equal to the empty string.


The <include> tag allows you to (surprise) include another template within the current template. The only required parameter is src, which should be the path to the .adp file of the template.

Other arguments (given as key=val) are passed to the included template as variables. If key is prefixed by an &, then the datasource val in the current template will be passed to the included template by reference. In this case, key and val may be, but do not need to be, the same. A shorthand notation of &=val may be used when passing a datasource by reference, and the name of the datasource is to be the same in both the current and the included template.

    <include src="include-me.adp" email=@email@ &=vital_stats &friends="amigos">


The <master>, which has one attribute, src, specifies the name of another template in which the output of the current template should be placed. The location of the current templates output within the master template is determined by the location of the <slave> tag in the master template.

A master template may itself be a slave to another master, provided circular loops are avoided.

A slave may propogate variables up to it's master by using the <property> tag.


The <slave> tag marks the position within the master template where the output of the slave template should be placed.

    <if @title@ not nil><title>@title@</title></if>
    <if @title@ not nil><h1>@title@</h1></if>
    <else><h1>Unknown Document</h1></else>


The <property> tag is used to propogate variables upwards from the slave to its master. The <property> tag has one attribute, name, which specifies the name of the variable to be set in the master template. The value of the variable set in the master is the content enclosed by the <property>...</property> tags.

    <master src="master">
    <property name="title">My homepage as of @todays_date@</property>
    This is my homepage and today is @todays_date@ ...


The <noparse> tag is used to encapsulate a section of a template whose template tags should not be parsed. This is mostly useful only when one template is dynamically generating another. Normal variables are interpreted, even inside of a <noparse> tag. Escape the @ signs with a backslash to prevent variable substitution from occuring.


adp_compile, adp_eval, db_multirow, multirow


adp, nstcl, templating