Michael Sokolov > HTML-Macro.1-19 > HTML::Macro



Annotate this POD

View/Report Bugs
Module Version: 1.19   Source  


HTML::Macro - generate dynamic HTML pages using templates


  use HTML::Macro;
  $htm = HTML::Macro->new();
  $htm->declare ('var', 'missing');
  $htm->set ('var', 'value');
  $htm->print ('test.html');


HTML::Macro is a module to be used behind a web server (in CGI scripts). It provides a convenient mechanism for generating HTML pages by combining "dynamic" data derived from a database or other computation with HTML templates that represent fixed or "static" content of a page.

There are many different ways to accomplish what HTML::Macro does, including ASP, embedded perl, CFML, etc, etc. The motivation behind HTML::Macro is to keep everything that a graphic designer wants to play with *in a single HTML template*, and to keep as much as possible of what a perl programmer wants to play with *in a perl file*. Our thinking is that there are two basically dissimilar tasks involved in producing a dynamic web page: graphic design and programming. Even if one person is responsible for both tasks, it is useful to separate them in order to aid clear thinking and organized work. I guess you could say the main motivation for this separation is to make it easier for emacs (and other text processors, including humans) to parse your files: it's yucky to have a lot of HTML in a string in your perl file, and it's yucky to have perl embedded in a special tag in an HTML file.

That said, HTML::Macro does provide for some simple programming constructs to appear embedded in HTML code. Think of it as a programming language on a similar level as the C preprocessor. HTML::Macro "code" is made to look like HTML tags so it will be fairly innocuous for most HTML-oriented editors to deal with. At the moment HTML::Macro suports variables, conditionals, loops, file interpolation and quoting (to inhibit all of the above). HTML::Macro variables are always surrounded with single or double hash marks: "#" or "##". Variables surrounded by double hash marks are subject to html entity encoding; variables with single hash marks are substituted "as is" (like single quotes in perl or UNIX shells). Conditionals are denoted by the <if> and <else> tags, and loops by the <loop> tag.


Create a new HTML::Macro:

    $htm = new HTML::Macro  ('templates/page_template.html');

The filename argument is optional. If you do not specify it now, you can do it later, which might be useful if you want to use this HTML::Macro to operate on more than one template. If you do specify the template when the object is created, the file is read in to memory at that time.

Optionally, declare the names of all the variables that will be substituted on this page. This has the effect of defining the value '' for all these variables.

  $htm->declare ('var', 'missing');

Set the values of one or more variables using HTML::Macro::set.

  $htm->set ('var', 'value');

Or use HTML::Macro::set_hash to set a whole bunch of values at once. Typically used with the value returned from a DBI::fetchrow_hashref.

  $htm->set_hash ( {'var' => 'value' } );

Finally, process the template and print the result using HTML::Macro::print, or save the value return by HTML::Macro::process.

    open CACHED_PAGE, '>page.html';
    print CACHED_PAGE, $htm->process;
    # or: print CACHED_PAGE, $htm->process ('templates/page_template.html');
    close CACHED_PAGE;
    - or - 


    - or -

    $htm->print ('test.html');

As a convenience the HTML::Macro::print function prints the processed template that would be returned by HTML::Macro::process, preceded by appropriate HTTP headers (Content-Type and no-cache directives).

