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

This is a question regarding HTML::Template::Expr. I have a template which has a big tmpl_loop block. And inside there are lot of tmpl_vars and tmpl_ifs with expr attributes. They expr attribute values(expressions) just have the ||, &&, ==, <, ( and ) symbols. I also added a function "not" which is nothing but sub { !shift }.

The problem was that it was taking about 6 seconds for the template output() call when the tmpl_loop got around 130 records! So I tried to implement differently. I used the following code to convert the template text so that it can be filled with HTML::Template.

my $template_text = read_file('test.tmpl'); # get all expr attributes my @orig_exprs = ($template_text =~ /expr="[^"]*"/g); my @exprs = @orig_exprs; @exprs = map({s/\s+//g; s/^expr="//; s/"$//; s/not\((.*?)\)/!$1/g; + $_} @exprs); @orig_exprs = map({s/[|&()]/\\$&/g; $_} @orig_exprs); # construct new tmpl_var/tmpl_if names in place of the expressions my @expr_names = @exprs; @expr_names = map({s/==/_is_/g; s/</_lt_/g; s/\|\|/_or_/g; s/\&\&/ +_and_/g; s/!/not_/g; $_} @expr_names); # replace the expression names in the actual template $template_text =~ s/$orig_exprs[$_]/$expr_names[$_]/g for ( 0..$#e +xprs ); @exprs = map({s/\w{2,}/\$row->\{$&\}/g; $_} @exprs); # generate new template file my $tmpl_filename = '/tmp/test.tmpl'); write_file($tmpl_filename, $template_text);
And here is the function that was used to set the values for the new expression variables in the template.
sub _fill_expr_params { my ($row, $expr_names, $exprs) = @_; $row->{$expr_names->[$_]} = eval($exprs->[$_]) for ( 0.. $#$exprs +); }

A hash-ref for a record $row with template variables used in the expresssion will be passed to this function and the references of @expr_names and @exprs arrays that we saw earlier will be paseed in to this function.

After doing this conversion I found that it took just 1 second for the template output() call! And I checked whether it works fine and it did. Can anyone please suggest whether I am making any mistake here? I saw in HTML::Template::Expr that Parse::RecDescent was used for evaluating expressions but in my _fill_expr_params function I have just used eval. Can this cause any problem?

Although I haven't done some optimizations yet like registering the functions beforehand(http://search.cpan.org/~samtregar/HTML-Template-Expr-0.07/Expr.pm#MOD_PERL_TIP) I think it shouldn't make much of a difference in the template output. Please correct me if I am wrong.

Thanks,
Ganesh

Replies are listed 'Best First'.
Re: Optimize a HTML::Template::Expr template
by zwon (Abbot) on Aug 22, 2009 at 13:26 UTC

    You can give a try to HTML::Template::Pro and check if it's really so fast as they're saying, but I personally prefer to avoid using HTML::Template unless I need just to insert couple of values onto page. There are Template and HTML::Mason for more complex cases.

      Thanks zwon. I am trying HTML::Template::Pro. But I also need to call query() on the template object. Is it possible to get around this? In the sense use HTML::Template::Pro but still do query().

      Edit: Or if I am not asking for too much is there a way to convert a HTML::Template object to HTML::Template::Pro object after I am done with all the query() calls and also some param() calls?

        Nope, query is not supported. And I don't think there's good way to convert HTML::Template object into HTML::Template::Pro