Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Calling functions in middle of CGI HTML declarations

by dr.jekyllandme (Sexton)
on Aug 26, 2012 at 11:51 UTC ( #989811=perlquestion: print w/ replies, xml ) Need Help??
dr.jekyllandme has asked for the wisdom of the Perl Monks concerning the following question:

Hello, I am new to CGI and I am trying to do some web stuff and the one problem that I keep running into is figuring out the proper way to generate the html. For example I want to create some div elements like this:
<div id="div-test"> <div>Hello</div> <div>GoodBye</div> <div>Friend</div> <div>Adios</div> <div>Amigo</div> </div>
My Perl code that generated the above:
my @fields = qw(Hello Goodbye Friend Adios Amigo); print header, start_html( -title => "testme"), div ( { -id => "div-test" }, # instead of doing this, can i create a div just by loopin +g # through @fields div("Hello"), div("GoodBye"), div("Friend"), div("Adios"), div("Amigo") ), end_html;
As the Perl Doc suggested, I've been using CGI standard to create my html, but I am not completely familiar with how to use it. I want to insert a foreach loop after my initial div to create a set of divs for each element in the array @fields. But when I do this, it throws a syntax error. I also noticed that I just can't insert a if statement or other Perl operations in a html declaration. How do I do this? If anyone can help, it would be great. Thank you for your time.

Comment on Calling functions in middle of CGI HTML declarations
Select or Download Code
Re: Calling functions in middle of CGI HTML declarations
by zwon (Monsignor) on Aug 26, 2012 at 11:56 UTC
Re: Calling functions in middle of CGI HTML declarations
by Don Coyote (Monk) on Aug 26, 2012 at 15:04 UTC

    Another way would be to place the array as an argument to the div method directly. You can get different results from slightly different constructs. Please note I am using the object orientated syntax. I have updated this reply with the syntax for the method orientated syntax. See end of post.

    Placing the array directly as an argument will result in the list being expanded as content.

    print $q->div( { -id => "div-test" }, $q->div(@fields), ); <body> <div id="div-test"> <div>Hello Goodbye Friend Adios Amigo</div> </div> </body>

    To reproduce a singular div for every item in the list then let the method know you are supplying a list by placing square brackets around the array.

    print $q->div( { -id => "div-test" }, $q->div([@fields]), ); <body> <div id="div-test"> <div>Hello</div> <div>Goodbye</div> <div>Friend</div> <div>Adios</div> <div>Amigo</div> </div><!--end div-test div --> </body>

    Using a foreach loop may become necessary if you perhaps wanted the id of each div to be entitled as per each item of the array. But while in the first two instances you would be placing the array into the content compartment of the argument to div, this would be a standalone statement for cgi to process. That is, placed outside of any arguments to div, if you wanted to you could write a quick div method to wrap any arrays of divs.

    print $q->div( { -id => "div-test" }, $q->div([@fields]), ); print ( $q->start_div({-id=>$_}), $q->end_div ) foreach @fields; <body> <div id="div-test"> <div>Hello</div> <div>Goodbye</div> <div>Friend</div> <div>Adios</div> <div>Amigo</div> </div><!--end div-test div --> <div id="Hello"></div> <div id="Goodbye"></div> <div id="Friend"></div> <div id="Adios"></div> <div id="Amigo"></div> </body>

    Have a play around with those and you should be able to get what you want.

    Update UTC 19:55 27 08 2012

    I have revisited my reply to adjust for using the method calling approach. Most of the previous works by simply removing the $q calls. However to enable the final foreach statement to work you will also need to import the div element methods as well as :standard.

    use CGI qw/:standard *div/;

    This allows you to use start_div and end_div methods. The glob in front of element allows you to call any start_element, end_element pair from your script. I have also included the reference syntax as shown by Your Mother in reply

    #! /usr/bin/perl use strict; use warnings; use CGI qw /:standard *div/; use CGI::Pretty; my $q = CGI->new(); my @fields = qw(Hello World); print header(), start_html(), div( @fields ), div( [@fields] ), div( { -id => "div-test" }, div(\@fields) ); print ( start_div({-id=>$_}), end_div() ) foreach @fields; print end_html(); exit 0;

    Prints

    Content-Type: text/html; charset=ISO-8859-1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-U +S"> <head> <title>Untitled Document</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1 +" /> </head> <body> <div> Hello World </div> <div> Hello </div> <div> World </div> <div id="div-test"> <div> Hello </div> <div> World </div> </div> <div id="Hello"> </div> <div id="World"> </div> </body> </html>

    Coyote

Re: Calling functions in middle of CGI HTML declarations
by Your Mother (Canon) on Aug 26, 2012 at 16:52 UTC

    Most (all?) block functions will take an array ref and do what you want–

    use CGI::Pretty ":standard"; my @fields = qw( Adios Amigo ); print div ({ -id => "div-test" }, div( \@fields ) ); __END__ <div id="div-test"> <div> Adios </div> <div> Amigo </div> </div>

    I use this the most in li constructions but it works fine with div, as you can see.

      The functions tend to take arguments on a per element basis. If the function is going to it will generally ask if it is recieveing an array or hash reference first then go on to process the code accordingly.

      The important thing is to provide the method with what it is expecting or is set up to handle. Here it is important to determine to the method it is being provided with an array reference rather than an expanded list. As it will determine whether the list is going to be concatenated and used as content as in the case where the array actual is used and ends up as one chunk in the div, or split into the lists components and then used as content, where the ref is used and creates the individual divs.

      The square brackets provide the method with an anonymous array built from the list provided in the array, whereas the reference to the array provides, a reference to the array. Providing the reference being the more efficient way to move the data through.

      I think that building an anonymous array out of a named array (what I did by adding square brackets)is probably more expensive than needs be, but was a workaround to get the desired result.

      Basically if you provide the array as a reference, the method does the foreach for you. But you have to inspect each method via the docs to determine what each will or wont accept. There can be differnces in output depending on which markup or version you are using and such.

      To note, while hacking through this I noticed that closed div beginning elements were produced which is some effect of the code being processed for xhtml and not html, hence the start_div/end_div in the foreach statement to explicitly inform cgi what I wanted. This also prevented the divs being built recursively within themselves without any closing elements.

        Did you silently update your original reply or did I just completely miss the parts that are similar to mine? If I did miss it, sorry about that.

Re: Calling functions in middle of CGI HTML declarations
by flexvault (Parson) on Aug 26, 2012 at 18:04 UTC

    dr.jekyllandme,

    Since you're learning about CGI, I did a post about a tool here that allows you to keep the Perl code and the HTML files separate. The more I use it, the better I like it.

    My cgi scripts are smaller and faster as a result of this technique.

    I have expanded my use of the hash (%TWORK) so that now I keep all input fields and all calculated results in the same hash. I use 'read' to slurp the file in all at once, and then I call the subroutine once, and then print the output to the web server. You can have someone else(web/graphic designer) edit the HTML file, and your code stays intact.

    Good Luck!

    "Well done is better than well said." - Benjamin Franklin

        You're entitled to your opinion!

        You're not entitled to tell me what my opinion is!

        Thank you!

        "Well done is better than well said." - Benjamin Franklin

Re: Calling functions in middle of CGI HTML declarations
by GrandFather (Cardinal) on Aug 26, 2012 at 22:44 UTC

    As Mr. Muskrat suggests you really should consider using a templating system. I recommend HTML::Template is a fairly easy entry point for this sort of task. Consider:

    #!/usr/bin/perl use strict; use warnings; use HTML::Template qw(); use CGI qw(); my $fName = 'sample.html'; open my $temp, '>', $fName or die "Can't create $fName: $!\n"; print $temp <<'HTML'; <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-U +S"> <head> <title><TMPL_VAR name="title"></title> <meta http-equiv="Content-Type" content="text/html; charset=iso-88 +59-1" /> </head> <body> <div id="<TMPL_VAR name="divname">"> <TMPL_LOOP name="divs"> <div><TMPL_VAR name="div"></div> </TMPL_LOOP></div> </body> </html> HTML close $temp; my $tmpl = HTML::Template->new(filename => $fName); my @fields = qw(Hello Goodbye Friend Adios Amigo); my @loopParams = map {{div => $_}} @fields; print CGI::header(); $tmpl->param(title => "testme"); $tmpl->param(divname => 'div-test'); $tmpl->param(divs => \@loopParams); print $tmpl->output();

    Prints:

    Content-Type: text/html; charset=ISO-8859-1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-U +S"> <head> <title>testme</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-88 +59-1" /> </head> <body> <div id="div-test"> <div>Hello</div> <div>Goodbye</div> <div>Friend</div> <div>Adios</div> <div>Amigo</div> </div> </body> </html>
    True laziness is hard work
Re: Calling functions in middle of CGI HTML declarations
by sundialsvc4 (Monsignor) on Aug 27, 2012 at 00:56 UTC

    Whereas I would chime in for Template::Toolkit, but the essential point is the same:   you should, insofar as possible, clearly separate program logic from presentation.   If When the marketing department says to you, “that looks great, but can you just ... (insert complete page makeover here),” you should be able to do that just by changing a template.   The program logic builds data structures (and provides functions), then the template iterates through them.   “Separation of concerns.”

    Templating systems have considerable power for just this reason.   You can loop through data structures, make decisions, call Perl functions and so-on from within a template.   (Usually, the templating system works by building and compiling a Perl subroutine on-the-fly.)

    Postscript:   This is one of the “lessons learned” of the PHP community ... and a hard lesson it was, because the intrinsic design of PHP is originally was very-specifically to allow logic to be embedded into the HTML.   Today, you won’t find any PHP pro doing that anymore (although plenty of legacy apps do and always will remain).   They all use templates now, and objects, and the language and its user-contributed-source libraries have grown in these directions.   While you may still find books that teach that approach, it is now widely recognized as a poor practice for the reasons aforesaid.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://989811]
Approved by ww
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (7)
As of 2014-07-23 02:51 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (131 votes), past polls