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

I'm struggling trying to populate an HTML::Template using a two dimensional array, which contains the results of a database query. I've tried many permutations of the following code. I either get an infinite loop, or template variable does not exist error. Is there something obviously wrong? Thanks in advance for your input.
sub table_data { my $self = shift; my @outer_loop; for (my $row = 0; $row <= @{$self->{selection}}; $row++) { my %hash; $hash{table_data_begin_row} = q{<fo:table-row>}; my @inner_loop; for (my $col = 0; $col <= @{$self->{selectionAttr}}; $col++) { my %hash; $hash{table_data} = $self->{selection}[$row][$col]; push @inner_loop, \%hash; } $hash{table_data_close_row} = q{</fo:table-row>}; $hash{table_data} = \@inner_loop; push @outer_loop, \%hash; } $self->{tmpl_obj}->param(table_data_loop => \@outer_loop); }
TEMPLATE:
<fo:table-body> <TMPL_LOOP NAME=table_data_loop> <TMPL_VAR NAME=table_data_begin_loop> <TMPL_LOOP NAME=table_data> <fo:table-cell> <fo:block border-right-width="0.5pt" text-align="center" vertical-al +ign="middle"> <TMPL_VAR NAME=table_data> </fo:block> </fo:table-cell> </TMPL_LOOP> <TMPL_VAR NAME=table_data_close_loop> </TMPL_LOOP> </fo:table-body>

Replies are listed 'Best First'.
Re: Help with nested loop in HTML::Template
by wfsp (Abbot) on Dec 22, 2007 at 10:59 UTC
    Hi mhearse,

    In your script you have table_data_begin_row and in your template you have table_data_begin_loop which may be part of the problem.

    That particular var is hard coded into your script so you could put it in the template (also table_data_close_row).

    I can't run your script to know if that is only snag but here's a snippet showing how I might do it. Notice the use of Data::Dumper which is excellent for these type of problems.

    #!/bin/perl5 use strict; use warnings; use Data::Dumper; use HTML::Template; $Data::Dumper::Indent = 1; $Data::Dumper::Sortkeys = 1; my $data = [ [qw{one two three}], [qw{four five six}], [qw{seven eight nine}], ]; my @outer_loop; for my $outer (@{$data}){ my @inner_loop; for my $inner (@{$outer}){ push @inner_loop, {data => $inner}; } push @outer_loop, {inner_loop => \@inner_loop}; } print Dumper \@outer_loop; my $param = {outer_loop => \@outer_loop}; my $tmpl = do{local $/;<DATA>}; my $t = HTML::Template->new(scalarref => \$tmpl) or die qq{tmpl obj fa +iled\n}; $t->param($param); print $t->output; __DATA__ <TMPL_LOOP NAME=outer_loop> --------------------------- <TMPL_LOOP NAME=inner_loop> <TMPL_VAR NAME=data> </TMPL_LOOP> </TMPL_LOOP>
    output (Dumper output followed by H::T output):
    $VAR1 = [ { 'inner_loop' => [ { 'data' => 'one' }, { 'data' => 'two' }, { 'data' => 'three' } ] }, { 'inner_loop' => [ { 'data' => 'four' }, { 'data' => 'five' }, { 'data' => 'six' } ] }, { 'inner_loop' => [ { 'data' => 'seven' }, { 'data' => 'eight' }, { 'data' => 'nine' } ] } ]; --------------------------- one two three --------------------------- four five six --------------------------- seven eight nine
Re: Help with nested loop in HTML::Template
by Rhandom (Curate) on Dec 22, 2007 at 19:24 UTC
    I would use Template::Alloy's extensions to HTML::Template. It is much easier to access data and will probably run faster than using HTML::Template by itself.
    #!/usr/bin/perl use strict; use warnings; use Template::Alloy qw(HTML::Template); use HTML::Template; my $data = [ [qw{one two three}], [qw{four five six}], [qw{seven eight nine}], ]; my $tmpl = do{local $/;<DATA>}; my $t = HTML::Template->new(scalarref => \$tmpl) or die qq{tmpl obj fa +iled\n}; $t->param({data => $data}); print $t->output; __DATA__ <TMPL_FOR row IN data> --------------------------- <TMPL_FOR i IN row> <TMPL_VAR i> </TMPL_FOR> </TMPL_FOR>
    The output will be same as the previous post.

    my @a=qw(random brilliant braindead); print $a[rand(@a)];
      Thanks for your replies. I was able to get it working using both of the examples in the two posts. I had no idea html templates had the <FOR> tag. Impressive.