CAM::Template - Clotho-style search/replace HTML templates


Copyright 2005 Clotho Advanced Media, Inc., <>

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.


  use CAM::Template;
  my $tmpl = new CAM::Template($tmpldir . "/main_tmpl.html");
  $tmpl->addParams(url => "",
                   date => localtime(),
                   name => "Carol");
  $tmpl->setLoop("birthdaylist", name => "Eileen", date => "Sep 12");
  $tmpl->addLoop("birthdaylist", name => "Chris",  date => "Oct 13");
  $tmpl->addLoop("birthdaylist", [{name => "Dan",   date => "Feb 12"},
                                  {name => "Scott", date => "Sep 24"}]);
  print "Content-Type: text/html\n\n";


This package is intended to replace Clotho's traditional ::PARAM:: syntax with an object-oriented API. This syntax is overrideable by subclasses. See the last section of this documentation for an explanation of the default syntax.

We recommend that you DO NOT use this module unless you have a good reason. The other CPAN templating modules, like HTML::Template and Template::Toolkit) are better maintained than this one. See for an excellent discussion of the various templating approaches.

So why does this module exist? Legacy, mostly. A ton of HTML was written in this templating language. So, we keep this module in good condition. Additionally, we believe it's unique in the Perl community in that it has a reconfigurable template syntax. That's worth a little, we think.



This class method returns a series of regular expressions used for template searching and replacing. Modules which subclass CAM::Template can override this method to implement a different template syntax.

