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

Hi Perl Monk,

I am trying to create a HTML reports for each customer using HTML::Template. I need some help on how to clear the params in the template before the for loop process the next customer from the text file.

Current Output for 1st customer processed by for loop:

Data Transfer Report for JKL

Period Device Code Port Code Traffic Direction Data Transfer (GB)

1Feb2010 - 28Feb2010 SWITCH FastEthernet1_0_6 OUT 1.024
1Feb2010 - 28Feb2010 SWITCH FastEthernet1_0_6 IN 1.358
1Feb2010 - 28Feb2010 SWITCH FastEthernet2_0_6 OUT -0.000
1Feb2010 - 28Feb2010 SWITCH FastEthernet2_0_6 IN -0.000


Current Output for 2ndt customer processed by for loop:

Data Transfer Report for JKL
Data Transfer Report for GHI
Period Device Code Port Code Traffic Direction Data Transfer (GB)
1Feb2010 - 28Feb2010 SWITCH FastEthernet1_0_6 OUT 1.024
1Feb2010 - 28Feb2010 SWITCH FastEthernet1_0_6 IN 1.358
1Feb2010 - 28Feb2010 SWITCH FastEthernet2_0_6 OUT -0.000
1Feb2010 - 28Feb2010 SWITCH FastEthernet2_0_6 IN -0.000
1Feb2010 - 28Feb2010 SWITCH FastEthernet1_0_19 OUT 1.172
1Feb2010 - 28Feb2010 SWITCH FastEthernet1_0_19 IN 0.253
1Feb2010 - 28Feb2010 SWITCH FastEthernet2_0_19 OUT -0.000
1Feb2010 - 28Feb2010 SWITCH FastEthernet2_0_19 IN -0.000

current code

#!/usr/bin/perl # # use warnings; use strict; use DateTime; use HTML::Template; use Fcntl; my $dt = DateTime->new( year => 1964, month => 10, day => 16, hour => 16, minute => 12, second => 47, nanosecond => 500000000, time_zone => 'Asia/Taipei', ); $dt = DateTime->now(); # same as ( epoch => time() ) my $year = $dt->year; my $is_leap = $dt->is_leap_year; my $month_abbr = $dt->month_abbr; # Jan, Feb, ... my $mnth = $dt->subtract(months => 1); my $first = $mnth->clone->set_day(1); my $first1 = $first->day . $first->month_abbr . $first->year; my $last = $first->clone->add( months => 1 )->subtract( days => 1 ); my $last1 = $last->day . $last->month_abbr . $last->year; my $lastmonth_period = "$first1 - $last1"; my $cust_file = "customer.txt"; my $billing_file = "20100301.bill"; my $cust; open (CUST_DATA, $cust_file) || die "Can't read '$cust_file': $!\n"; while (defined (my $line = <CUST_DATA>)) { chomp $line; # Remove trailing newline my ($cust_id,$cust_name) = split(/:/,$line); $cust->{$cust_id}->{name} = $cust_name; } close(CUST_DATA); my @bill_fields = qw(cust_id x_cust_id2 Device_Code Port Traf_Dir x_st +art_date x_end_date x_number Data_Usage); my $bill_line; my $bill_data; open(BILL_DATA, $billing_file) || die "Can't read '$billing_file': $!\ +n"; while (defined (my $line = <BILL_DATA>)) { chomp $line; # Remove trailing newline @{$bill_line}{@bill_fields} = split(/\s/, $line); $bill_data->{ $bill_line->{cust_id} }->{ $bill_line->{Device_Code} + }->{ $bill_line->{Port} }->{ $bill_line->{Traf_Dir} } = $bill_line-> +{Data_Usage}; } close(BILL_DATA); sub by_name ($$) { return $cust->{$a}->{name} <=> $cust->{$b}->{name} +}; my @loop; # the loop data will be put in here my @nameloop; for my $customer ( keys %$cust ) { my $total_usage = 0; my $cust_name = "$cust->{$customer}->{name}"; # Create each customer html file my $template = HTML::Template->new(filename => "billfix.tmpl"); sysopen (HTML, "$cust_name.html", O_RDWR|O_EXCL|O_CREAT, 0755); my %namerow = ( cust_name => $cust_name, ); push(@nameloop, \%namerow); $template->clear_params(custname_loop => \@nameloop); $template->param(custname_loop => \@nameloop); for my $device ( sort by_name keys %{$bill_data->{$customer}} ) { for my $port ( sort keys %{$bill_data->{$customer}->{$device}} + ) { (my $short_port = $port) =~ s/^FastEthernet/Fa/g; for my $direction qw(OUT IN) { my $usage = $bill_data ->{$customer}->{$device}->{$por +t}->{$direction} . $/; my %row = ( lastmonth_period => $lastmonth_period, device => $device, port => $port, direction => $direction, usage => $usage, ); push(@loop, \%row); } $template->param(billfix_loop => \@loop); } } printf HTML $template->output; }


