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

Hello,

I am new to perl modules and for sure Text::Template. Could you please give some hints for how to use fill_in more than once for the same template and each time we fill in different variables in the template? Is this possible? If we use HASH, do we have to cover all the variables in the template inside the hash we are going to fill in once?
Thanks a lot.

taizi
  • Comment on Text::Template=>How to fill in with more than one time?

Replies are listed 'Best First'.
Re: Text::Template=>How to fill in with more than one time?
by perrin (Chancellor) on Sep 04, 2003 at 02:17 UTC
    All you have to do is call fill_in more than once, using the same template object each time. Did you try it?
      Hi there:

      Yes, I tried it. The filled variables in the template in the first call became null in the second call of fill_in. The template only got the value of variables used in the second call of fill_in.

      Here is the template


      It has come to our attention that you are delinquent in your {$monthname[$last_paid_month]} payment. Please remit ${sprintf("%.2f", $amount)} immediately, or your patellae may be needlessly endangered. Love, Mark "Vizopteryx" Dominus

      Here is the script

      #!/usr/bin/perl5.6 use Text::Template; my $template = Text::Template->new(SOURCE => 'formletter.tmpl') or die "Couldn't construct template: $Text::Template::ERROR" +; my @monthname = qw(January February March April May June July August September October November Dece +mber); my %vars1 = (title => 'Mr.', last_paid_month => 1, # February amount => 392.12, monthname => \@monthname, ); my $result = $template->fill_in(HASH => \%vars1); if (defined $result) { print $result } else { die "Couldn't fill in template: $Text::Template::ERROR" } my %vars2 = (title => 'Mr.', firstname => 'Bill', lastname => 'Gates', ); $result = $template->fill_in(HASH => \%vars2); if (defined $result) { print $result } else { die "Couldn't fill in template: $Text::Template::ERROR" }

      Here is the output

      Dear Mr. ,
      It has come to our attention that you are delinquent in your
      February payment. Please remit
      $392.12 immediately, or your patellae may be needlessly endangered.
      Love,
      Mark "Vizopteryx" Dominus
      Dear Mr. Gates,
      It has come to our attention that you are delinquent in your
      payment. Please remit
      $0.00 immediately, or your patellae may
      be needlessly endangered.
      Love,
      Mark "Vizopteryx" Dominus

      <edit: castaway: added code tags>
        Argh!
        I played around with this for a while before I realised the mistake.. Your set of values for the second template contains neither 'last_paid_month', nor 'amount', the other values aren't even being used.. It's no wonder theres no month or value in the second output..

        C.

        (Well that was a good waste of 20 minutes.. Do I feel stupid..)

        Use another hash to hold the variables and just keep adding your new hash to it. Anything you change will override the previous values, anything you don't will just stay there.
        #!/usr/bin/perl5.6 use Text::Template; my $template = Text::Template->new(SOURCE => 'formletter.tmpl') or die "Couldn't construct template: $Text::Template::ERROR" +; my @monthname = qw(January February March April May June July August September October November Dece +mber); my %vars1 = (title => 'Mr.', last_paid_month => 1, # February amount => 392.12, monthname => \@monthname, ); my %keepvars = %vars1; my $result = $template->fill_in(HASH => \%keepvars); if (defined $result) { print $result } else { die "Couldn't fill in template: $Text::Template::ERROR" } my %vars2 = (title => 'Mr.', firstname => 'Bill', lastname => 'Gates', ); %keepvars = (%keepvars, %vars2); $result = $template->fill_in(HASH => \%keepvars); if (defined $result) { print $result } else { die "Couldn't fill in template: $Text::Template::ERROR" }
        Oh, now I understand: you want to call it more than once but have the variables from the first call still be there, right? I thought you just wanted to produce multiple different results without loading the template again.

        I don't understand why you would want to do that, but the answer is no, you can't. Instead, you should collect all the values for a single run of the template before you call fill_in. Is there a reason you are avoiding that?

Re: Text::Template=>How to fill in with more than one time?
by jeffa (Bishop) on Sep 04, 2003 at 13:32 UTC
    Yes. First, you create the template:
    my $template = Text::Template->new( TYPE => 'FILE', SOURCE => 'formletter.tmpl', ) or die $Text::Template::ERROR;
    But before we move, here is a modified version of that file that i want you to consider:
    Dear {$name}, It has come to our attention that you are delinquent in your {$month} payment. Please remit {$amount} immediately, or your patellae may be needlessly endangered. Love, Mark "Vizopteryx" Dominus
    Back the Perl script, now that we have a template ready to go, we just need to fill it in and print. Usually, you are doing this inside of a while or foreach loop, because your data usually is going to either be coming from a (delimited) file or a data base. Let's say, for simplicity's sake that this is a CSV file like so:
    Gates,Bill,Mr.,1,42000000000 Wall,Larry,Mr.,5,2
    That's last name, first name, salutation, the month index, and the amount owed. So, all we need to do is extract the data. I recommend Text::CSV_XS, but i am going to use split, again for simplicity:
    my @monthname = qw(January yadda yadda December); open FH, '<', 'data.csv' or die "can't open data file: $!"; while (<FH>) { chomp; my ($last,$first,$title,$month,$amount) = split ',', $_; my $result = $template->fill_in(HASH => { name => "$title $first $last", month => $monthname[$month], amount => sprintf('%.2f',$amount), }); die $Text::Template::ERROR unless $result; print $result; }
    And that's it. :)

    One thing you may have noticed is that i calculated the month in the Perl code, not the template. I also formatted the amount in the Perl code, but this particular decoration might be better in the template. Hope this helps.

    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)
    
      Hi Jeffa:

      Thanks for the information. I learned something new to me from your comments. However, my original intention was not to fill in the template with complete information more than once like what you showed here. I tried to fill in the template part by part. For example, get name from one data file, fill-in the template, and then get amount from another data file, then fill in again. In the following fill-in, I like to keep the previously filled-in information. It seems not possible for the current Text::Template

      Taizi
        Ah, it seems I misunderstood your question as well. In that case, consider not using a HASH, but a PACKAGE instead, and just change the values you want to change in the package vars, keeping the previous ones the same. Text::Template itself has no memory function. Alternatively, you could re-use the same HASH each time, and just change the variables that are different..

        C.