Example of the recommended way to write an override function for this method in a subclass:

  sub patterns {
    my $pkg = shift;
    return {
      # include syntax:  <? include("subfile.tmpl") ?>
      include => qr/<? *include\(\"([^\"]+)\"\) *?>/,

Create a new template object. You can specify the template filename and the replacement dictionary right away, or do it later via methods.

setFileCache 0|1

Indicate whether the template file should be cached in memory. Defaults to 1 (aka true). This can be used either on an object or globally:

    my $tmpl = new CAM::Template();

The global value only affects future template objects, not existing ones.

setIncludeFiles 0|1

Indicate whether the template file should be able to include other template files automatically via the

   <!-- #include template="<filename>" -->

directive. Defaults to 1 (aka true). Note that this is recursive, so don't have a file include itself! This method can be used either on an object or globally:

    my $tmpl = new CAM::Template();

The global value only affects future template objects, not existing ones.

setFilename FILENAME

Specify the template file to be used. Returns false if the file does not exist or the object if it does. This loads and preparses the file.

setString STRING

Specify template content to be used. Use this instead of setFilename if you already have the contents in memory. This preparses the string.


Template loops (i.e. addLoop) usually instantiate new template objects to populate the loop body. In general, we want the new instance to be the same class as the main template object. However, in some subclasses of CAM::Template, this is a bad thing (for example PDF templates with loops in their individual pages).

In the latter case, the subclass should override this method with something like the following:

   sub loopClass { "CAM::Template" }

Add to an iterating portion of the page. This extracts the <cam_loop> from the template, fills it with the specified parameters (and any previously specified with setParams() or addParams()), and appends to the LOOPNAME parameter in the params list.

If the ARRAYREF form of the method is used, it behaves as if you had done:

    foreach my $row (@$ARRAYREF) {
       $tmpl->addLoop($LOOPNAME, $row);

so, the elements of the ARRAYREF are hashrefs representing a series of rows to be added.

clearLoop LOOPNAME

Blank the contents of the loop accumlator. This is really only useful for nested loops. For example:

    foreach my $state (@states) {
       foreach my $city (@{$state->{cities}}) {
                             city => $city->{name},
                             pop => $city->{population});
       $template->addLoop("state", state => $state->{name});

Exactly like addLoop above, except it clears the loop first. This is useful for the first element of a nested loop.


Takes a moment to analyze the template to see if any time can be gained by skipping unused portions of the replacement syntax. This is obviously more useful for templates that are replaced often, like loops.

Implementation note as of v0.77: In practice this rarely helps except on large, simplistic templates. Hopefully this will improve in the future.

addParams [HASHREF | KEY => VALUE], ...

Specify the search/replace dictionary for the template. The arguments can either be key value pairs, or hash references (it is permitted to mix the two as of v0.71 of this library). For example:

    my %hash = (name => "chris", age => 30);
    my $hashref = \%hash;

Returns false if the hash has an uneven number of arguments, or the argument is not a hash reference. Returns the object otherwise.

Note: this appends to the parameter list. To replace the list, use the setParams method instead.

setParams HASHREF | KEY => VALUE, ...

Exactly like addParams above, except it clears the parameter list first.


Executes the search/replace and returns the content.


Sends the replaced content to the currently selected output (usually STDOUT) or the supplied filehandle.


The template syntax has four primary purposes: 1) to merge template files (i.e. include standard headers, footers, etc., 2) to mark blanks in the template that need to be filled with strings from the program, 3) to indicate optional sections of the template which are shown or not shown, 4) to produce similar, repeated sections (like table rows), and


To include another file in your template, use this notation:

  <!-- include template="file.tmpl" -->

This causes "file.tmpl" to be slurped into the template before any further processing occurs. Subtemplates are allowed to slurp in their own subtemplates too, but make sure that a file does not attempt to include itself! A subtemplate can even be included in multiple places. For example:

  <!-- Top nav -->
  <!-- include template="nav.tmpl" -->
  ...  blah blah ...
  <!-- Bottom nav -->
  <!-- include template="nav.tmpl" -->

String Replacement

To search and replace strings, use one of these three tag descriptions:

   <!-- ::var:: -->

The first is the normal syntax. The second alternative is nice if you want to view the raw template, so the "::" part doesn't show in your browser. The last was a workaround for Mac Dreamweaver which mangled ":" characters sometimes, but is now rarely used.

For example, if your template looks like this:

  Hello, <!--::fname::--> ::lname::!  Today is ;;day;;.

then your output will be:

  Hello, Chris Dolan!  Today is Friday.

if your code has this command:

  $template->setParams(fname => "Chris", lname => "Dolan", day => "Friday");

Another form of string replacement is one that is set in the template itself. The syntax for this is:

  ::var==some arbitrary string of text::

This is useful particularly for included subtemplates, or for phrases that are repeated often. In the following example, the table cell color is hard-coded at the top of the template where it can be easily changed:

  ::oddcolor==#AAAAAA:: ::evencolor==#FFFFFF::
  <tr><td bgcolor="::oddcolor::">one</td></tr>
  <tr><td bgcolor="::evencolor::">two</td></tr>
  <tr><td bgcolor="::oddcolor::">three</td></tr>
  <tr><td bgcolor="::evencolor::">four</td></tr>

The value portion of this tag can be any string on one line, as long as it is less than 80 characters and does not contain "::". These hard-coded parameters can be overridden by parameters of the same name set with addParams(). However setParams() does NOT clear the hard-coded parameters, unlike the parameters set in the Perl code.

Conditional Blocks

Conditional sections of a template are either shown or not shown depending on the state of a boolean parameter. A parameter is true or false just as Perl variables are true or false: undef, "" and 0 are false; everything else is true. Conditional blocks are marked by the following codes:

   ??var?? Some text to display... ??var??
   ??!var?? Some text to display... ??!var??

The first type is shown if "var" is true and not shown if "var" is false. The second type is the opposite: show if false, not shown if true. Think of them as "if" and "unless" blocks, respectively.

These blocks are highly flexible. They can span mutliple lines and can be nested within each other.

For example, this template:

  Hello ??male??Mr.??male????!male??Ms.??!male?? ::lname::!

produces these:

  Hello Mr. Dolan!
  Hello Ms. Smith!

for these parameters, respectively:

  $template->setParams(male => 1, lname => "Dolan");
  $template->setParams(lname => "Smith");


Often in templates you wish to print a list of data. In this case, you indicate one instance of this in a <CAM_loop> tag and use the addLoop() method to replicate it. The syntax is:

  <CAM_loop name="var"> ... </CAM_loop>

Note that "CAM_loop" is case insensitive, so you can write it as <cam_loop> if you like. For more detail see the documentation for the addLoop() method above.


Here is an example template using most of the above syntax:

  ::title==Example Template::
  <head> <title>::title::</title> </head>
    <!-- include template="nav.tmpl" -->
    ??name?? <b> Welcome, ::name::! ??name??
    ??!name?? Nice to meet you. ??!name??
      <CAM_loop name="data">
          ??height??  <td>::height::</td>  ??height??
          ??!height?? <td>(no height)</td> ??!height??
          ??weight??  <td>::weight::</td>  ??weight??
          ??!weight?? <td>(no weight)</td> ??!weight??
      Sorry, there is no data to show right now.

and here is a filled in example of that template, exactly as it would appear for the following code.

  $tmpl->setParams(name => "Chris");
  $tmpl->addLoop(height => "72", weight => 200);
  $tmpl->addLoop(height => "69", weight => undef);
  $tmpl->addLoop(height => "", weight => 150);

  <head> <title>Example Template</title> </head>
    <h1>Example Template</h1>
    <a href="../index.html">Back to home</a>
    <b> Welcome, Chris! 
            <td>(no weight)</td>  
            <td>(no height)</td>  


Clotho Advanced Media, Inc.

Primary developer: Chris Dolan