ITL

Interchange functions are accessed via the Interchange Tag Language (ITL).
The pages in a catalog may be mostly HTML, but they will use ITL tags
to provide dynamic content and access Interchange functions in general.
ITL is a superset of MML, or Minivend Markup Language.

ITL tags perform all kinds of operations.
There's more than 200 standard predefined tags, and the
UserTag facility allows you to create your own custom tags,
indistinguishable from the ones "built-in". To get started
with custom tags, see usertag glossary entry.

Basics

ITL tags are similar to HTML, in that they accept
attributes and that there are both
standalone (non-container) and
container tags.

A container tag has both beginning and ending elements, such as tag if:

[if value name]
You have provided us with your name. It is [value name].
[/if]

In the above example, you see that container tags are in general
useful only when content is provided in their body
(the place between the opening and corresponding ending tag).

There must be no whitespace
between the left bracket ([) and the tag name; [forum] is
valid, [ forum] is not!

Standard Syntax

We've covered the most basic syntax above. If you need to pass
attributes to the tag, you do that in the opening section.
If the tag is a container, then body text can additionally be specified
between the opening and closing marker:

[tagnameparameters_or_attributes]
Body Text
[/tagname]

Note that some Interchangemacros (drop-in text replacements)
may look like tags or end tags. For example, [/page] used to
be a macro that expanded to </a>, but [page]
itself was not a container tag and [/page] wasn't its
closing element. Likewise, some tags perform special subtags processing
on their own, and the subtags are not considered real tags —
they only exist in the context of the surrounding tag and usually support
only limited options. One such example is tag [row] with its subtag
.

It is important to mention that
if a tag or argument name
includes an underscore or dash (such as in [item-list]), then you can
always choose between the dash and
underscore! The two forms are interchangeable, except that you
must be consistent with tag markers; an ending tag must match the opening tag.
Both [item-list]...[/item-list] or
[item_list]...[/item_list] are fine, but
[item-list]...[/item_list] is
not.

This is a very convenient feature. It is a common standard to use dashes
(-) in ITL, and underscores (_)
in Perl code (because in Perl, dashes would be interpreted as minus operators,
which is not what you'd expect).

Named and Positional Parameters

There are two styles of supplying attributes to a tag:
named and positional.

In the named style, you supply attributes using
key=value
pairs, just as with HTML:

[value name=variable_name]

The positional-style tag that accomplishes the same thing, but is more
compact:

[value variable_name]

Positional syntax, however, requires support by each tag individually. That
is, set of arguments that can be specified in positional notation (as
well as their position in the set) are fixed and determined in advance. You can
see a list of accepted positional arguments (and their implicit order) in
each tag's SYNOPSIS reference section; try [value] for example.

You cannot mix named and positional
attributes in the same tag; use either all named, or all positional.

In most cases, positional attributes (called parameters)
work the same as named attributes. However, there are a
few situations where you must use named attributes:

When you want to specify a parameter that, positionally, comes after a
parameter that you want to omit, e.g. omit the first parameter but specify
the second. The parser would have no way of knowing which is which, so
you must revert to named syntax. This rarely happens, though, because the
first positional parameter is usually required for a given tag anyway, and
can't be omitted.

When there is some ambiguity as to which parameter is which, usually
due to whitespace. If the argument value contains any whitespace
(even if it is enclosed in quotes!), you
must use named syntax.

When you need to interpolate the value of an attribute, such
as of default= in
[value name=time default="[time]"].

When you are using looping subtags (Loop tags and subtags are explained below).

HTML Comments

ITL also supports a special notation where you use HTML comment
markers with ITL inside, and where the comments are removed by Interchange
so that the tag results show up in the generated HTML page.

That means [tagname...]
and <!--[tagname...]--> are equivalent.

This allows you to make your raw ITL tags appear as comments in HTML
browsers, and especially in HTML editors which might not like non-HTML markup
at random positions.
You might want to use this if your editor has trouble with
ITL tags when editing Interchange page templates, or alternatively, if
you want to use one .html file both as an Interchange
page and as a static page delivered directly by your web server where no
Interchange processing is performed.

When you really wish to treat HTML comments as plain comments and not remove
them, then you must include a whitespace between the HTML comment delimiters
and the ITL square brackets:

ITL is interpolated in both cases however. To prevent ITL
interpolation within HTML comments, you
either need to see the no_html_comment_embed pragma, or enclose
the block in a special ITL[comment] tag instead of in
HTML comment:

Besides not being interpolated at all, [comment] blocks do not
appear in the final HTML sent to the client either, so you can be completely
safe regarding any unintentional code or information leakage.

While <!--[ and [ are completely
interchangeable, the Interchange parser does not replace ]-->
with ] unless it sees <!--[at least once somewhere on the page.
This is a small parsing speed optimization and shouldn't cause you any
trouble as you're supposed to be consistent in your syntax anyway.

Argument Interpolation

When ITL tags are expanded, for example when
[value name] yields the actual user's name, we say the tags
are interpolated.

If you want to use one tag's output as another tag's input, you
must use named syntax and you must double-quote the
argument. For example, this WILL NOT work:

[page scan se=[scratch variable_name]]

The above code is in really bad shape. To make it work, we
need to do two things: switch to named syntax, and properly quote arguments
containing whitespace:

[page href=scan arg="se=[scratch variable_name]"]

Note that the href argument did not need to be
quoted; arg did, because it
contained a whitespace and it contained a tag intended for interpolation
([scratch variable_name]).

Note

As you can implicitly see from the above example, attribute values
are normally interpolated (in other words,
se=[scratch variable_name] was expanded to
se=VARIABLE_VALUE
before being passed as value to arg=.

Deeper Look at Argument Quoting

The question is — exactly when can you omit the quotes around
argument values? First answer is trivial; never omit the quotes and you'll
never run into trouble.

The other answer says, "omitting quotes earns you a bonus for style and achieves
small parser speed improvement". However, if the value contains a whitespace,
you must quote it.
To quote values, you can use double quotes ("),
single quotes (') and
pipes (|) interchangeably.
Pipes have the additional functionality of
removing leading and trailing whitespace, but generally you can use
all types in combination to do three levels of quoting with ITL; for
more deeply nested constructs, use direct Perl code.

Additionally, container tags
can be closed using "XML-style" syntax.
The following two lines are identical in effect:

Note, however, that you can use "/]"
only with tags for which you provide no attributes, or the attributes are named
and quoted.
Positional attributes (parameters)
"absorb" everything (including the "/") up to the closing
bracket, and therefore using "/]" is not possible.

When using "/]" notation, it is still possible to provide body for the tag
by specifying body= attribute.

The above covers a good deal of quoting, but it's still not all
there is to it.
Loop subtags, which we explain some lines
below, are an exception to the rule and do not need quotes
(even though they sometimes contain whitespace),
because they are parsed earlier in a separate pass, before the
general parser takes on.

Here's an example with loop subtags that would work properly even
with quotes omitted. (Pay attention
to [item-field url] which, at first sight, looks like it is
invalid because it contains a space and is not quoted nor named.)

You might wonder why unquoted tags are allowed. The answer is
performance. If you have large lists of tags you can
achieve significant speed-ups by using positional attributes. Parsing and
disassembling named attributes takes some more CPU cycles.

Accessing Perl from ITL

Perl-related ITL tags

Among ITL tags, [perl], [calc], [calcn] and [mvasp]
are used obtain direct access to the Perl language in Interchange pages.
In fact, all the ITL tags are only extensions (and convenience features)
built on top of Interchange's Perl core, so all ITL tags boil down to Perl
code anyway. Using Perl directly could have the benefits of:

As you see, this notation (and implied functionality) is completely valid
and possible. It is then just up to the called tag to handle attribute value
appropriately.

Note

It is only possible to use the backticks notation with
named parameters!

Universal Attributes

Universal attributes apply to all tags, although tags might specify
their own defaults for the attribute. The code implementing universal
attributes is independent of the routines that implement specific
tags.

We will explain interpolate and
reparse attributes here.
It is important to remember that the behavior of the
interpolate attribute (unfortunately) differs,
based on whether a tag is stand-alone or a
container.
In addition,
the reparse attribute is only used with
container tags.

With standalone tags, the interpolate attribute
specifies whether the output of the tag will be
interpolated.
Output of most of the stand-alone tags is not interpolated by default.
Exceptions to this rule would include, for example, the [include] tag.

With container tags, the interpolate attribute
specifies whether the tag body will be
interpolated before being passed to the tag.
The reparse attribute specifies whether
output will be interpolated.

For an interpolation example with container tags, let's assume the
user's name is Kilroy:

The first line would log "Kilroy was here" to
CATROOT/etc/log,
while the second line would log pretty useless "[value name] was here".

For an interpolation example with stand-alone tags, consider the following:

[set name=now interpolate=0][time]%A, %B %d, %Y[/time][/set]

We've set the scratch variable new to not contain the
actual date, but the ITL code to calculate and display the date each time
it's called. Let's assume today is Monday, January 1, 2001, and we have the
following code:

[scratch name=now interpolate=1]
[scratch name=now interpolate=0]

The first line would then produce the expected
Monday, January 1, 2001, while the second would
leave us with unusable [time]%A, %B %d, %Y[/time].

The example above serves to show interpolate used
with a stand-alone tag. This behavior can only be achieved by using
reparse attribute if you're having a container
instead of the stand-alone tag.

The reparse attribute is only used with container
tags, and specifies whether the tag output will be
interpolated. This is basically the same as the
interpolate attribute for stand-alone tags, but a
new name had to be invented because interpolate
already performed a different function with container tags, when
this functionality was to be added.

Most container tags will have their output re-parsed for more
Interchange tags by default. If you wish to prevent this behavior, you
must explicitly set the reparse
attribute to a false value. Note, however, that you will
almost always want the default action. Probably the only ITL tag that
doesn't reparse by default is [mvasp].

In Interchange 5.3.1, the no_default_reparse pragma was added, which
disables the default reparsing of container tags' output. It is therefore
advisable to always specify the reparse=1 attribute at
places where you want reparsing to really occur.

The third attribute, send , was deprecated long ago
and will only be described for historical reference.

Tag-specific Attributes

Each tag may accept additional arguments which vary from tag to
tag. For each tag individually, you need to consult the
appropriate reference page to learn tag-specific parameters and attributes.
Note, however, that the tag arguments do not necessarily have to be announced
in the tag definition header; sometimes they're used pretty much
ad-hoc, but we are making sure to keep the documentation
up to date. We kindly ask you to inform us of any errors or omissions in the
documentation.

Attribute Arrays and Hashes

Instead of just plain values, for some tags it would be particularly convenient
if they accepted arrays or hashes of argument values, much like
you could do if you used Perl directly. Fortunately, ITL supports
that too! For an ordinary tag, the syntax is as follows:

attribute.ARRAY_INDEX=valueattribute.HASH_KEY=value

ARRAY_INDEX is an integer array index starting
from 0 (this is due to standard programming practice and
Perl behavior). Note that you cannot have both an array and a hash
attribute of the same name (even though that would be possible in pure
Perl).

It is up to each individual tag to handle an
array or hash value properly.
See the documentation for the specific tag before passing
it an attribute array or hash value.
The [page] tag, for example, would treat a search specification array
(the structure we've shown above) as a joined search (one of different
search types we support).

On the Perl level, before passing attributes to a tag, Interchange parser would
convert attributes to an anonymous array reference.

If you were passing the above example directly to a tag named
ROUTINE
within a [perl] block or your custom tag, you would actually pass an
anonymous array as the value of the attribute:

Pay attention to the fact that with array- or hash-based attributes,
their values are not interpolated.
It means that, at places where scalar options
are interpolated (such as
[tag option='[time]'], resulting in [time] expanding to
the current time), reference-based attributes are not (such as
[tag my.option='[time]'], which would result in literal
"[time]" being passed to the attribute "my.option".
Interpolation of reference-based attributes can be enabled by
setting the interpolate_itl_references pragma.

Looping Tags and Sub-tags

Certain tags can only appear in a special context, usually nested within
other, parent tags. Those include, for example, the ones interpreted as part
of a surrounding loop tags, such as
[loop], [item-list], [query] or [search-region].

In each of the above, PREFIX represents an
arbitrary prefix that is used in that looping tag; this is needed to be able
to support nesting in arbitrary order and to arbitrary level.
All of the
subtags are only interpreted within their container tags (they can only
appear inside their parent tags' bodies) and they only accept
positional parameters. The default prefixes follow:

As we've said already, subtags are parsed before the standard parsing routine
takes on; that means before any regular tags within the
loop. This has a subtle effect; it can, for example, prevent the
usual tags from accepting looping tags' values as attributes. In such cases,
look for "subtag" (prefixed) variants of the usual tags.

Speaking of loops and Perl, there are two types of records that Interchange can
return with looping lists: ARRAY and HASH.

An array list is the normal output of the [query] and [loop] tags,
or of a search operation. In those cases, fields specified in
mv_return_fields (or those specified in SQL) are returned for
each selected row.
The two queries below are essentially identical:

Both will return an array of arrays consisting of the
foo and
bar columns.
The corresponding Perl data structure would look like this
(familiarity with the output from Data::Dumper Perl
module helps here):