http://www.perlmonks.org?node_id=246408

lacertus has asked for the wisdom of the Perl Monks concerning the following question:

Hey Friends,

I'm having a jot of difficulty conceptualizing this implementation of a CGI program. I'm just starting out with CGI here, so if I am blatantly overlooking something, go easy on me. I have "CGI Programming with Perl", but can't seem to find the solution to my question. Here's the code, explanation follows:
sub cgiOut { my $q = new CGI; print $q->header( "text/plain" ), $q->start_html( -title=>"Apache Stats for $hostname", -bgcolor=>"#ffffff"), $q->h2( "Apache Stats for $hostname" ), $q->hr, $q->table( { -broder=>"1", -width=>"100%" }, $q->Tr( [ for(sort keys %host) { ??? RIGHT HERE ??? } print $q->end_html; }
You see, I am trying to insert table data consisting of the key and value of %host (at 'RIGHT HERE'), but this implementation is screwy. I have opened up the Tr section, but what next? That for loop comes into play while print is still outputting to stdout. I hope I have been clear in my inquiry, I'm a bit fouled up here!

Thanks Kindly,
Lacertus

------------------------------------
"There is more in heaven and earth
than is dreamt of in your philosophy"

edited: Fri Mar 28 20:41:18 2003 by jeffa - title change (was: CGI Heeby Jeebies)

Replies are listed 'Best First'.
Re: Constructing HTML tables with CGI.pm
by BrowserUk (Pope) on Mar 28, 2003 at 07:25 UTC

    The first problem is that you can't embed for loops inside function calls inside a print statement. However, Perl nicely deals with this using map. The second problem is that if you pass your TD wrapped data to Tr() as an anonymous array (ie. wrapped in []) as you have shown, CGI.pm will wrap each of the TD's in a seperate TR, which is probably not want you want. This may get started.

    #!perl -slw use strict; use CGI; use CGI::Pretty; sub cgiOut { my (%host) = @_; my $q = new CGI; print $q->header( "text/plain" ), $q->start_html( -title=>"Apache Stats for \$hostname", -bgcolor=>"#ffffff"), $q->h2( "Apache Stats for \$hostname" ), $q->hr, $q->table( { -border=>"1", -width=>"100%" }, map{ $q->Tr( $q->td($_) , $q->td($host{$_}) ) } sort keys %host ); print $q->end_html; } my %host= ( foo=>100, bar=>200,, baz=>300 ); cgiOut %host;

    Oh. I noticed a third problem too, it's spelt border not broder :)


    Examine what is said, not who speaks.
    1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
    2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
    3) Any sufficiently advanced technology is indistinguishable from magic.
    Arthur C. Clarke.
Re: Constructing HTML tables with CGI.pm
by dws (Chancellor) on Mar 28, 2003 at 07:23 UTC
    It looks like you're headed towards something like the following (untested) fragment.
    print $q->header('text/html'), $q->start_html('yada yada'), $q->h2('more yada'), $q->hr, $q->table( { -border => 1, -width => '100%' }, ( map { $q->Tr( $q->td($_), $q->td($host{$_}) ) } sort keys %host )), $q->end_html;
    Note how map replaces the foreach you thought you'd need.

    Note also that you want the header to be 'text/html'. 'text/plain' will work for some browsers (e.g., IE), but only because they try to outsmart the content type if the the body looks like HTML. Don't rely on this behavior.

Re: Constructing HTML tables with CGI.pm
by robartes (Priest) on Mar 28, 2003 at 07:24 UTC
    Well, if you want to keep your 'print HTML as one print statement' paradigm, you just Build the content of the table outside of the print statement:
    #!/usr/local/bin/perl -w use strict; use CGI; my %host=( 'camel', 'flea', 'frog', 'green'); cgiout(); sub cgiout { my $q= new CGI; my $tablecontent=[$q->th(['key', 'value'])]; for (sort keys %host) { push @$tablecontent, $q->td([ $_, $host{$_} ]) ; } print $q->table( { border => 1, -width => '100%'}, $q->Tr( $tablecontent), ); }
    This results in this table:
    key value
    camel flea
    frog green

    Update: Removed slightly snide comment open for misinterpretation.

    CU
    Robartes-

      Hi, I tried the code you provided. But it didnt print me a table. Below is the output I got.
      <table width="100%" border="1"><tr><th>key</th> <th>value</th></tr> <t +r><td>camel</td> <td>flea</td></tr> <tr><td>frog</td> <td>green</td>< +/tr></table>
Re: Constructing HTML tables with CGI.pm
by kabel (Chaplain) on Mar 28, 2003 at 07:28 UTC
    you want Tr () to output your hash. so, each key/value pair inside the hash must be encapsulated inside a td () - the loop to use therefore is "map", not "for".

    for is only used for the sideeffects of the corresponding block that is applied to each of the elements of the list. especially the for does not return anything meaningful.

    the map takes a list, and returns a list - and that is what you want. you specify the transform of each element in the list in the map block. consider this:

    use strict; use warnings; use CGI qw/:standard/; my %hosts = ('a' .. 'z'); cgiOut (); sub cgiOut { my $q = new CGI; print $q->header( "text/plain" ), $q->start_html( -title=>"Apache Stats for \$hostname", -bgcolor=>"#ffffff"), $q->h2( "Apache Stats for \$hostname" ), $q->hr, $q->table( { -border=>"1", -width=>"100%" }, $q->Tr({}, [map { td([$_, $hosts{$_}]) } sort keys %hosts])), $q->end_html; }

    HTH
Re: Constructing HTML tables with CGI.pm
by The Mad Hatter (Priest) on Mar 28, 2003 at 16:36 UTC
    What the others have said is good and answers your question, but if you're going to be doing a lot of stuff like this, consider using HTML::Template or some other templating system. Most support loops in the template.