Customer.txt file

200612:ABC
200905:DEF
200213:GHI
200010:JKL

HTML Template file

<HTML> <HEAD><title>My Billfix Page</title></HEAD> <BODY> <TMPL_LOOP NAME="custname_loop"> <H1>Data Transfer Report for <TMPL_VAR cust_name></H1> <TABLE BORDER="1"> </TMPL_LOOP> <TR> <TD><B>Period</B></TD> <TD><B>Device Code</B></TD> <TD><B>Port Code</B></TD> <TD><B>Traffic Direction</B></TD> <TD><B>Data Transfer (GB)</B></TD> </TR> <TMPL_LOOP NAME="billfix_loop"> <TR> <TD><TMPL_VAR NAME="lastmonth_period"></TD> <TD><TMPL_VAR NAME="device"></TD> <TD><TMPL_VAR NAME="port"></TD> <TD><TMPL_VAR NAME="direction"></TD> <TD><TMPL_VAR NAME="usage"></TD> </TR> </TMPL_LOOP> </TABLE> </BODY> </HTML>


Billing file

200612 200612 SWITCH FastEthernet1_0_33 OUT 01-Feb-2010 +_02:00 01-Mar-2010_02:00 4.336 1.311 200612 200612 SWITCH FastEthernet1_0_33 IN 01-Feb-2010_ +02:00 01-Mar-2010_02:00 35.435 10.716 200612 200612 SWITCH FastEthernet1_0_35 OUT 01-Feb-2010 +_02:00 01-Mar-2010_02:00 167.976 50.796 200612 200612 SWITCH FastEthernet1_0_35 IN 01-Feb-2010_ +02:00 01-Mar-2010_02:00 26.064 7.882 200612 200612 SWITCH FastEthernet2_0_33 OUT 01-Feb-2010 +_02:00 01-Mar-2010_02:00 -0.000 -0.000 200612 200612 SWITCH FastEthernet2_0_33 IN 01-Feb-2010_ +02:00 01-Mar-2010_02:00 -0.000 -0.000 200612 200612 SWITCH FastEthernet2_0_35 OUT 01-Feb-2010 +_02:00 01-Mar-2010_02:00 -0.000 -0.000 200612 200612 SWITCH FastEthernet2_0_35 IN 01-Feb-2010_ +02:00 01-Mar-2010_02:00 -0.000 -0.000 200905 200905 SWITCH FastEthernet1_0_4 OUT 01-Feb-2010_ +02:00 01-Mar-2010_02:00 3.193 0.965 200905 200905 SWITCH FastEthernet1_0_4 IN 01-Feb-2010_0 +2:00 01-Mar-2010_02:00 41.499 12.549 200905 200905 SWITCH FastEthernet2_0_4 OUT 01-Feb-2010_ +02:00 01-Mar-2010_02:00 -0.000 -0.000 200905 200905 SWITCH FastEthernet2_0_4 IN 01-Feb-2010_0 +2:00 01-Mar-2010_02:00 -0.000 -0.000 200213 200213 SWITCH FastEthernet1_0_19 OUT 01-Feb-2010 +_02:00 01-Mar-2010_02:00 3.877 1.172 200213 200213 SWITCH FastEthernet1_0_19 IN 01-Feb-2010_ +02:00 01-Mar-2010_02:00 0.837 0.253 200213 200213 SWITCH FastEthernet2_0_19 OUT 01-Feb-2010 +_02:00 01-Mar-2010_02:00 -0.000 -0.000 200213 200213 SWITCH FastEthernet2_0_19 IN 01-Feb-2010_ +02:00 01-Mar-2010_02:00 -0.000 -0.000 200010 200010 SWITCH FastEthernet1_0_6 OUT 01-Feb-2010_ +02:00 01-Mar-2010_02:00 3.386 1.024 200010 200010 SWITCH FastEthernet1_0_6 IN 01-Feb-2010_0 +2:00 01-Mar-2010_02:00 4.489 1.358 200010 200010 SWITCH FastEthernet2_0_6 OUT 01-Feb-2010_ +02:00 01-Mar-2010_02:00 -0.000 -0.000 200010 200010 SWITCH FastEthernet2_0_6 IN 01-Feb-2010_0 +2:00 01-Mar-2010_02:00 -0.000 -0.000


