Article

Introducing HTML::Template

Page: 1 2

Loops

Although the <tmpl_var> tag is extremely useful, it isn't sufficient by itself. Often, we'll need to present a set of data in a tabular format. This is where the <tmpl_loop> tag comes in:

<html>  
<head>  
<title>Template 2</title>  
</head>  
<body>  
<table>  
 <tr>  
   <th>Language</th>  
   <th>Description</th>  
 </tr>  
 <tmpl_loop name="language">  
 <tr>  
   <td><tmpl_var name="language_name"></td>  
   <td><tmpl_var name="description"></td>  
 </tr>  
 </tmpl_loop>  
</table>  
</body>  
</html>

Essentially, we have a loop called language, and we have two variables inside it, called language_name and description. On the Perl side of things, HTML::Template expects loops to be passed as an array reference of hash (associative array) references:

1.  #!c:/perl/bin/perl -T  
2.  use CGI qw(:all);  
3.  use HTML::Template;  
4.  my @languages = (  
5.      {  
6.          language_name => 'Perl',  
7.          description   => 'Practical Extraction and Report Language'  
8.      },  
9.      {  
10.          language_name => 'PHP',  
11.          description   => 'Hypertext Preprocessor'  
12.      },  
13.      {  
14.          language_name => 'ASP',  
15.          description   => 'Active Server Pages'  
16.      },  
17.  );  
18.  print header;  
19.  my $template = HTML::Template->new( filename => 'template2.tmpl' );  
20.  $template->param( language => \@languages );  
21.  print $template->output();

Lines 4-17 define the array of hash references. The hash key names must be the same as the template <tmpl_var> names inside <tmpl_loop>. At line 20, a reference to the languages array is passed to the template tag <tmpl_loop name=language>.

Setting the loop data in our Perl script by hand is simple enough, but in the real world, we're likely to retrieve our template data from a database. Let's say we have a table called "languages", with a column called "language_name" and another called "description." We can just as easily generate the output from a query:

1.  #!c:/perl/bin/perl -T  
2.  use CGI qw(:all);  
3.  use HTML::Template;  
4.  use DBI;  
 
5.  my $dbh = DBI->connect('dbi:<driver>:<my db>', '<user>', '<password>');  
 
6.  my $sql = "select * from languages";  
7.  my $sth = $dbh->prepare($sql);  
8.  $sth->execute();  
 
9.  my $languages = $sth->fetchall_arrayref({  
10.     language_name => 1,  
11.     description   => 1}  
12.  );  
 
13.  print header;  
14.  my $template = HTML::Template->new( filename => 'template2.tmpl' );  
15.  $template->param( language => $languages );  
16.  print $template->output();

At line 4, we bring in the DBI, Perl's database module. Line 5 connects to the MySQL database. Replace <driver>, <my db>, <user> and <password> with whatever is appropriate for your system. This isn't production code -- we wouldn't normally hard-code this information, and we would typically include checks to see if any of our database interactions failed.

Lines 6-8 prepare our SQL select statement and execute it. In lines 9-12 we fetch the entire result set. DBI offers many different formats for the data. An array reference is best for us, because this is the format that HTML::Template expects. We can specify in a hash reference the columns that we wish to name in our array.

Conditionals

Finally, we may wish to alter the output based on certain conditions. HTML::Template offers both an IF and an UNLESS tag. Suppose, for example, that we want to present a special message if no languages are found:

<html>  
<head>  
<title>Template 3</title>  
</head>  
<body>  
<table>  
   <tmpl_if name=language>  
 <tr>  
   <th>Language</th>  
   <th>Description</th>  
 </tr>  
 <tmpl_loop name="language">  
 <tr>  
   <td><tmpl_var name="language_name"></td>  
   <td><tmpl_var name="description"></td>  
 </tr>  
 </tmpl_loop>  
   <tmpl_else>  
 Sorry, no languages were found  
   </tmpl_if>  
</table>  
</body>  
</html>

All that we've done here is wrap our loop in a conditional. If the language parameter is true, the results are displayed; otherwise, we'll let the person viewing the page know that no records were found.

UNLESS is similar to IF, except that instead of checking if a condition is true, we're seeing if it isn't (i.e. "unless true, do this").

Multiple Templates Per Page

Unless your page is trivial, you'll most likely want to add headers, footers and even some form of navigation. You can include other templates quite easily:

<tmpl_include name="menu.tmpl">

Is that It?

We've covered the basics of HTML::Template here. Sam Tregar, its author, was very careful not to include any bells and whistles that might undermine the philosophy of keeping the business logic separate from the user interface. Despite the limited template syntax, I've never had a requirement for anything more sophisticated. However, against Sam's better judgment, he created an extension called HTML::Template::Expr, which allows a developer to add expression and function support.

Lastly, for the PHP and Python programmers out there, HTML::Template has been ported to your language of choice. More information can be found at http://htmltmpl.sourceforge.net/.

If you liked this article, share the love:
Print-Friendly Version Suggest an Article

Rate This Article

  • 1
    Poor
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
    Great

Comment on This Article

Have something to say?

Post A Comment

You need to be a member of the SitePoint Forums to comment on this post. Sign Up

Already a member? Post using your SitePoint Forums account: