Vol. 2, No. 7
Generating HTML with CGI.pm
Once before, way back in issue 39, we delved into the CGI libraries
that Tripod offers, and joined hands to praise Tripod for the
bounty.
Today let's take a look at a particular one of these libraries --
the favorite of Web wranglers worldwide -- CGI.pm.
CGI, the Common Gateway Interface, is the standard way for a Web
server to pass users' requests to applications and then pass the
resulting data back to the user. A very common instance of this is
sending the data that the user enters in a form to a Perl script
(or "CGI script") for processing. CGI.pm is an optional module for
Perl that makes it easy both to parse HTML form inputs and to create
HTML pages dynamically. It provides a library of predefined functions
that are very helpful for this kind of work, particularly when writing
larger, more complex scripts. Perl CGI can certainly happen without
CGI.pm, but why not make your life easier? CGI.pm offers a simple
interface -- much simpler than HTML -- for creating HTML pages, and
gives you a dizzying amount of power for parsing input.
Setting forms aside for today, let's take a look at the page-creation
functions of the library. Say you want a very simple page with just a
single sentence on it. In HTML, you have to go through all this:
<HTML>
<HEAD>
<TITLE>Peanut Butter
</TITLE>
</HEAD>
<BODY>
I love peanut butter.
</BODY>
</HTML>
But if we're using CGI.pm to generate our page, it looks like this:
use CGI qw/:standard/;
print header();
print start_html("Peanut Butter");
print "I love peanut butter.";
print end_html();
What's happening here? Well, a lot of the tedious parts of putting
together an HTML page are being automated.
We start our script by stating that we want to use CGI.pm --
specifically, we want to import the "standard" set of functions from
that library. That "use" line, or one very much like it, will appear
in every script that uses CGI.pm.
Then we proceed to call on those functions. header() generates the
HTTP header, telling the browser what kind of page it's getting.
start_html() generates the equivalent of the first six lines of our
example page: <HTML>, the HEAD section, including the title, and
<BODY> (as well as a <!DOCTYPE> tag, which the SGML standard
encourages us all to use). Then we print our text using Perl's print
command, and finally end_html() closes the BODY and HTML tags and
sends us on our way with a kiss. It couldn't be more simple.
Naturally, we can play around with all of these. The default header
that header() sends is text/html, but we could specify text/plain,
image/jpg, or whatever we want. We can also use the status parameter
to change the page status -- to pretend it isn't there, for example,
by saying header(-status=>'404 Not Found').
To make the background color of our page black, we just mention
that that's what we want to the start_html function, et voila:
start_html(-BGCOLOR=>'black'). If we want a black page of lost
diaries ostensibly written by Dashiell Hammett, we say:
start_html(-BGCOLOR=>'black', -meta=>{'author'=>'Dashiell Hammett',
'description'=>'Lost Diaries of Dashiell Hammett'}) If no tag is
specified, any text inside the start_html parentheses will be
interpreted as the title text.
Note that syntax. Each parameter begins with a dash. => separates
an attribute and its value. If a tag has multiple attributes,
they're grouped within curly brackets. And everything's inside the
parentheses of the function.
The same syntax applies to all the HTML functions of CGI.pm. To
insert a <BR> tag into your page, just "print br();". <P> tag, same
thing: "print p();".
For italics and the like, we just make the text to be italicized the
argument of the i() function: print i("Perl can be fun!!!"). It can
also be interpolated in the middle of a longer print statement, by
using commas to separate the different functions:
print b("Perl ",i("can")," be fun.");
Notice that in the above case the whole sentence is bold, but only
one word is italicized.
And creating links -- not that you asked, but it'll come up sooner
or later -- goes like this:
print a({href=>"more.html"},"Read more");
Using CGI.pm's HTML shortcuts, HTML becomes miraculously easier to
read -- once you get used to the new format. For nested tag
structures, like lists and tables, you just use parentheses. So
something like:
<UL>
<LI>George</LI>
<LI>Paul</LI>
<LI>Ringo</LI>
<LI>John</LI>
</UL>
</pre>
becomes
print ul(
li(["George","Paul","Ringo","John"]),
);
Just give the function a list, and it'll generate a new tag for
each element of the list. This is particularly nice when we want to
give the same attribute to a number of tags. Say we want all of our
list items to have a SQUARE type bullet. In regular HTML, we'd have
to write <LI TYPE="SQUARE"> four times. In Perl, though:
print ul(
li({-type=>"square"},["George","Paul","Ringo","John"]);
);
This type of thing comes in very handy indeed when working with
tables. Watch this. Say we want to generate the following HTML:
<TABLE>
<CAPTION><B>Cats I have known</B></CAPTION>
<TR>
<TH></TH>
<TH>Irving</TH>
<TH>Polly</TH>
<TH>Rhombus</TH>
</TR>
<TR>
<TH>Gray</TH>
<TD>yes</TD>
<TD>no</TD>
<TD>yes</TD>
</TR>
<TR>
<TH>Long-haired</TH>
<TD>no</TD>
<TD>no</TD>
<TD>yes</TD>
</TR>
<TR>
<TH>Polydactylic</TH>
<TD>no</TD>
<TD>yes</TD>
<TD>no</TD>
</TR>
</TABLE>
Whew. But we can generate that table in just a few lines of Perl,
as follows:
print table(caption(b('Cats I have known')),
Tr([
th(['','Irving','Polly','Rhombus']),
th('Gray').td(['yes','no','yes']),
th('Long-haired').td(['no','no','yes']),
th('Polydactylic').td(['no','yes','no'])
])
);
The same approach can be used to great effect when you're filling
table cells with variables, numbers calculated on the fly, or
anything else -- just stick the variable name into the list, and
generate away!
That covers the basics of generating HTML. See you here next time
for more fun with CGI! Meanwhile, practice writing scripts to
generate HTML pages on the fly, and try using variables to encode
some of the content.
RESOURCES:
Intro to CGI
All about CGI.pm
Tripod's Script Editor
Webmonkey's Guide to CGI