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


In my perl scripts, I often generate HTML code like this :




print <<eof ;
The variable is : $variable
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<HR color=#99ffcc SIZE=4>
<FONT face=Arial color=#99ffcc><B>
Bottom text




However, this code is not easily editable with softwares like FrontPage.

I would like to put this code in an easily editable .html file, and use an instruction in my perl script, that would insert this html file in my perl script, with the $variable, so that $variable is substituted on execution of the script. This is an example with $variable but i would like to work with any $xxx

Any suggestion ?

Thanks for your help.

Replies are listed 'Best First'.
Re: inserting HTML file in a PERL script
by Tortue (Scribe) on May 29, 2005 at 11:17 UTC
    Here's the kind of thing you could do if this needs to be quick and dirty and you don't have time to learn Template::Toolkit:
    my $variable = 'This is a value!'; my $variable_name = '$variable'; my $template = snarf('template.htm'); $template =~ s/\Q$variable_name\E/$variable/g; print $template; sub snarf { local $/ = undef; my $template_file = shift; open F, $template_file or die "can't open $template_file"; my $template = <F>; close F; $template; }
    with the template.htm file containing:
    <HTML> <HEAD> <TITLE>Title</TITLE> </HEAD> The variable is : $variable <BR><BR> <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0> <TR><TD> <HR color=#99ffcc SIZE=4> <FONT face=Arial color=#99ffcc><B> Bottom text </B></FONT> </TD></TR></TABLE> </BODY> </HTML>

      Thank you for your help everyone, it is highly appreciated.


      About this script, it seems to be applicable only if the variable is named $variable

      Could it be possible to give me the code for a script that would replace anything starting with $xxx ?

      The variables that i have got in my html code can be named A-Z and '_' like $EMAIL or $CONTACT_ADDRESS

        yes, you could match on the $ and lookup the variable name in a hash, and replace with the value. Expects the template variables to be uppercase (A-Z and _ only) and the hash keys to be lower case.
        use strict; use warnings; my %data = ( first_name => 'Foo', email => 'Bar', ); $/ = undef; my $s = <DATA>; $s =~ s/\$([A-Z_]+)/exists $data{lc $1}?$data{lc $1}:$&/esg; print $s; __DATA__ First name is $FIRST_NAME and<br> email is: $EMAIL. junk is $JUNK
        Just to generalize the script I gave you... This replaces any variable in the template with its value in the program. It's a quick-and-dirty fix that may solve your problem if you're in a rush. Of course, as others have noted, it would be better if you used a proper templating system. Note also that this only works for simple scalar variables (e.g. $thing, $ZOWIE), not for more complicated variables such as array or hash elements (e.g., $var[$num] or $var{thing}).
        my $template = snarf('template.htm'); while ($template =~ /(\$[:alpha:]\w*)/g) { my $variable_name = $1; my $value = eval $variable_name; $template =~ s/\Q$variable_name\E/$value/g; } print $template;
