HTML::Template's TMPL_LOOP tag is useful for displaying lists of things. But if the list becomes long, you might want to break it into columns. HTML::Template doesn't provide an easy way to do this. The columnize() method, below, will take your loop data (in the structure required by HTML::Template's param() method - making this easy to incorporate into your existing code) and create a new structure, reformatted into rows and columns. You specify both the number of columns as well as the ordering of your data - either across or down the columns. (Your comments are invited.)
Sample simple usage:
... my $flat_data = [{data=>'A'} , {data=>'B'}, {data=>'C'}, {data=>'D'},{data=>'E'}]; my $columnized_data = columnize($flat_data, 3, "across"); my $tmpl_file = ...; my $tmpl = HTML::Template->new( filename => $tmpl_file, loop_context_vars => 1 ) or die "Creation of template object from $tmpl_file failed."; $tmpl->param( {DATA_LOOP => $columnized_data}); print "Content-type: text/html\n\n", $tmpl->output();
The output will look like:
A B C D E
In case you're wondering, the return value of columnize() was:
[ { 'COLUMN_LOOP' => [ {'data' => 'A'}, {'data' => 'B'}, {'data' => 'C'} ] }, { 'COLUMN_LOOP' => [ {'data' => 'D'}, {'data' => 'E'} ] } ];
Alternatively, had you called columnize($flat_data, 3, "down"), you'd get output:
A C E B D
with columnize() returning:
[ { 'COLUMN_LOOP' => [ {'data' => 'A'}, {'data' => 'C'}, {'data' => 'E'} ] }, { 'COLUMN_LOOP' => [ {'data' => 'B'}, {'data' => 'D'} ] } ];
Once you've added this second dimension to your data, you'll need to to do the same to your template. This is easy, since HTML::Template allows for nesting TMPL_LOOP tags. Simply add a nested TMPL_LOOP tag named COLUMN_LOOP, to your existing TMPL_LOOP. (The outer loop represents the rows, the inner loop, the columns).
So if your existing TMPL_LOOP section looks like: <tmpl_loop name="DATA_LOOP"> <tr> <td> <tmpl_var name="data">"> </td> </tr> </tmpl_loop> Change it to: <tmpl_loop name="DATA_LOOP"> <tr> <tmpl_loop name="COLUMN_LOOP"> <td> <tmpl_var name="data">"> </td> </tmpl_loop> </tr> </tmpl_loop> ____
The code:
#!/usr/bin/perl -w use strict; use Carp; sub columnize { my $rows_ref = shift; my $num_cols = shift; my $order = shift; if (!defined $rows_ref or !defined $num_cols or !defined $order) { croak("Undefined params not permitted:\n"); } if ($num_cols < 1) {croak "Bad column-number param: $num_cols\n";} if ($order !~ /^(across|down)$/i) {croak "Bad order param: $order\n +";} use integer; # use integer division for all division operations my $num_rows = ($#$rows_ref / $num_cols) + 1; my @result_rows = (); for (my $row = 0; $row < $num_rows; $row++) { for (my $col = 0; $col < $num_cols; $col++) { my $index; if ($order eq "across") { $index = ($row * $num_cols) + $col; } else { $index = ($col * $num_rows) + $row; } # Skip any empty spots in the last row (if "across") # or in the last column (if "down"): next if ($index > $#$rows_ref); $result_rows[$row]->{COLUMN_LOOP}->[$col] = $rows_ref->[$inde +x]; } } return \@result_rows; } ____
Caveat: when calling columnize with a "down" ordering, the column parameter is used as a maximum suggested column count, rather than a fixed specification. It calculates the number of rows that would result from the given number of columns, and then chooses an actual number of columns that would leave the fewest empty slots in the last row. Consider:
columnize(<data set with 11 items>, 5, "down"); A literal interpretation would produce: A D F H J B E G I K C
But if you're going to fill 3 rows anyway, and require the end-user to read vertically, then what you (or at least your reader) would probably want is:
A D G J B E H K C F I
If you look at the output of the 'ls' command, you'll see that it follows a similar algorithm. Of course, this will usually only make a difference when you specify a lot of columns, and your data set is relatively small.

In reply to Producing Columns with HTML::Template by hey_david

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.