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

Hello monks,

I am trying to use print <<HTML; to print html from perl code. I'll have to use perl code to work some business logic and depending on the result will have to print html. So need to switch between perl code and print html in the same .pl

When I tried to use print <<HTML; to print a bunch of html tags and then stop it for some perl code and resume, I don't get any syntax error but the page when printed shows all the code after the first ending "HTML".

Sample code (from a much larger chunk) is:
#!/usr/bin/perl use strict; use warnings; use DBI; use CGI; use CGI::Carp qw(fatalsToBrowser); #print "Content-type: text/html\n\n"; my $database = "dbname"; my $db_server = "hostname"; my $user = "dbusername"; my $password = 'pwd'; #single quote as it contained $ my $query = new CGI; print $query->header; my $dbh = DBI->connect("DBI:mysql:$database:$db_server",$user,$passwor +d); my $statement = "select active from comm_desk_widget_status where user + = 'admin' order by name asc"; my $sth; $sth = $dbh->prepare($statement) or die "Couldn’t prepare the query: $ +sth->errstr"; my $rv = $sth->execute or die "Couldn’t execute query: $dbh->errstr"; print <<HTML; #start HTML printing in chunk <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1" +> <title>CommDesk Dashboard</title> <style> body { background-color: AliceBlue; } span.note1 {float:left} span.note2 {font-size:80%} table#t01, #t01 th, #t01 td { border: none; border-collapse: collapse; font-size:80%; } </style> </head> <body> <div style="float:left; width:50%"> <b>Call Volume Tab Configuration</b> <br /><span class="note2">Customize your personal view of the Call Vol +ume Tab.</span> HTML; #stop HTML printing in chunk. But when this file is fetched from + browser, it displays everything starting from the following line unt +il next while (my \@row = $sth->fetchrow_array) { print "<table id="t01">"; print "<tr>"; if (row[0] eq '1') { print "<td><form><input type="checkbox" name="trunk_usage" val +ue="1" checked>% Trunk Usage</form></td>"; } else { print "<td><form><input type="checkbox" name="trunk_usage" val +ue="1">% Trunk Usage</form></td>"; } if (row[1] eq '1') { print "<td><form><input type="checkbox" name="pre_ivr" value=" +1" checked>Pre-IVR Call Volume</form></td>"; } else { print "<td><form><input type="checkbox" name="pre_ivr" value=" +1">Pre-IVR Call Volume</form></td>"; } print "</tr>"; print "<tr>"; if (row[2] eq '1') { print "<td><form><input type="checkbox" name="trunk_group" val +ue="1" checked>Trunk Group Utilization</form></td>"; } else { print "<td><form><input type="checkbox" name="trunk_group" val +ue="1">Trunk Group Utilization</form></td>"; } if (row[3] eq '1') { print "<td><form><input type="checkbox" name="average_speed" v +alue="1" checked>Average Speed of Answer</form></td>"; } else { print "<td><form><input type="checkbox" name="average_speed" v +alue="1">Average Speed of Answer</form></td>"; } print "</tr>"; print "<tr>"; if (row[4] eq '1') { print "<td><form><input type="checkbox" name="outage_call" val +ue="1" checked>Outage Call Volume</form></td>"; } else { print "<td><form><input type="checkbox" name="outage_call" val +ue="1">Outage Call Volume</form></td>"; } if (row[5] eq '1') { print "<td><form><input type="checkbox" name="ivr_call" value= +"1" checked>IVR Call Volume</form></td>"; } else { print "<td><form><input type="checkbox" name="ivr_call" value= +"1">IVR Call Volume</form></td>"; } print "</tr>"; print "<tr>"; if (row[6] eq '1') { print "<td><form><input type="checkbox" name="non_outage_call" + value="1" checked>Non-Outage Call Volume</form></td>"; } else { print "<td><form><input type="checkbox" name="non_outage_call" + value="1">Non-Outage Call Volume</form></td>"; } if (row[7] eq '1') { print "<td><form><input type="checkbox" name="post_ivr" value= +"1" checked>Post-IVR Call Volume</form></td>"; } else { print "<td><form><input type="checkbox" name="post_ivr" value= +"1">Post-IVR Call Volume</form></td>"; } print "</tr>"; print "</table>"; print <<HTML; #start HTML printing in chunk. Browser shows code until +above line on page </div> </body> </html> HTML

UPDATE (so anyone who stumbles across this node will know what were the take aways I was able to use, and probably they should also): After receiving lot of great advice, I was able to use following:

Used hash instead of array

Rearranged code to put the HTML generating code in subs, so the HTML is removed from main program flow.

I wanted to use some template as well but I can only use what I have available on the server, and Template::Tiny is not available

Replies are listed 'Best First'.
Re: Can we use print <<HTML; twice in same file?
by anonymized user 468275 (Curate) on Aug 25, 2015 at 15:06 UTC
    The construction you are using is called a heredoc. Perl treats everything after the <<HTML expression as input until it finds a matching HTML line. "HTML; # blah blah" was NOT a match with "HTML" and was therefore not treated as the terminator. I think it's pretty picky -- even an "invisible" space after the "HTML" could fail the match and I doubt comment "#" will "work" (i.e. be stripped rejected as you thought by the matching) and semicolon is also probably going to fail the match too.

    One world, one people

Re: Can we use print <<HTML; twice in same file?
by toolic (Bishop) on Aug 25, 2015 at 15:11 UTC
    From perlop:
    The terminating string must appear by itself (unquoted and with no surrounding whitespace) on the terminating line.
    Change:
    HTML; #stop HTML printing in chunk. But when this file is fetched from + browser, it displays everything starting from the following line unt +il next
    to:
    HTML

      No, you quoted the text about the trailing tag. Just change <<HTML; #… to <<"HTML"; #…


      Enjoy, Have FUN! H.Merijn

        Did you try that?

        Adding the double quotes around the opening tag won't solve the OP's problem. When using a herdoc, perl will "assume" that double quotes were used if none were used.

Re: Can we use print <<HTML; twice in same file?
by GotToBTru (Prior) on Aug 25, 2015 at 17:06 UTC

    It's very simple to test this.

    $data = <<HTML; Here is my data! HTML $other = <<HTML; Here is some OTHER data! HTML print "$data\n$other\n";

    Output:

    Here is my data! Here is some OTHER data!
    Dum Spiro Spero
Re: Can we use print <<HTML; twice in same file?
by 1nickt (Canon) on Aug 25, 2015 at 16:53 UTC

    It's a Bad Idea to mix languages in a program. You have CSS inside HTML inside Perl ... it would make your life a lot easier to separate them out. Please look at Template::Tiny or another templating engine.

    At the very least, create your own package to contain all that HTML-producing code, or at the very very least, put the code in subs so the HTML is removed from your main program flow. E.g.:

    while (my @row = $sth->fetchrow_array) { print ivr_call( $row[5] ); print non_outage_call( $row[6] ); } sub ivr_call { my $checked = shift eq '1' ? 'checked' : ''; return "<td><form><input type='checkbox' name='ivr_call' value='1' $ +checked>IVR Call Volume</form></td>"; } sub non_outage_call { my $checked = shift eq '1' ? 'checked' : ''; return "<td><form><input type='checkbox' name='non_outage_call' valu +e='1' $checked>Non-Outage Call Volume</form></td>"; }
    The way forward always starts with a minimal test.
Re: Can we use print <<HTML; twice in same file?
by Perl300 (Friar) on Aug 25, 2015 at 18:11 UTC
    Hi again,

    Thanks for all the inputs. I had screwd up the code too much and once the confusion I had about heredoc was clarified, I removed the syntax errors (thanks to fishmonger) and now the script is working fine.

    I still need to modify how I am fetching data as it's one column I am fetching but only first element of array is getting the value and others are left uninitialized. I'll find what I am still doing wrong.

    Also appreciate all for suggesting me better approach as well. I am creating dynamic webpage in perl and as this is first time had no idea of how to do and where to start. So I started from reading some html and decided to use CGI module as it's on perl 5.8 and I can't get modules that are not already present.

Re: Can we use print <<HTML; twice in same file?
by Perl300 (Friar) on Aug 25, 2015 at 15:58 UTC
    Hi all, thanks for your inputs. I had tried removing # and everything after it preceding HTML (including ;) but it gives chunk of compilation errors first one being

    Bareword found where operator expected at Admin_Test.pl line 54, near ""<table id="t01"

    And when I add a ";" after "HTML" all the compilation errors disappear.

    To correct those compilation errors I had added a semocolon after HTML. My aplologies for not mentioning this in original post

      You have a number of syntax errors. Lets look at the first few lines of your while loop.

      while (my \@row = $sth->fetchrow_array) { print "<table id="t01">"; print "<tr>"; if (row[0] eq '1') {

      my \@row is wrong. It should be my @row.
      print "<table id="t01">"; has a quoting error. You need to either escape the inner double quotes in id="t01" or use single quotes like this id='t01'.
      if (row[0] eq '1') is missing the $ on the $row[0] var

      When I see a repeating pattern I think 'can I loop this ?'

      my @stat = ( ['trunk_usage' ,'% Trunk Usage'], ['pre_ivr' ,'Pre-IVR Call Volume'], ['trunk_group' ,'Trunk Group Utilization'], ['average_speed','Average Speed of Answer'], ['outage_call' ,'Outage Call Volume'], ['ivr_call' ,'IVR Call Volume'], ['non_outage' ,'Non-Outage Call Volume'], ['post_ivr' ,'Post-IVR Call Volume'],); my @row = (1,0,1,1,1,0,1,0); #while (my @row = $sth->fetchrow_array) { print qq!<table id="t01"><tr>!; for my $i (0..$#stat){ my $chk = ($row[$i] == 1) ? 'checked' : ''; print qq!<td> <input type="checkbox" name="$stat[$i][0]" value="1" $chk /> $stat[$i][1] </td>!; if (($i % 2) && ($i < $#stat)){ print q!</tr><tr>!; } } print q!</tr></table>!; #} print q!</div></body></html>!;
      You need to put the database stuff back to replace the test values in @row, and probably the <form> tags but around the table not each input.
      poj
Re: [Solved]: Can we use print <<HTML; twice in same file?
by Perl300 (Friar) on Aug 25, 2015 at 18:53 UTC

    Updated subject to mention this is solved. Also I figured that I had to use first element of @row while it loops through all the rows and use only that element.

    So I created a new array @widget and kept adding first element from @row while it iterates over all the rows of result. And finally using elemtnts of this new array.

    my @widget; while (my @row = $sth->fetchrow_array) { push(@widget, $row[0]); }

      You should change your SQL so it only fetches the data you want. Alternatively, see DBI.pm#selectcol_arrayref

      .
      The way forward always starts with a minimal test.

      What is in the NAME field of comm_desk_widget_status. Are they names like 'trunk_usage','post_ivr', etc ?

      poj
        mysql> desc comm_desk_widget_status; +--------------+--------------+------+-----+-------------------+ | Field | Type | Null | Key | Default | +--------------+--------------+------+-----+-------------------+ | user | varchar(100) | NO | PRI | NULL | | name | varchar(200) | NO | PRI | | | display | varchar(200) | NO | | NULL | | active | int(1) | NO | | 1 | | ts | timestamp | NO | | CURRENT_TIMESTAMP | | last_updated | varchar(100) | YES | | NULL | +--------------+--------------+------+-----+-------------------+
        This is the table description.
Re: [Solved]: Can we use print <<HTML; twice in same file?
by bulrush (Scribe) on Sep 03, 2015 at 11:41 UTC
    The standard Perl hash, the size of the key plus data is limited to 1008 bytes. Is this enough for you?

    When I use bigger data, I use DBM::Deep. I tie it to a file but it's darn fast and has worked fine on multiple applications for me. I believe the hash data size is only limited by your hardware and OS, same for the max file size.

    Other people have tied DBD::SQLite into a hash also.

    Max data size when you tie BerkeleyDB to a hash is 1 billion bytes.

Re: [Solved]: Can we use print <<HTML; twice in same file?
by locked_user sundialsvc4 (Abbot) on Aug 26, 2015 at 04:51 UTC

    I’ll second the motion that you really should be using templates here.   (My personal favorite happens to be Template::Toolkit, but de nada.)   There is a fairly-excellent chance that the output of this program will need to be “tweaked,” in response to every whim of the Marketing Department ... ;-) ... and it is w-a-y-y-y easier to do this if the output is described by an external template, instead of being embedded in the Perl source.

A reply falls below the community's threshold of quality. You may see it by logging in.