Re: inserting HTML file in a PERL script
by dimar (Curate) on May 29, 2005 at 09:26 UTC

    Your question makes a little sense, but it is not exactly clear what is your underlying rationale and goals:

    • do you intend to serve the html over the web or just open them locally on your own machine?
    • do you intend to use msft FrontPage extensions in your pages or just using that because it is the only tool you have available?
    • are you using this variable interpolation method because you do not want to use any of the myriad templating solutions already out there?

    Absent a better understanding of why you are going this specific path, please take a look at Template Toolkit. It seems as though you are trying to re-invent it, or something similar.


      Hello and thanks for your answer.

      - I will serve them on the web

      - I use FrontPage, because it is indeed the only tool that I have in order to design nice looking HTML pages.

      - I inherited of these scripts that I now have to manage myself, and dont feel like re-writing them all with new tools, as my knowledge of perl is very limited.

      These scripts have a myriad of embedded HTML codes with the print <<eof method, and I have to re-edit and make them look better.

      But for these .pl and .pm scripts, FrontPage is of little help for me, as the mixture of perl script and HTML code makes it almost impossible to properly edit.

        To add to the advice from tchatzi.

        The first time I came across Perl I was in a very similar situation to yourself. Perhaps the experiences I had maybe helpful.

        Only make one small change at a time. You'll stand a better chance of having something that still works.

        A point often made is that, as much as possible, keeping code and HTML separate makes maintaining both easier. A first step could be at least moving it all to the end of the script. Have a sub that returns the HTML.

        my $name = 'John'; my $html = get_html(); # sub name corrected # later... sub get_html{ my $html = <<HTML; <html> <head> <title>my html</title> </head> <body> <p>Hi there $name</p> </body> </html> HTML return $html; }
        The next step I took was to replace the variable with an HTML comment.
        <p>Hi there <!-- name --></p>
        and then the code would look something like
        my $html = get_html(); $html =~ s/<!-- name -->/$name/;
        The advantage here is that Frontpage can happily use the HTML.

        After that it wasn't long before the HTML ended up in a file.

        my $html; { local $/; my $file = 'template.html'; open my $fh, '<', $file or die "can't open $file to read: $!"; $data = <$fh>; close $fh or die "cannot close $file: $!"; }
        This way you can maintain the HTML in FrontPage.

        Once you get to this stage you start to realise you have trod a well worn path! Many have gone before you. As scooterm pointed out above there are many template modules available. I now use HTML::Template and find it excellent.

        There are many other aspects of cgi scripts you may want to consider (there is a very good module for that too).

        Hope this is of help. If after looking through the docs you still hit some snags (I hit plenty) come back, show what you were trying to do, what you have tried, what you expected. If you do that I have always found the monks very helpful.

        Good luck!

        update: Corrected name of sub in code snippet

        What you can do is make your own page in FrontPage, as long as you feel more comfortable when working with it , instead of straight HTML code, and then go on the 'code' tab that Frontpage has and copy and paste the code or parts of it, between the print <<EOF;.......and......EOF
        Remember to add any variables that the preview code had.

        Or you can copy and paste the html code from the perl script to your code tab at frontpage(without any variables in it of course) and try to change it the way you want, and copy and paste it back from where you got it.

        This is realy not the right solution though, but if you don't feel comfortable with perl or html, then i think its your only way out.

        If there are more than one part of html code in the perl script, then remember to delete from the html code that fronpage will generate, the <html>,<body>,</html>,</body> tags, and also any other headers including <meta> tags, from the middle parts of your perl script.

        ``The wise man doesn't give the right answers, he poses the right questions.'' TIMTOWTDI
Re: inserting HTML file in a PERL script
by dimar (Curate) on May 29, 2005 at 19:16 UTC

    On a contrarian note, thetallblondguy, the time it has taken you to consider the partial solutions in this thread, and the different ways you could indicate variables, might have been better spent looking into a full-grown "real world" application like Template Toolkit (or any of the legion of its kin). Because if this is any kind of serious work, this is not the kind of wheel you want to re-invent.

    Your clarification actually suggests your question is not really a perl or CGI question, but a question about how to *surgically* separate the Perl from HTML without breaking either one. That's exactly what templating systems are designed to do.

    Sure, you could create perl subroutines that spit out HTML, or separate files with some (special syntax) in them, but the list of wheels you would have to re-invent to get it right are too numerous to list here. For example:

    How to disambiguate 'true variables' from 'false variables'? $19.95USD -> not a variable, a price $e1p_zE@z -> not a variable, a suggested user-password Micro$oft -> not a variable, a common company name $$$CASH$$$ -> not a variable, a common spam subject line How to handle common scenarios that always come up? # A variable whose value is contingent on another variable # A variable that appears inside of a loop # A variable that should have some 'default' fill in value if the user +-supplied value is left blank # A sample code-snippet that should appear inside the HTML and not be +messed with or interpolated AT ALL

    There is a whole catalogue of issues to deal with, and each issue you resolve (on your own) means yet one more (undocumented) 're-invented wheel' that the person who comes after you will have to learn just to figure out what is going on.

    If you *really* insist on creating your own system from scratch, you should at least try to use a totally unique syntax for indicating the presence of a 'true variable' ... something that is not likely to appear in any other context.

    Hello @@@:username:@@@, Please consider using @@@:existing_template_system:@@@ instead of creating your own from scratch; instead of hand-rolling the @@@:huge_number:@@@th ad-hoc system that no one understands except you.
Re: inserting HTML file in a PERL script
by astroboy (Chaplain) on May 29, 2005 at 18:44 UTC
    HTML::Template is a very light, simple solution. The Template Toolkit is nice, but it may be bigger than what you need.
Re: inserting HTML file in a PERL script
by TedPride (Priest) on May 29, 2005 at 18:32 UTC
    davidrw's solution is the best imho, with some minor changes to the substitution line:
    $s =~ s/\$([a-zA-Z]\w*)/exists $data{lc $1} ? $data{lc $1} : ''/esg;
    There's no point allowing just uppercase letters and then lowercasing them. It's also not a good idea (at least in my opinion) to leave $vars that don't have a value defined as the original text. The intention was probably to keep things like $10.45 from being interpreted as '', but you can easily avoid this by defining your var names as starting with a letter.
      actually i hadn't thought of the $10.45 case, but that's a key point. The upper/lower casing I picked was pretty much just an arbitrary definition of this quick & dirty template system. My rationale was all upper for the template vars so that they stand out more in the template. And all lowercase for the keys since variable/key names are typically lowercase. Also, lc'ing it makes it tolerant of typos like $FIRSt_NAME in the template.

      As for what to do with unknown vars, i figured that leaving '$FOO' in there was better to make it obvious that it didn't match, whereas doing '' might not be noticed..

      But both ways are up to the template authoer on how they prefer it to work..
Re: inserting HTML file in a PERL script
by kyoshu (Curate) on May 31, 2005 at 07:15 UTC
    why don't you just create a html template and
    use HTML::Template;
    example of perl sciript:
    #!/usr/bin/perl -wT
    use strict;
    use CGI;
    use HTML::Template;
    use CGI::Carp qw/fatalsToBrowser/;
    my $default_puslapis = 'pradzia';
    my $default_sritis = 'pagrindinis';
    my $templ = 'data/pagrindinis/main.html';
    my $q = new CGI;
    if (grep { /application\/xhtml\+xml/ } $q->Accept ) {
            print "Content-type: application/xhtml+xml\n\n";
    } else {
            print "Content-type: text/html;Charset=utf-8\n\n";
    my $tmpl = HTML::Template->new(filename => $templ);
    my $puslapis = $q->param('puslapis') || $default_puslapis;
    $puslapis =~ /(\w+)/;
    $puslapis = $1;
    my $sritis = $q->param('sritis') || $default_sritis;
    $sritis =~ /(\w+)/;
    $sritis = $1;
    if (-e "data/$sritis/$puslapis.html") {
            undef local $/;
            open my $f, "<data/$sritis/$puslapis.html";
            my $content = <$f>;
            close $f;
            $tmpl->param('tekstas', $content);
    } else {
            $tmpl->param('tekstas', 'Klaida!');
    and then you create 'data/pagrindinis/main.html'
    where in html code you just add something like:
    <TMPL_VAR NAME="tekstas">
    in the place where you want $content to appear.
    (all this code is from working example with some changes for you to see :-))
Re: inserting HTML file in a PERL script
by Ctrl-z (Friar) on May 30, 2005 at 12:16 UTC

    I would second scooterm's comment. In addition, the answers above dont really solve your problem:

    • You dont want to be cutting and pasting between an HTML editor and Perl editor
    • You dont want to be heavily modifying the HTML (adding special variable tags or whatever)
    • You do not want to be heavily modifying the existing Perl code (rewriting to a module API or adding half-assed templating subroutines)

    To sum up, by the time perl starts executing you want it to run exactly as your program does now. But for you (while developing) you want the html fragments in their own file, to edit with Frontpage and use Perl's existing $variable syntax.

    Consider using a source filter.

    package Insert; use Filter::Simple; sub slurp { my $file = shift; my ($str, $in); open($in, $file) or die $!; local $/ = undef; $str = <$in>; close $in; return $str; } FILTER { 1 while $_ =~ s/INSERT\(\s*?["']?([^"']*?)["']?\s*?\)/slurp($1)/e; + } 1;

    This will paste the contents of files into your script before perl begins executing.

    1. Save the above code with the rest of your program as
    2. add use Insert; to the top of your script
    3. Cut the contents of each heredoc and paste into a new file
    4. Replace the heredoc contents with INSERT("/path/to/that/file")

    So this

    my $variable = "World!"; print <<EOT; Hello $variable EOT

    would become this

    use Insert; my $variable = "World!"; print <<EOT; INSERT("includeme.txt") EOT
    With the file includeme.txt being
    Hello $variable

    This will do what you want - but be careful what you wish for.

    At least you can concentrate on hacking the HTML rather than adapting existing code to an API or debugging a broken wheel.

    Once you get the HTML the way you want it, you can simply paste it back into the code to get better performance.

    time was, I could move my arms like a bird and...