Introducing HTML::Template

The Comprehensive Perl Archive Network (CPAN) contains a vast array of modules that make a developer’s life much easier. You would do well to browse the treasures at http://cpan.org before embarking on any new project.

As an example, in this tutorial I’ll provide a brief overview of how to install the HTML::Template module. But first, let’s see how you can install a Perl module on your system.

Installing Perl

Perl Installation on Windows

Perl for Windows is available as a free download at http://www.activestate.com. Installing a module is surprisingly simple; however, it does require that the module is in ActiveState’s ppd format.

Installation can be performed from the ppm shell:

C:>ppm 
PPM - Programmer's Package Manager version 3.1.
Copyright (c) 2001 ActiveState SRL. All Rights Reserved.

Entering interactive shell. Using Term::ReadLine::Stub as readline library.

Type 'help' to get started.

ppm> install HTML-Template

It’s as simple as that. If any dependencies exist, they will be installed first. Note that not all Perl modules have been packaged for ppm. To find out if a module is available, type search <module> in the shell.

If you require a module that’s not in ActiveState’s repository, it’s possible that someone else has packaged it. You can find a list of additional repositories by installing the PPM::Repositories module, then running this code:

use PPM::Repositories; 

for my $rep ( keys %Repositories ) {
   next unless $Repositories{$rep}->{Active};
   next unless grep { $_ == 5.8 } @{ $Repositories{$rep}->{PerlV} };
   print $rep, $/, $Repositories{$rep}->{location}, $/,
     $Repositories{$rep}->{Notes}, $/, $/;
}

Failing all else, you could install the module by hand. We discuss how to do this in the Unix/Linux section below.

Perl Installation on Unix/Linux

Perl installation on Unix and Linux can be achieved in two ways: manually, or automatically.

The Manual Way

Download the module, unzip and untar it.

$ tar zxvf HTML-Template-xx.tar.gz 
$ cd HTML-Template-x.x
$ perl Makefile.PL
$ make
$ make test
$ make install

If you wish to install the file manually under Windows, you’ll need to download nmake.exe from Microsoft. Then, simply replace make with nmake in the instructions above.

While the majority of modules are pure Perl, some may contain C code, in which case you will need a C compiler. (A compiler is never required for ppm packages).

Make sure that you peruse the README file before you install a module.

The Automatic Way

Some modules are dependent on other modules, which in turn may have other dependencies. Installing all these modules can be a bit tedious, but there is an alternative: install the CPAN package. Then, simply invoke the cpan shell from the command line:

$ cpan

The first time cpan is run, it will configure itself. Answer the prompts, and when the configuration is complete, you can install your package:

cpan> install HTML::Template

If any dependencies exist, cpan can fetch and install them.

Now that you know how to install Perl modules, let’s take a closer look at one of Perl’s templating solutions: HTML::Template.

Introducing HTML::Template

Perl is great as a prototyping language because it’s very expressive: developers can do a lot in a few lines. A corollary of this is that it’s easy for a small application to morph into something much bigger than anticipated. Maintaining and extending such an application can become quite onerous.

Writing large Web applications using traditional CGI techniques is an approach that doesn’t scale very well. If you’re the only developer, mixing your HTML with your Perl may be tolerable, but this approach doesn’t work when you’re part of a team. Your typical Web designer won’t want to start changing your Perl code if the design needs to be changed.

Most Web languages provide some means to separate the application code from the markup code. In most cases, the HTML is placed in separate template files, which then act as containers for dynamic data. With languages like PHP, the templates can be thought of as an extension of the core language itself, although, if you’re like me, you’ll still prefer third-party template solutions like Smarty.

Perl has a number of templating solutions. HTML::Mason and the Template Toolkit are two of the most popular solutions, and offer powerful capabilities. Developers can place sophisticated logic in their templates, but unless they’re disciplined, they can undo many of the benefits of using templates in the first place, including the separation of the business logic from the interface.

HTML::Template is a lightweight alternative. It aims to provide the most basic functionality for creating Web pages, and no more. The philosophy is to keep your Perl and your HTML separate.

A Simple Example

Below is an example of a simple template, template1.tmpl. Note that it consists mainly of standard HTML with a single non-standard tag, tmpl_var, where the attribute name is set to day.

<html> 
<head>
 <title>Template 1</title>
</head>
<body>
Today is <tmpl_var name=day>
</body>
</html>

Using the template template from Perl is very simple:

1.  #!c:/perl/bin/perl -T 
2.  use CGI qw(:all);
3.  use HTML::Template;
4.  use POSIX;
5.  print header;
6.  my $template = HTML::Template->new(filename => 'template1.tmpl');
7.  $template->param(day => strftime('%A', localtime()) );
8.  print $template->output();

Line 1 simply states where the Perl interpreter is located. The -T switch means we’re in taint mode. This provides an extra level of security to Web applications by telling Perl that we should not trust any user input unless we explicitly state otherwise. This is good practice: you should always include this switch as a matter of course.

Line 2 imports the CGI.pm module. This isn’t 100% necessary: we could write out own CGI functions by hand, but this risks introducing all sorts of bugs and security issues. The CGI module is very well-tested, and you should always use it when writing CGI applications.

At line 3, we import the HTML::Template module. Line 4 brings in the standard /POSIX functionality. This allows us easily to determine the day of the week later on. Keep in mind Perl’s philosophy of There’s More Than One Way to do It (TMTOWTDI) — we could have done this using any number of date modules.

Line 5 is CGI shorthand for print "Content-Type: text/htmlnn". We need to return the content type before we output the rest of the Web page. On line 6, we create the template object. The file name of our template is supplied as the only parameter.

Line 7 sets the <tmpl_var> tag with the name of "day" to the day of the week. If you’re not familiar with the POSIX strftime function, %A is shorthand for returning the day of the week. The same formatting masks are available to PHP and C.

And finally, at line 8, we display the Web page.

So now we’ve been introduced to the basic HTML::Template philosophy: we create mostly HTML code, and we intersperse some <tmpl> placeholders for dynamic content. The syntax is kept deliberately simple; your Web designers can simply maintain the site’s look and feel through standard HTML and a small number of additional tags.

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/.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

No Reader comments

Comments on this post are closed.