Matisse Enzer > Text-TagTemplate > Text::TagTemplate

Download:
Text-TagTemplate-1.83.tar.gz

Dependencies

Annotate this POD

Related Modules

HTML::Parser
more...
By perlmonks.org
View/Report Bugs
Module Version: 1.83   Source  

NAME ^

        Text::TagTemplate

VERSION ^

        1.82

SYNOPSIS ^

        use Text::TagTemplate qw( :standard );

        # Define a single tag to substitute in a template.
        add_tag( MYTAG => 'Hello world.' );

        # Define several tags all at once. The  tags()  method wipes out
        # all current tags.
        tags( +{ FOO => 'The string foo.',  # Single-quoted string
                 BAR => "$ENV{ USER }",     # Double-quoted string
                 LIST => join( '<LI>', @list ),  # Function call

                 # Functions or subroutines that get called each time
                 # the tag is replaced, possibly producing different
                 # results for the same tag if it appears twice or more.
                 TIME => \&time(),          # Reference to a function
                 SUB => sub {               # Anonymous subroutine
                        my( $params ) = @_;
                        return $params->{ NAME };
                }
        } );

        # Add a couple of tags to the existing set.  Takes a hash-ref.
        add_tags( +{ TAG1 => "Hello $ENV{ USER }",
                     TAG2 => rand( 10 ),  # random number between 0 and 10
                } );

        # Set the template file to use.
        template_file( 'template.htmlt' );

        # This is list of items to construct a list from.
        list( 'One', 'Two', 'Three' );

        # These are template-fragment files to use for making the list.
        entry_file( 'entry.htmlf' );
        join_file(  'join.htmlf'  );

        # This is a callback sub used to make the tags for each entry in a
        # parsed list.
        entry_callback( sub {
                my( $item ) = @_;
                return +{ ITEM => $item };
        } );

        # Add a new tag that contains the whole parsed list.
        add_tag( LIST => parse_list_files );

        # Print the template file with substitutions.
        print parse_file;

DESCRIPTION ^

This module is designed to make the process of constructing web-based applications (such as CGI programs and Apache::Registry scripts) much easier, by separating the logic and application development from the HTML coding, and allowing ongoing changes to the HTML without requiring non-programmers to modify HTML embedded deep inside Perl code.

This module provides a mechanism for including special HTML-like tags in a file (or scalar) and replacing those tags at run-time with dynamically generated content. For example the special tag <#USERINFO FIELD="favorite_color">

might be replaced by "green" after doing a database lookup. Usually each special tag will have its own subroutine which is executed every time the tag is seen.

Each subroutine can be basically anything you might want to do in Perl including database lookups or whatever. You simply create subroutines to return whatever is appropriate for replacing each special tag you create.

Attributes in the special tags (such as the FIELD="favorite_color" in the example above) are passed to the matching subroutine.

It is not web-specific, though, despite the definite bias that way, and the template-parsing can just as easily be used on any other text documents. The examples here will assume that you are using it for convential CGI applications.

It provides functions for parsing strings, and constructing lists of repeated elements (as in the output of a search engine).

It is object-oriented, but -- like the CGI module -- it does not require the programmer to use an OO interface. You can just import the ``:standard'' set of methods and use them with no object reference, and it will create and use an internal object automatically. This is the recommended method of using it unless you either need multiple template objects, or you are concerned about namespace pollution.

TEMPLATES ^

The structure of templates is as any other text file, but with extra elements added that are processed by the CGI as it prints the file to the browser. These extra elements are referred to in this manual as ``tags'', which should not be confused with plain HTML tags -- these tags are replaced before the browser even begins to process the HTML tags. The syntax for tags intentionally mimics HTML tags, though, to simplify matters for HTML-coders.

A tag looks like this:

        <#TAG>

or optionally with parameters like:

        <#TAG NAME=VALUE>

or with quoted parameters like:

        <#TAG NAME="Value, including spaces etc.">

Tags may be embedded in other tags (as of version 1.5), e.g. <#USERINFO DISPLAY="<#FAVORITE_COLOR>">

The tag name is the first part after the opening <# of the whole tag. It must be a simple identifier -- I recommend sticking to the character set [A-Z_] for this. The following parameters are optional and only used if the tag-action is a callback subroutine (see below). They are supplied in HTML-style name/value pairs. The parameter name like the tag name must be a simple identifier, and again I recommend that it is drawn from the character set [A-Z_]. The value can be any string, quoted if it contains spaces and the like. Even if quoted, it may not contain any of:

        < > " & =

which should be replaced with their HTML escape equivalents:

        &lt; &gt; &quot; &amp; &#061;

This may be a bug. At present, other HTML escapes are not permitted in the value. This may also be a bug.

Tag names and parameter names are, by default, case-insensitive (they are converted to upper-case when supplied). You can change this behaviour by using the auto_cap() method. I don't recommend doing that, though.

There are four special parameters that can be supplied to any tag, HTMLESC and URLESC. Two of them cause the text returned by the tag to be HTML or URL escaped, which makes outputting data from plain-text sources like databases or text files easier for the programmer. An example might be:

        <#FULL_NAME HTMLESC>

which would let the programmer simply put the full-name data into the tag without first escaping it. Another might be:

        <A HREF="/cgi-bin/lookup.cgi?key=<#RECORD_KEY URLESC>">

A typical template might look like:

        <HTML><HEAD><TITLE>A template</TITLE></HEAD>
        <BODY>

        <P>This is a tag:  <#TAG></P>

        <P>This is a list:</P>

        <#LIST>

        <P>This is a tag that calls a callback:  <#ITEM ID=358></P>

        </BODY></HTML>

Note that it is a full HTML document.

TAGS ^

You can supply the tags that will be used for substitutions in several ways. Firstly, you can set the tags that will be used directly, erasing all tags currently stored, using the tags() method. This method -- when given an argument -- removes all present tags and replaces them with tags drawn from the hash-reference you must supply. For example:

        tags( +{ FOO => 'A string called foo.',
                 BAR => 'A string called bar.' } );

The keys to the hash-ref supplied are the tag names; the values are the substitution actions (see below for more details on actions).

If you have an existing hash you can use it to define several tags. For example:

        tags( \%ENV );

would add a tag for each environment variable in the %ENV hash.

Secondly, you can use the add_tags() method to add all the tags in the supplied hash-ref to the existing tags, replacing the existing ones where there is conflict. For example:

        add_tags( +{ FOOBAR => 'A string called foobar added.',
                     BAR    => 'This replaces the previous value for BAR' } );

Thirdly, you can add a single tag with add_tag(), which takes two arguments, the tag name and the tag value. For example:

        add_tag( FOO => 'This replaces the previous value for FOO' );

Which one of these is the best one to use depends on your application and coding style, of course.

ACTIONS ^

Whichever way you choose to supply tags for substitutions, you will need to supply an action for each tag. These come in two sorts: scalar values (or scalar refs, which are treated the same way), and subroutine references for callbacks.

Scalar Text Values

A scalar text value is simply used as a string and substituted in the output when parsed. All of the following are scalar text values:

        tags( +{ FOO => 'The string foo.',  # Single-quoted string
                 BAR => "$ENV{ USER }",     # Double-quoted string
                 LIST => join( '<LI>', @list ),  # Function call
        } );

Subroutine References

If the tag action is a subroutine reference then it is treated as a callback. The value supplied to it is a single hash-ref containing the parameter name/value pairs supplied in the tag in the template. For example, if the tag looked like:

        <#TAG NAME="Value">

the callback would have an @_ that looked like:

        +{ NAME => 'Value' }

The callback must return a simple scalar value that will be substituted in the output. For example:

        add_tag( TAG  => sub {
                    my( $params ) = @_;
                    my $name = $params->{ NAME };
                    my $text = DatabaseLookup("$name");
                    return $text;
                }
        } );

You can use these callbacks to allow the HTML coder to look up data in a database, to set global configuration parameters, and many other situations where you wish to allow more flexible user of your templates.