HTML::Macro::process attempts to perform a substitution on any word beginning and ending with single or double hashmarks (#) , such as ##NAME##. A word is any sequence of alphanumerics and underscores. If the HTML::Macro has a matching variable, its value is substituted for the word in the template everywhere it appears. A matching variable may match the template word literally, or it may match one of the following:

the word with the delimiting hash marks stripped off ('NAME' in the example) the word without delimiters lowercased ('name') the word without delimiters uppercased ('NAME')

A typical usage is to stuff all the values returned from DBI::fetchrow_hashref into an HTML::Macro. Then SQL column names are to be mapped to template variables. Databases have different case conventions for column names; providing the case insensitivity and stripping the underscores allows templates to be written in a portable fashion while preserving an upper-case convention for template variables.

HTML entity quoting

Variables surrounded by double delimiters are subject to HTML entity encoding. That is, >, < and "" occuring in the variables value are replaced by their corresponding HTML entities. Variables surrounded by single delimiters are not quoted; they are substituted "as is"


Conditional tags take one of the following forms:

<if expr="perl expression"> HTML block 1 <else/> HTML block 2 </if>


<if expr="perl expression"> HTML block 1 <else> HTML block 2 </else> </if>

or simply

<if expr="perl expression"> HTML block 1 </if>

Conditional tags are processed by evaluating the value of the "expr" attribute as a perl expression. The entire conditional tag structure is replaced by the HTML in the first block if the expression is true, or the second block (or nothing if there is no else clause) if the expressin is false.

Conditional expressions are subject to variable substitution, allowing for constructs such as:

You have #NUM_ITEMS# item<if "#NUM_THINGS# > 1">s</if> in your basket.

File Interpolation

It is often helpful to structure HTML by separating commonly-used chunks (headers, footers, etc) into separate files. HTML::Macro provides the <include/> tag for this purpose. Markup such as <include/ file="file.html"> gets replaced by the contents of file.html, which is itself subject to evaluation by HTML::Macro. If the "asis" attribute is present: <include/ file="quoteme.html" asis>, the file is included "as is"; without any further evaluation.

Also, HTML::Macro provides support for an include path. This allows common "part" files to be placed in a common place. HTML::Macro::push_incpath adds to the path, as in $htm->push_incpath ("/path/to/include/files"). The current directory (of the file being processed) is always checked first, followed by each directory on the incpath. When paths are added to the incpath they are always converted to absolute paths, relative to the working directory of the invoking script. Thus, if your script is running in "/cgi-bin" and calls push_incpath("include"), this adds "/cgi-bin/include" to the incpath.


The preceding transformations can be inhibited by the use of the "<quote>" tag. Any markup enclosed by <quote> ... </quote> is passed on as-is. quote tags may be nested to provide for multiple passes of macro substitution.

    This could be useful if you need to include markup like <if> in your
    output, although that could be more easily accomplished by the usual
    HTML entity encodings: escaping < with &lt; and so on.  The real reason
    this is here is to enable multiple passes of HTML::Macro to run on "proto"
    templates that just generate other templates.

Quote tags have an optional "preserve" attribute. If "preserve" is present, its value is evaluated (as with if above), and if the result is true, the quote tag is preserved in the output. Otherwise, the tag is swallowed and the quoting behavior is inhibited. So:

<quote preserve="1">xyzzy<include/ file="foo"></quote>

would be passed over unchanged,


<quote preserve="0"><include/ file="foo"></quote>

would be replaced by the contents of the file named "foo".


The <loop> tag provides for repeated blocks of HTML, with subsequent iterations evaluated in different contexts. For more about loops, see the IF:Page::Loop documentation.

New in 1.19; Various performance enhancements, including file caching. Included files, and templates read by HTML::Macro::new and process are cached in memory if $self->{'@cache_files'} is true. This can improve performance significantly if you include a file in a loop that is repeated often. No attempt is made to detect when a file changes, so this cache is unsuitable for use with mod_perl. I plan to add cache freshening at some point for just this reason.

collapse_whitespace is now only called on the "final" pass of evaluation, saving considerable work. Also, we attempt to make lighter use of cwd, which turns out to be expensive in many OS implementations since it calls `pwd`. I am considering a rewrite of the entire mechanism for walking directories, but at least it runs reasonably fast now when you have a lot of includes.

    Eval blocks

New in 1.15, the <eval expr=""></eval> construct evaluates its expression attribute as Perl, in the package in which the HTML::Macro was created. This is designed to allow you to call out to a perl function, not to embed large blocks of code in the middle of your HTML, which we do not advocate. The expression attribute is treated as a Perl block (enclosed in curly braces) and passed a single argument: an HTML::Macro object whose content is the markup between the <eval> and </eval> tags, and whose attributes are inherited from the enclosing HTML::Macro. The return value of the expression is interpolated into the output. A typical use might be:

Your user profile: <eval expr="&get_user_info"> #FIRST_NAME# #LAST_NAME# <br> #ADDRESS## #CITY# #STATE# <br> </eval>

where get_user_info is a function defined in the package that called HTML::Macro::process (or process_buf, or print...). Presumably get_user_info will look something like:

sub get_user_info { my ($htm) = @_; my $id = $htm->get ('user_id'); ... get database record for user with id $id ...; $htm->set ('first_name', ...); ...; return $htm->process; }

Note that the syntax used to call the function makes use of a special Perl feature that the @_ variable is automatically passed as an arg list when you use & and not () in the function call: a more explicit syntax would be:

<eval expr="&get_user_info(@_)">...


You can use the <define/> tag, as in:

 <define/ name="variable_name" value="variable_value">  

to define HTML::Macro tags during the course of processing. These definitions are processed in the same macro evaluation pass as all the other tags. Hence the defined variable is only in scope after the definition, and any redefinition will override, in the way that you would expect.

This feature is useful for passing arguments to functions called by eval.

New in version 1.14:

- The quote tag is now deprecated. In its place, you should use tags with an underscore appended to indicate tags to be processed by a preprocessor. Indicate that this is a preprocessing pass by setting the variable '@precompile' to something true. For example: <if_ expr="0">I am a comment to be removed by a preprocessor.</if_> <if expr="#num# > 10">this if will be left unevaluated by a preprocessor.</if>

- Support for testing for the existence of a variable is now provided by the if "def" attribute. You used to have to do a test on the value of the variable, which sometimes caused problems if the variable was a complicated string with quotes in it. Now you can say:

  <if def="var"><b>#var#</b><br></if>

  and so on.

- If you set '@collapse_whitespace' the processor will collapse all adjacent whitespace (including line terminators) to a single space. An exception is made for markup appearing within <textarea>, <pre> and <quote> tags. Similarly, setting '@collapse_blank_lines' (and not '@collapse_whitespace', which takes precedence), will cause adjacent line terminators to be collapsed to a single newline character. We use the former for a final pass in order to produce efficient HTML, the latter for the preprocessor, to improve the readability of generated HTML with a lot of blank lines in it.

HTML::Macro is copyright (c) 2000,2001,2002 by Michael Sokolov and Interactive Factory (sm). Some rights may be reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.


Michael Sokolov, sokolov@ifactory.com

SEE ALSO HTML::Macro::Loop ^


syntax highlighting: