Formatting Lists and Tables with HTML Shortcuts (Perl Cookbook, 2nd Edition)

## 19.6. Formatting Lists and Tables with HTML Shortcuts

### 19.6.1. Problem

You have several lists and tables to generate and wish they were easier to output.

### 19.6.2. Solution

The CGI module provides HTML helper functions that, when passed array references, apply themselves to each element of the referenced array:

>     print ol( li([ qw(red blue green)]) );
>     <OL><LI>red</LI><LI>blue</LI><LI>green</LI></OL>
>     @names = qw(Larry Moe Curly);
>     print ul( li({ -TYPE => "disc" }, \@names) );
>     <UL><LI TYPE="disc">Larry</LI> <LI TYPE="disc">Moe</LI>
>         <LI TYPE="disc">Curly</LI></UL>

### 19.6.3. Discussion

The HTML-generating functions in CGI.pm can make it easy to generate lists and tables. Passed a simple string, these functions produce HTML for that string. But passed an array reference, they work on all strings in that array.

>     print li("alpha");
>     <LI>alpha</LI>
>     print li( [ "alpha", "omega"] );
>     <LI>alpha</LI> <LI>omega</LI>

The shortcut functions for lists are loaded when you use the `:standard` import tag, but you need to ask for `:html3` explicitly to get helper functions for tables. There's also a conflict between the `<TR>` tag, which would normally make a `tr( )` function, and Perl's built-in `tr///` operator. Therefore, to make a table row, use the `Tr( )` function.

This example generates an HTML table starting with a hash of arrays. The keys will be the row headers, and the array of values are the columns.

>     use CGI qw(:standard :html3);

>     %hash = (
>         "Wisconsin"  => [ "Superior", "Lake Geneva", "Madison" ],
>         "Colorado"   => [ "Denver", "Fort Collins", "Boulder" ],
>         "Texas"      => [ "Plano", "Austin", "Fort Stockton" ],
>         "California" => [ "Sebastopol", "Santa Rosa", "Berkeley" ],
>     );

>     $\ = "\n";

>     print "<TABLE><CAPTION>Cities I Have Known</CAPTION>";
>     print Tr(th [qw(State Cities)]);
>     for $k (sort keys %hash) {
>         print Tr(th($k), td( [ sort @{$hash{$k}} ] ));
>     }
>     print "</TABLE>";

That generates text like this:

>     <TABLE> <CAPTION>Cities I Have Known</CAPTION>
>         <TR><TH>State</TH> <TH>Cities</TH></TR>
>         <TR><TH>California</TH> <TD>Berkeley</TD> <TD>Santa Rosa</TD>
>             <TD>Sebastopol</TD> </TR>
>         <TR><TH>Colorado</TH> <TD>Boulder</TD> <TD>Denver</TD>
>             <TD>Fort Collins</TD> </TR>
>         <TR><TH>Texas</TH> <TD>Austin</TD> <TD>Fort Stockton</TD>
>             <TD>Plano</TD> </TR>
>         <TR><TH>Wisconsin</TH> <TD>Lake Geneva</TD> <TD>Madison</TD>
>             <TD>Superior</TD></TR>
>     </TABLE>

You can produce the same output using one print statement, although it is slightly trickier because you have to use a `map` to create the implicit loop. This print statement produces output identical to that displayed previously:

>     print table
>             caption('Cities I have Known'),
>             Tr(th [qw(State Cities)]),
>             map { Tr(th($_), td( [ sort @{$hash{$_}} ] )) } sort keys %hash;

This is especially useful for formatting the results of a database query, as in Example 19-3 (see Chapter 14 for more on databases).

#### Example 19-3. salcheck

>       #!/usr/bin/perl
>       # salcheck - check for salaries
>       use DBI;
>       use strict;
>       use CGI qw(:standard :html3);

>       my $limit = param("LIMIT");

>       print header( ), start_html("Salary Query"),
>             h1("Search"),
>             start_form( ),
>             p("Enter minimum salary", textfield("LIMIT")),
>             submit( ),
>             end_form( );

>       if (defined $limit) {
>           my $dbh = DBI->connect("dbi:mysql:somedb:server.host.dom:3306",
>               "username", "password")
>               or die "Connecting: $DBI::errstr";
>           my $sth = $dbh->prepare("SELECT name,salary FROM employees
>               WHERE salary > $limit")
>               or die "Preparing: ", $dbh->errstr;
>           $sth->execute
>               or die "Executing: ", $sth->errstr;

>           print h1("Results"), "<TABLE BORDER=1>";

>           while (my $row = $sth->fetchrow_arrayref( )) {
>                  print Tr( td( $row ) );
>           }

>           print "</TABLE>\n";
>           $sth->finish;
>           $dbh->disconnect;
>       }

>       print end_html( );

### 19.6.4. See Also

The documentation for the standard CGI module; Recipe 14.9

Copyright © 2003 O'Reilly & Associates. All rights reserved.