For example, the supplied value can be the key to a database lookup and the callback returns a value from the database; or it can be used to set context for succeeding tags so that they return different values. This sort of thing is tricky to code but easy to use for the HTMLer, and can save a great deal of future coding work.

Default Action

If no action is supplied for a tag, the default action is used. The default default action is to confess() with an error, since usually the use of unknown tags indicates a bug in the application. You may wish to simply ignore unknown tags and replace them with blank space, in which case you can use the unknown_action() method to change it. If you wish to ignore unknown tags, you set this to the special value ``IGNORE''. For example:

        unknown_action( 'IGNORE' );

Unknown tags will then be left in the output (and typically ignored by web browsers.) The default action is indicated by the special value ``CONFESS''. If you want to have unknown tags just be replaced by warning text (and be logged with a cluck() call), use the special value ``CLUCK''. For example:

        unknown_action( 'CLUCK' );

If the default action is a subroutine reference then the name of the unknown tag is passed as a parameter called ''TAG''. For example:

        unknown_action( sub {
                            my( $params ) = @_;
                            my $tagname   = $params->{ TAG };
                            return "<BLINK>$tagname is unknown.</BLINK>";
        } );

You may also specify a custom string to be substituted for any unknown tags. For example:

        unknown_action( '***Unknown Tag Used Here***' );

PARSING ^

Once you have some tags defined by your program you need to specify which template to parse and replace tags in.

You can supply a string to parse, or the name of file to use. The latter is usually easier. For example:

        template_string( 'A string containing some tag: <#FOO>' );

or:

        template_file( 'template.htmlt' );

These methods just set the internal string or file to look for; the actual parsing is done by the parse() or parse_file() methods. These return the parsed template, they don't store it internally anywhere, so you have to store or print it yourself. For example:

        print parse_file;

will print the current template file using the current set of tags for substitutions. Or:

        $parsed = parse;

will put the parsed string into $parsed using the current string and tags for substitutions.

These methods can also be called using more parameters to skip the internally stored strings, files, and tags. See the per-method documentation below for more details; it's probably easier to do it the step-by-step method, though.

MAKING LISTS ^

One of the things that often comes up in CGI applications is the need to produce a list of results -- say from a search engine.

Because you don't necessarily know in advance the number of elements, and usually you want each element formatted identically, it's hard to do this in a single template.

This module provides a convenient interface for doing this using two templates for each list, each a fragment of the completed list. The ``entry'' template is used for each entry in the list. The ``join'' template is inserted in between each pair of entries. You only need to use a ''join'' template if you, say, want a dividing line between each entry but not one following the end of the list. The entry template is the interesting one.

There's a complicated way of making a list tag and an easy way. I suggest using the easy way. Let's say you have three items in a list and each of them is a hashref containing a row from a database. You also have a file with a template fragment that has tags with the same names as the columns in that database. To make a list using three copies of that template and add it as a tag to the current template object, you can do:

        add_list_tag( ITEM_LIST => \@list );

and then when you use the tag, you can specify the template file in a parameter like this:

        <#ITEM_LIST ENTRY_FILE="entry.htmlf">

If the columns in the database are "name", "address" and "phone", that template might look like:

        <LI>Name: <#NAME HTMLESC><BR>
        Address: <#ADDRESS HTMLESC><BR>
        Phone: <#PHONE HTMLESC</LI>

Note that the path to the template can be absolute or relative; it can be any file on the system, so make sure you trust your HTML people if you use this method to make a list tag for them.

The second argument to add_list_tag is that list of tag hashrefs. It might look like:

        +[ +{
                NAME => 'Jacob',
                ADDRESS => 'A place',
                PHONE => 'Some phone',
        }, +{
                NAME => 'Matisse',
                ADDRESS => 'Another place',
                PHONE => 'A different phone',
        }, ]

and for each entry in that list, it will use the hash ref as a miniature set of tags for that entry.

If you want to use the long way to make a list (not recommended; it's what add_list_tag() uses internally), there are three things you need to set:

A list (array).
An entry template.
A subroutine that takes one element of the list as an argument and returns a hash reference to a set of tags (which should appear in the entry_template.)

You set the list of elements that you want to be made into a parsed list using the list() method. It just takes a list. Obviously, the ordering in that list is important. Each element is a scalar, but it can be a reference, of course, and will usually be either a key or a reference to a more complex set of data. For example:

        list( $jacob, $matisse, $alejandro );

or list( \%hash1, \%hash2, \%hash3 );

You set the templates for the entry and join templates with the entry_string() & join_string() or entry_file() & join_file() methods. These work in the way you would expect. For example:

        entry_string( '<P>Name:  <#NAME></P><P>City:  <#CITY></P>' );
        join_string( '' );

or:

        entry_file( 'entry.htmlf' );
        join_file(  'join.htmlf'  );

Usually the _file methods are the ones you want.

In the join template, you can either just use the existing tags stored in the object (which is recommended, since usually you don't care what's in the join template, if you use it at all) or you can supply your own set of tags with the join_tags() method, which works just like the tags() method.

The complicated part is the callback. You must supply a subroutine to generate the tags for each entry. It's easier than it seems.

The callback is set with the entry_callback() method. It is called for each entry in the list, and its sole argument will be the item we are looking at from the list, a single scalar. It must return a hash-ref of name/action pairs of the tags that appear in the entry template. A callback might look like this:

        entry_callback( sub {
                my( $person ) = @_;   # $person is assumed to be a hash-ref

                my $tags= +{ NAME => $person->name,
                             CITY => $person->city };

                return $tags;
        } );

You then have to make the list from this stuff, using the parse_list() or parse_list_files() methods. These return the full parsed list as a string. For example:

        $list = parse_list;

or more often you'll be wanting to put that into another tag to put into your full-page template, like:

        add_tag( LIST => parse_list_files );

That example above might produce a parsed list looking like:

        <P>Name:  Jacob</P><P>City:  Norwich</P>
        <P>Name:  Matisse</P><P>City:  San Francisco</P>
        <P>Name:  Alejandro</P><P>City:  San Francisco</P>

which you could then insert into your output.

If you're lazy and each item in your list is either a hashref or can easily be turned into one (for example, by returning a row from a database as a hashref) you may just want to return it directly, like this:

        entry_callback( sub {
                ( $userid ) = @_;
                $sth = $dbh->prepare( <<"EOS" );
        SELECT * FROM users WHERE userid = "$userid"
        EOS
                $sth->execute;
                return $sth->fetchrow_hashref;
        } );

or more even more lazily, something like this:

        $sth = $dbh->prepare( <<"EOS" );
        SELECT * FROM users
        EOS
        $sth->execute;
        while ( $user = $sth->fetchrow_hashref ) {
                push @users, $user;
        }
        list( @users );
        entry_callback( sub { return $_[ 0 ] } );

Isn't that easy? What's even easier is that the default value for entry_callback() is sub { return $_[ 0 ] }, so if your list is a list of hashrefs, you don't even need to touch it.

WHICH INTERFACE? ^

You have a choice when using this module. You may either use an object-oriented interface, where you create new instances of Text::TagTemplate objects and call methods on them, or you may use the conventional interface, where you import these methods into your namespace and call them without an object reference. This is very similar to the way the CGI module does things. I recommend the latter method, because the other forces you to do a lot of object referencing that isn't particularly clear to read. You might need to use it if you want multiple objects or you are concerned about namespace conflicts. You'll also want to use the object interface if you're running under mod_perl, because mod_perl uses a global to store the template object, and it won't get deallocated between handler calls.

For the OO interface, just use:

        use Text::TagTemplate;
        my $parser = new Text::TagTemplate;

For the conventional interface, use:

        use Text::TagTemplate qw( :standard );

and you'll get all the commonly-used methods automatically imported. If you want the more obscure configuration methods, you can have them too with:

        use Text::TagTemplate qw( :standard :config );

The examples given here all use the conventional interface, for clarity. The OO interface would look like:

        $parser = new Text::TagTemplate;
        $parser->template_file( 'default.htmlt' );
        $parser->parse;

PER-METHOD DOCUMENTATION ^

The following are the public methods provided by Text::TagTemplate.

new() or new( %tags ) or new( \%tags ) ^

Instantiate a new template object. Optionally take a hash or hash-ref of tags to add initially.

  my $parser = Text::TagTemplate->new();
  my $parser = Text::TagTemplate->new( %tags );
  my $parser = Text::TagTemplate->new( \%tags );

Setting the Tag Pattern ^

The default pattern for tags is <#TAGNAME attributes >. This is implemented internally as a regular expression: (?-xism:<#([^<>]*)) made up from three pieces which you may override using the next three methods tag_start(), tag_end(), and tag_contents().

For example, you might want to use a pattern for tags that does not look like HTML tags, perhaps to avoid confusing some HTML parsing tool.

Examples;

To use tags like this:

   /* TAGNAME attribute=value attribute2=value */

Do this:

   tag_start('/\*');       # you must escape the * character
   tag_contents('[^*]*');  # * inside [] does not need escaping
   tag_end('\*/');         # escape the *
tag_start() or tag_start( $pattern )

Set and or get the pattern used to find the start of tags.

With no arguments returns the current value. The default value is <#.

If an argument is supplied it is used to replace the current value. Returns the new value.

See also tag_contents() and tag_end(), below.

tag_contents() or tag_contents( $pattern )

Set and or get the pattern used to find the content of tags, that is the stuff in between the tag_start and the tag_end.

With no arguments returns the current value. The default value is [^<>]*.

If an argument is supplied it is used to replace the current value. Returns the new value.

The pattern should be something that matches any number of characters that are not the end of the tag. (See tag_end, below.) Typ[ically you should use an atom followed by *. In the defaul pattern [^<>]* the [^<>] defines a "character class" consisting of anything except < or >. The * means "zero-or-more" of the preceding thing.

Examples:

Set the contents pattern to match anything that is not --

tag_end() or tag_end( $pattern )

Set and or get the pattern used to find the end of tags.

With no arguments returns the current value. The default value is <.

If an argument is supplied it is used to replace the current value. Returns the new value.

tag_patten()

Returns the complete pattern used to find tags. The value is returned as a quoted regular expression. The default value is (?-xism:<#([^<>]*)).

Equivalant to:

 $start    = tag_start();
 $contents = tag_contents();
 $end      = tag_end();
 return qr/$start($contents)$end/;
auto_cap() or auto_cap( $new_value )

Returns whether tag names will automatically be capitalised, and if a value is supplied sets the auto-capitalisation to this value first. Default is 1; changing it is not recommended but hey go ahead and ignore me anyway, what do I know? Setting it to false will make tag names case-sensitive and you probably don't want that.

unknown_action() or unknown_action( $action )

Returns what to do with unknown tags. If a value is supplied sets the action to this value first. If the action is the special value 'CONFESS' then it will confess() at that point. This is the default. If the action is the special value 'IGNORE' then unknown tags will be ignored by the module, and will appear unchanged in the parsed output. If the special value 'CLUCK' is used then the the unknown tags will be replaced by warning text and logged with a cluck() call. (See Carp for cluck() and confess() - these are like warn() and (die(), but with a stack trace.) Other special values may be supplied later, so if scalar actions are require it is suggested that a scalar ref be supplied, where these special actions will not be taken no matter what the value.

tags() or tags( %tags ) or tags( \%tags )

Returns the contents of the tags as a hash-ref of tag/action pairs. If tags are supplied as a hash or hashref, it first sets the contents to these tags, clearing all previous tags.

add_tag( $tag_name, $tag_action )

Adds a new tag. Takes a tag name and the tag action.

add_list_tag( $tag_name, \@list, $entry_callback, @join_tags )

Add a tag that will build a parsed list, allowing the person using the tag to supply the filename of the entry and join templates, or to supply the strings directly in tag parameters (which is currently annoying given the way they need to be escaped). The tag will take parameters for ENTRY_STRING, ENTRY_FILE, JOIN_STRING or JOIN_FILE.

No checking is currently performed on the filenames given. This shouldn't be a security problem unless you're allowing untrusted users to write your templates for you, which mean it's a bug that I need to fix (since I want untrusted users to be able to write templates under some circumstnaces).

add_tags( %tags ) or add_tags( \%tags )

Adds a bunch of tags. Takes a hash or hash-ref of tag/action pairs.

delete_tag( $name )

Delete a tag by name.

clear_tags()

Clears all existing tags.

list() or list( @list )

Returns (and sets if supplied) the list of values to be used in parse_list() or parse_list_files() calls.

template_string() or template_string( $string )

Returns (and sets if supplied) the default template string for parse().

template_file() or template_file( $file )

Returns (and sets if supplied) the default template file for parse_file().

entry_string() or entry_string( $string )

Returns (and sets if supplied) the entry string to be used in parse_list() calls.

entry_file() or entry_file( $file )

Returns (and sets if supplied) the entry file to be used in parse_list_files() calls.

entry_callback() or entry_callback( $callback )

Returns (and sets if supplied) the callback sub to be used in parse_list() or parse_list_files() calls. If you don't set this, the default is just to return the item passed in, which will only work if the item is a hashref suitable for use as a set of tags.

join_string() or join_string( $string )

Returns (and sets if supplied) the join string to be used in parse_list() calls.

join_file() or join_file( $file )

Returns (and sets if supplied) the join file to be used in parse_list_files() calls.

join_tags() or join_tags( %tags ) or join_tags( \%tags )

Returns (and sets if supplied) the join tags to be used in parse_list() and parse_list_files() calls.

parse() or parse( $string ) or parse( $string, %tags ) or parse( $string, \%tags )

Parse a string, either the default string, or a string supplied. Returns the string. Can optionally also take the tags hash or hash-ref directly as well.

parse_file() or parse_file( $file ) or parse_file( $file, %tags ) or parse_file( $file, \%tags )

Parses a file, either the default file or the supplied filename. Returns the parsed file. Dies if the file cannot be read. Can optionally take the tags hash or hash-ref directly.

parse_list() or parse_list( \@list )
or parse_list( \@list, $entry_string, $join_string )
or parse_list( \@list, $entry_string, $join_string, $entry_callback, \%join_tags )

Makes a string from a list of entries, either the default or a supplied list.

At least one template string is needed: the one to use for each entry, and another is optional, to be used to join the entries.

A callback subroutine must be supplied using entry_callback(), which takes the entry value from the list and must return a hash-ref of tags to be interpolated in the entry string. This will be called for each entry in the list. You can also supply a set of tags for the join string using join_tags(), but by default the main tags will be used in that string.

You can also optionally supply the strings for the entry and join template. Otherwise the strings set previously (with entry_string() and join_string() ) will be used.

Finally, you can also supply the callback sub and join tags directly if you want.

parse_list_files() or parse_list_files( \@list )
or parse_list_files( \@list, $entry_file, $join_file )
or parse_list_files( \@list, $entry_file, $join_file, $entry_callback )
or parse_list_files( \@list, $entry_file, $join_file, $entry_callback, %join_tags )
or parse_list_files( \@list, $entry_file, $join_file, $entry_callback, \%join_tags )

Exactly as parse_list(), but using filenames, not strings.

COPYRIGHT ^

Copyright (C) 2000 SF Interactive, Inc. All rights reserved.

LICENSE ^

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

AUTHOR ^

Jacob Davies

        <jacob@well.com>

MAINTAINER ^

Matisse Enzer

        <matisse@matisse.net>

SEE ALSO ^

The README file supplied with the distribution, and the example/ subdirectory there, which contains a full CGI application using this module.

The CGI module documentation.

Apache::TagRegistry(1)

Carp(3)

syntax highlighting: