|P is for Practical|
The question of how to use CGI scripts to generate HTML comes up frequently. Consistently, people try to embed the HTML directly in the CGI script. While for simple scripts, this may be useful, it quickly becomes a maintenance nightmare for large sites.
Imagine even a relatively small site that has 5 CGI scripts that each generate 5 Web pages. Since we want a common look and feel, those Web pages often have duplicate elements that get repeated throughout the code. Sometimes, the programmer realizes that common elements should be stuffed in a single location and then added to each page as appropriate. This is useful because it makes updating the pages easier, but it still faces the "mixing HTML and code" problem.
Typically, an organization has relatively few programmers, so updating these Web pages require having relatively high-priced programmers doing HTML maintenance. The programmers often hate this and the company suffers. Another annoying problem with this is a problem that Perl has with "here" documents. Imagine a 100 line here document beginning on line 219 of a script. If one of the values embedded in a document is undefined, you often get an error message like the following:
Perl reports the first line that begins the here document as the one containing the unitialized value. Often, this can be a difficult bug to track down!
While there are many reasons to consider alternatives to embedding HTML in your CGI scripts, I'll just leave it at that and suggest that you consider a template scheme. Many recommend using Template Toolkit for this. However, for a light-weight, easy to implement system, consider using HTML::Template.
Here's a simple example. We'll create a small Web page that will print out all of your environment variables. We'll show four basic functions of HTML::Template: embedded values, looping, branching, and including external HTML files in the main HTML document.
Create the above document and save it as "template.tmpl". You'll notice some new tags in there. Here's what they do:
The TMPL_VAR tag allows you to assign a value to a name (in this case, HEADING will be assigned a scalar value in the CGI script.
This tells HTML::Template that we want to start a loop named ENV_VARS. While it's iterating through the loop, it will look for TMPL_VAR tags and assign them scalar values that the CGI script creates. The following tags are used in the HTML template:
To populate them, an array of anonymous hash references will be created. Each hash reference will look like the following:
As HTML::Template iterates over the array, it will take the name/value pairs in the hash reference and use them to duplicate the items in the loop with the name/value pairs filled in appropriately.
The TMPL_INCLUDE tag tells HTML::Template to take the contents of the filename specified and insert them into the HTML document where the tag is found. Note that, as of this writing, you cannot include HTML::Template tags in the included document.
For now, just create a file named footer.tmpl and add the following line to it:
Simple branching is also possible:
This is a simple branch. It tests the value of the BOOL scalar that gets passed to the template object. If it evaluates as true... well, you get the idea.
Finally, here's the script that gets this to work:
It's the $template->param() call that actually sets up the template. Note that HEADING and BOOL are simply scalar values, while ENV_VARS is the array of hash references that is used for the loop. Try playing around with some of these values to get a feel for how this works.
HTML::Template actually has quite a bit of functionality beyond what I have described here, so be sure to read the documentation. Further, there are a variety of ways to get the output that I did above.
Incidentally, I did not describe the use of "loop context vars." They can be handy to control the behavior of loops, but they've been noted to be buggy in the past and I have found them to still have some issues. Handle with care.