-1

I'm using CGI and HTML::Template. I need to add below tag in all the templates which contain <form> tag (tag should be added inside <form> tag).

<input type="hidden" value="TO_BE_PARSED_FROM_CGI">

I don't want to edit all the template files manually. Is there any method available in HTML::Template to do this? Some type of hook which I can pass while creating constructor of HTML::Template?

Chankey Pathak
  • 21,187
  • 12
  • 85
  • 133
  • You don't have to modify all the template files manually. Perl has HTML parsers that can help you locate where the changes need to be made. Go ahead and fix the templates ***once*** as opposed to modifying your code to do it each and every time it runs. – Sinan Ünür Sep 16 '16 at 14:15
  • @SinanÜnür my example below could do this – Dr.Avalanche Sep 16 '16 at 14:18
  • @Dr.Avalanche Sure. In general, I am not a fan of slurpy methods unless one has to use them, but voted your answer up, too. – Sinan Ünür Sep 16 '16 at 14:26
  • Did the solution we discussed in chat not work? – simbabque Sep 16 '16 at 18:38

2 Answers2

2

You don't have to modify all the template files manually. Perl has HTML parsers that can help you locate where the changes need to be made. Go ahead and fix the templates once as opposed to modifying your code to do it each and every time it runs. Below, I use \*DATA for illustrative purposes, but, clearly, the list of template files could come from anywhere.

Back the files up first (better still, make sure you do this in a branch in your version control system).

#!/usr/bin/env perl

use utf8;
use strict;
use warnings;
use open qw[ :std :encoding(UTF-8) ];

use HTML::TokeParser::Simple;

run(\@ARGV);

sub run {
    my $argv = shift;
    my $parser = HTML::TokeParser::Simple->new(handle => \*DATA);

    while (my $token = $parser->get_token) {
        print $token->as_is;
        if ($token->is_start_tag('form')) {
            print qq{\n<input type="hidden" name="sid" value="<TMPL_VAR NAME=SID>">\n};
        }
    }
}

__DATA__
<h3>Here is a form:</h3>

<form
    method="POST"
    action="https://example.com/action-action-action.pl"
    id="action"
    name="actionable_form">

<label for="date">Date:</label>
<input type="date" name="date" id="date">

<input type="submit">

</form>
Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
1

Is there any method available in HTML::Template to do this?

This again? ;) No, you need to read and manipulate the DOM to do what you want. HTML::Template only works with it's specific tags/markers. Store $template->output() into a variable. Read the variable with a parser such as Mojo::DOM to find the instances of forms and append your content. This example illustrates a solution:

#!/usr/bin/perl
use strict;
use warnings;
use Mojo::DOM;

# fake output of $template->output;

my $html = << 'HTML';
  <html>
    <head>
      <title>test</title>
    </head>
    <body>
      <form method="post">
        <input type="text" id="name">
      </form>
    </body>
  </html>
HTML

# you say you want to parse this from CGI
my $value ='foo'; 

# what you want to add
my $addme = "<input type='hidden' value='$value'>";

my $dom = Mojo::DOM->new();

$dom->parse( $html )->at('form')->child_nodes->first->append( $addme )->root;
print $dom;

prints:

  <html>
    <head>
          <title>test</title>
        </head>
        <body>
          <form method="post">
            <input type="hidden" value="foo"><input id="name" type="text">
          </form>
        </body>
  </html>

Edit.

Since we don't know what you're doing within your templates the sanest method is to base any changes on the output of your existing code. Meaning that you can safely add the method illustrated to the above before the point were you currently print the output of your template. You could use the code given as a one off update to actually write the change back to your templates, and the value rather than foo could be an HTML::Template param.

Dr.Avalanche
  • 1,944
  • 2
  • 28
  • 37
  • If this may be a recurring issue, rather add a tag which then includes the hidden tags. (remember to escape properly) – FtLie Sep 16 '16 at 12:37
  • @FtLie the last time they asked this question they stated that they did not want to edit the template files at all: edit and in the question 'I don't want to edit all the template files manually. ' – Dr.Avalanche Sep 16 '16 at 12:39
  • @FtLie sorry, misunderstood your point. Yes that is another option, but the problem is that in order to get the rendered template we need to act upon `$template->output`. Without knowing exactly what the templates were doing, the above method is actually the better choice. – Dr.Avalanche Sep 16 '16 at 12:54