Thanks in advance for your help!

Replies are listed 'Best First'.
Re: Create HTML reports using HTML Template
by 7stud (Deacon) on Mar 24, 2010 at 12:12 UTC

    Use a nested loop in your template file:

    <HTML> <HEAD><title>My Billfix Page</title></HEAD> <BODY> <TMPL_LOOP NAME="custname_loop"> <H1>Data Transfer Report for <TMPL_VAR cust_name></H1> <TABLE BORDER="1"> <TR> <TD><B>Period</B></TD> <TD><B>Device Code</B></TD> <TD><B>Port Code</B></TD> <TD><B>Traffic Direction</B></TD> <TD><B>Data Transfer (GB)</B></TD> </TR> <TMPL_LOOP NAME="billfix_loop"> <TR> <TD><TMPL_VAR NAME="lastmonth_period"></TD> <TD><TMPL_VAR NAME="device"></TD> <TD><TMPL_VAR NAME="port"></TD> <TD><TMPL_VAR NAME="direction"></TD> <TD><TMPL_VAR NAME="usage"></TD> </TR> </TMPL_LOOP> </TMPL_LOOP> </TABLE> </BODY> </HTML>

    Unfortunately, that means you have to present $template->param() with a very complicated data structure. You could probably hand scribe the data reports before figuring out how to accumulate the data and present it properly to $template->param():

    use strict; use warnings; use 5.010; use HTML::Template; use Data::Dumper; my @lines = ( "Bobby June abc 15 north good", "Bobby Sept xyz 20 north fair", "Bobby March xyz 10 north great", "Jenny July def 30 south poor", "Jenny Aug stu 20 south bad", ); my @inner_loop_fields = qw{ lastmonth_period device port direction usage }; my %combined_info_for; #key = customer name #value = array for (@lines) { my($name, @data) = split; my %field_info_for; @field_info_for{@inner_loop_fields} = @data; #assignment to hash slice--allows you to do a mass #assignment to multiple keys at once push @{$combined_info_for{$name}}, \%field_info_for; #add hashes to the customer array--one array for each #customer name, perl magic -> if array doesn't exist, #create an empty one and push the value into the array } #say Dumper(%combined_info_for); #check your work my @outer_loop_fields = qw{ cust_name billfix_loop }; my @outer_loop_info; while ( my($name, $AoH_ref) = each %combined_info_for ) { my %hash_for; @hash_for{@outer_loop_fields} = ($name, $AoH_ref); #assignment to a hash slice again--multiple keys in the hash #are assigned to in one step push @outer_loop_info, \%hash_for; } my $template = HTML::Template->new(filename => "html2.tmpl"); $template->param(custname_loop => \@outer_loop_info); print $template->output();
Re: Create HTML reports using HTML Template
by moosie (Initiate) on Mar 25, 2010 at 01:23 UTC
    You need to move the @loop and @nameloop declarations inside the "for my $customer" loop. Currently you loop through each customer, adding to these arrays, but never emptying them in between customers. Also, I haven't tested this last bit, but I believe you can move your my $template = HTML::Template->new outside the loop, and then just call $template->clear_params(); at the bottom of the loop before you proceed to the next customer. Either that or use the HTML::Template caching option, so you don't have to re-parse the template with each customer.