Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

list of list and HTML::Template

by InfiniteLoop (Hermit)
on Sep 20, 2005 at 15:03 UTC ( [id://493477]=perlquestion: print w/replies, xml ) Need Help??

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

Greetings Monks,
Im using HTML::Template to display data from database in a tree form. The data is being passed an arrayref of hashref, to the template. The data looks something like this;
[ { 'name' => 'foo', 'id' => 1 'children' => [ { 'name' => 'bar', 'id' => 2, "children" => ... }, .... ] }, ... ]
I use a <tmpl_loop> construct to display the "name" and "id" in the tree.

However for some of the branches the "children" key might be present or not. Also the "children" is recursive, as in a sub-branch can have sub-sub-branch and so on.

I have problem in using HTML::Template to display this data structure, as the data is recursive. Is there a way to use HTML::Template to display such data structures ?

Replies are listed 'Best First'.
Re: list of list and HTML::Template
by jeffa (Bishop) on Sep 20, 2005 at 19:55 UTC

    I would use a recursive subroutine to walk the tree and collect the output as you go. Maybe something like this will help you (depth traversal):

    use HTML::Template; my $thingy = [ { name => 'foo', id => 1, children => [ { name => 'bar', id => 2, children => [ { name => 'baz', id => 3, }, { name => 'qux', id => 4, }, ], }, { name => 'ducks', id => 5, }, ], }, { name => 'last', id => 6, }, ]; our $tmpl = HTML::Template->new( filehandle => \*DATA, die_on_bad_params => 0, ); our $output; our $tab_loop = []; recurse($thingy); print $output; sub recurse { my $thingy = shift; for (@$thingy) { $tmpl->param(tab_loop => $tab_loop, %$_); $output .= $tmpl->output; push @$tab_loop, { tab => "\t" }; recurse($_->{children}) if ref $_->{children}; pop @$tab_loop; } } __DATA__ <tmpl_loop tab_loop><tmpl_var tab></tmpl_loop><tmpl_var id> - <tmpl_va +r name>

    I'd be tempted to attack this problem with Template instead.

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
Re: list of list and HTML::Template
by neniro (Priest) on Sep 20, 2005 at 15:41 UTC
    Of course you can try to build a nested template but you need to know a maximal depth:
    <TMPL_IF NAME="children"> <TMPL_LOOP NAME="children"> ... <TMPL_IF NAME="children"> <TMPL_LOOP NAME="children"> (...) </TMPL_LOOP> </TMPL_IF> ... </TMPL_LOOP> </TMPL_IF>
    I don't think that this is a good idea (or practise). I personally would try to use <TMPL_VAR NAME="tree_expanded"> and use an own recursive defined function to stringify the tree. :(
Re: list of list and HTML::Template
by Ctrl-z (Friar) on Sep 20, 2005 at 17:20 UTC

    Filters could be your friend here. Still requires a maximum depth to stop infinite recursion...

    In tmpl.tmpl

    <TMPL_LOOP kids> <div style="margin-left:10px;border:1px dotted #555555"> <h3><TMPL_VAR name>.<TMPL_VAR depth></h3> ho hum... <TMPL_RECURSE "tmpl.tmpl">Sorry, ran out of steam</TMPL_RE +CURSE> </div> </TMPL_LOOP>
    In program
    use HTML::Template; my $MAX_DEPTH = 3; my $t = HTML::Template->new( filename => "tmpl.tmpl", die_on_bad_params => 0, filter => mk_filter($MAX_DEPTH +)); # populate with recursive data... $t->param( kids => recursive() ); print "<html><head><title>Wheeee!</title></head><body>"; print $t->output(); print "</body></html>"; # # create a filter for HTML::Template # sub mk_filter { my $max = shift; my $cur = 0; return sub { print STDERR "FILTERING:\n",${$_[0]},"\n\n"; 1 while ${$_[0]} =~ s#<TMPL_RECURSE\s+?"([^"]+)"\s*>(.*?)</TMP +L_RECURSE>#do_filter($max,$cur++,$1,$2)#sgei ; print STDERR "FILTERED:\n",${$_[0]},"\n\n"; }; } # # Perform substitution # sub do_filter { my($max,$cur, $file, $els) = @_; if($cur < $max) { open my $f, $file or die $!; local $/ = undef; return <$f>; } else{ return $els; } } # # just produce some recursive data... # sub recursive { my $depth = shift || 0; my @kids = (); return [] if $depth > $MAX_DEPTH; push @kids, { name=> $_, depth=>$depth, kids=> recursive($depth+1) + } foreach (0...2 ); return \@kids; }



    time was, I could move my arms like a bird and...
Re: list of list and HTML::Template
by saberworks (Curate) on Sep 20, 2005 at 15:55 UTC
    You can use <TMPL_IF> to test to see if there are "children." However this doesn't help your recursive problem. In the one case I was passing recursive data, I ended up doing what has been suggested: write a function to "stringify" the data and do that and pass the result to HTML::Template. Not exactly a great solution, have you searched CPAN for any of the addons to HTML::Template? You could try writing a plugin: HTML::Template::Pluggable.
Re: list of list and HTML::Template
by InfiniteSilence (Curate) on Sep 20, 2005 at 15:20 UTC
    Pop open the perldoc again and look for the following section:

    Number: 3 <TMPL_LOOP>s within <TMPL_LOOP>s are fine and work as you would ex +pect. If the syntax for the param() call has you stumped, here's an exam +ple of a param call with one nested loop: $template->param(LOOP => [ { name => 'Bobby', nicknames => [ { name => 'the big bad + wolf' }, { name => 'He-Man' }, ], }, ], );

    Celebrate Intellectual Diversity

      The problem is I don't have the control over the "children" array ref, i.e I don't know in advance how deep the "children" is stacked. Other wise, in my template I would have used a <tmpl_loop> in a <tmpl_loop>.
Re: list of list and HTML::Template
by zigdon (Deacon) on Sep 20, 2005 at 23:33 UTC
    Couldn't you include templates recursivly?
    Children.tmpl: ... <TMPL_IF Children> <TMPL_LOOP Children> <TMPL_INCLUDE Children.tmpl> </TMPL_LOOP # end looping on the children> </TMPL_IF # closing the optional children>
    Just make sure to adjust max_includes to a level higher than the max number of generations you might encounter.

    -- zigdon

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://493477]
Approved by socketdave
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (4)
As of 2024-04-15 05:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found