📄 ch05_04.htm
字号:
<?label 5.4. Alternatives for Generating Output?><html><head><title>Alternatives for Generating Output (CGI Programming with Perl)</title><link href="../style/style1.css" type="text/css" rel="stylesheet" /><meta name="DC.Creator" content="Scott Guelich, Gunther Birznieks and Shishir Gundavaram" /><meta scheme="MIME" content="text/xml" name="DC.Format" /><meta content="en-US" name="DC.Language" /><meta content="O'Reilly & Associates, Inc." name="DC.Publisher" /><meta scheme="ISBN" name="DC.Source" content="1565924193L" /><meta name="DC.Subject.Keyword" content="stuff" /><meta name="DC.Title" content="CGI Programming with Perl" /><meta content="Text.Monograph" name="DC.Type" /></head><body bgcolor="#ffffff"><img src="gifs/smbanner.gif" alt="Book Home" usemap="#banner-map" border="0" /><map name="banner-map"><area alt="CGI Programming with Perl" href="index.htm" coords="0,0,466,65" shape="rect" /><area alt="Search this book" href="jobjects/fsearch.htm" coords="467,0,514,18" shape="rect" /></map><div class="navbar"><table border="0" width="515"><tr><td width="172" valign="top" align="left"><a href="ch05_03.htm"><img src="../gifs/txtpreva.gif" alt="Previous" border="0" /></a></td><td width="171" valign="top" align="center"><a href="index.htm">CGI Programming with Perl</a></td><td width="172" valign="top" align="right"><a href="ch05_05.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0" /></a></td></tr></table></div><hr align="left" width="515" /><h2 class="sect1">5.4. Alternatives for Generating Output</h2><p>There are <a name="INDEX-1166" /> <a name="INDEX-1,167" /> <a name="INDEX-1,168" />many different ways that peopleoutput HTML from their CGI scripts. We have just looked at how you dothis from CGI.pm, and in the next chapter we will look at how we canuse HTML templates to keep the HTML separate from the code. However,let's look here at a couple of other techniques developers useto output HTML from their scripts.</p><p>One thing to keep in mind as we look at these techniques is howdifficult the HTML is to maintain. Over the lifetime of a CGIapplication, it is often the HTML that changes the most. Thus much ofthe maintenance of the application will involve making changes to thedesign or wording found in the HTML, so the HTML should be easy toedit.</p><a name="ch05-25-fm2xml" /><div class="sect2"><h3 class="sect2">5.4.1. Lots of print Statements</h3><p>The simplest solution for including HTML in the source code is thehardest to maintain. Many web developers start out writing CGIscripts that contain numerous<tt class="function">print</tt><a name="INDEX-1169" /> statements to return documents, even forlarge sections of static content -- content that remains the sameeach time the CGI script is called.</p><p>Here is an example:</p><blockquote><pre class="code">#!/usr/bin/perl -wTuse strict;my $timestamp = localtime;print "Content-type: text/html\n\n";print "<html>\n";print "<head>\n";print "<title>The Time</title>\n";print "</head>\n";print "<body bgcolor=\"#ffffff\">\n";print "<h2>Current Time</h2>\n";print "<hr>\n";print "<p>The current time according to this system is: \n";print "<b>$timestamp</b>\n";print "</p>\n";print "</body>\n";print "</html>\n";</pre></blockquote><p>This is a pretty basic example, but you could imagine just howcomplicated this can get on a large web page with numerous graphics,nested tables, style declarations, etc. Not only is this difficult toread because of the extra noise that each <tt class="function">print</tt>statement adds, but each <a name="INDEX-1170" /> <a name="INDEX-1,171" /><a name="INDEX-1172" /> <a name="INDEX-1,173" />double quote in the HTML must be escapedwith a backslash. If you forget to do this even once, you will likelygenerate a syntax error. Making HTML edits to something that lookslike this is much more work than it should be. You should definitelyavoid this approach in your scripts.</p></div><a name="ch05-26-fm2xml" /><div class="sect2"><h3 class="sect2">5.4.2. Here Documents</h3><p>As we have seen in earlier examples, Perl supports a feature called<em class="firstterm">here documents</em><a name="INDEX-1174" /><a name="INDEX-1175" />that allows you to express a large block of content separately withinyour code. To create a here document, simply use<tt class="literal"><<</tt> followed by the<a name="INDEX-1176" />token that will be used to indicatethe end of the here document. You can include the token in single ordouble <a name="INDEX-1177" />quotes, and thecontent will be evaluated as if it were a string within those quotes.In other words, if you use single quotes, variables will not beinterpreted. If you omit the quotes, it acts as though you had useddouble quotes.</p><p>Here is the previous example using a here document instead:</p><blockquote><pre class="code">#!/usr/bin/perl -wTuse strict;use CGI;my $timestamp = localtime;print <<END_OF_MESSAGE;Content-type: text/html<html> <head> <title>The Time</title> </head> <body bgcolor="#ffffff"> <h2>Current Time</h2> <hr> <p>The current time according to this system is: <b>$timestamp</b></p> </body></html>END_OF_MESSAGE</pre></blockquote><p>This is much cleaner than using lots of <tt class="function">print</tt>statements, and it allows us to indent the HTML content. The resultis that this is much easier to read and to update. You could haveaccomplished something similar by using one<tt class="function">print</tt> statement and putting all the contentinside one pair of double quotes, but then you would have had toprecede each double quote in the HTML with a backslash, and forcomplicated HTML documents this could get tedious.</p><p>Another solution is to use <a name="INDEX-1178" /><a name="INDEX-1179" /><a name="INDEX-1180" />Perl's <tt class="literal">qq//</tt>operator, but with a different delimiter, such as<tt class="literal">~</tt>. You must find a<a name="INDEX-1181" />delimiter that will not appear in theHTML, and remember that if your content includes JavaScript, it caninclude many characters that HTML might otherwise not.<em class="filename">here</em> documents are generally a safer solution.</p><p>One drawback to using <em class="emphasis">here</em> documents is thatthey do not <a name="INDEX-1182" />easily indent, so they may lookodd inside blocks of otherwise cleanly indented code. TomChristiansen and Nathan Torkington address this issue in the<em class="citetitle">Perl Cookbook</em> (O'Reilly & Associates,Inc.). The following solutions are adapted from theirdiscussion.</p><p>If you do not care about extra leading whitespace in your HTMLoutput, you can simply indent everything. You can also indent theending token if you use<a name="INDEX-1183" />quotes and includethe indent in the name (although this is more readable, it may beless maintainable because if the indentation changes, then you mustadjust the name of the token to match):</p><blockquote><pre class="code">#!/usr/bin/perl -wTuse strict;use CGI;my $timestamp = localtime;display_document( $timestamp );sub display_document { my $timestamp = shift; print <<" END_OF_MESSAGE"; Content-type: text/html <html> <head> <title>The Time</title> </head> <body bgcolor="#ffffff"> <h2>Current Time</h2> <hr> <p>The current time according to this system is: <b>$timestamp</b></p> </body> </html> END_OF_MESSAGE}</pre></blockquote><p>One problem with indenting HTML <em class="emphasis">here</em> documentsis that the extra indentation is sent to the client. You can solvethis problem by creating a function that "unindents" yourtext. If you wish to <a name="INDEX-1184" />remove all indentation, this issimple; if you want to maintain your HTML's indentation, thisis more complex. The challenge is determining the amount ofindentation to remove: what portion belongs to the content and whatpart is incidental to your script? You could assume the first linecontains the smallest indent, but this would not work if you wereonly printing the end of an HTML document, for example, when the lastline would probably contain the smallest indent.</p><p>In the following code the<tt class="function">unindent</tt><a name="INDEX-1185" /> subroutine looks at all of thelines being printed, finds the smallest indent, and removes thatamount from all of the lines:</p><blockquote><pre class="code">sub unindent;sub display_document { my $timestamp = shift; print unindent <<" END_OF_MESSAGE"; Content-type: text/html <html> <head> <title>The Time</title> </head> <body bgcolor="#ffffff"> <h2>Current Time</h2> <hr> <p>The current time according to this system is: <b>$timestamp</b></p> </body> </html> END_OF_MESSAGE}sub unindent { local $_ = shift; my( $indent ) = sort /^([ \t]*)\S/gm; s/^$indent//gm; return $_;}</pre></blockquote><p>Predeclaring the <tt class="function">unindent</tt> function, as we do onthe first line, allows us to omit parentheses when we use it. Thissolution, of course, increases the amount of work the server must dofor each request, so it would not be appropriate on a heavily usedserver. Also keep in mind that each additional space increases thenumber of bytes you must transfer and the user must download, so youmay actually want to strip all leading whitespace instead. After all,users probably care more about the page downloading faster than howit looks if they view the source code.</p><p>Overall, <em class="emphasis">here</em> documents are not a bad solutionfor large chunks of code, but they do not offer CGI.pm'sadvantages, especially the ability to have your<a name="INDEX-1186" />HTML code verified syntactically.It's much harder to forget to close an HTML tag with CGI.pmthan it is with a here document. Also, many times you must build HTMLprogrammatically. For example, you may read records from a databaseand add a row to a table for each record. In these cases, when youare working with small chunks of HTML, CGI.pm is much easier to workwith than here documents.</p><p>Using CGI.pm's methods for outputting HTML generates strongreactions in developers. Some love it; others don't.Don't worry if it doesn't match your needs, we will lookat a whole class of <a name="INDEX-1187" /> <a name="INDEX-1,188" />alternatives in thenext <a name="INDEX-1189" /><a name="INDEX-1190" /><a name="INDEX-1191" />chapter.</p></div><hr align="left" width="515" /><div class="navbar"><table border="0" width="515"><tr><td width="172" valign="top" align="left"><a href="ch05_03.htm"><img src="../gifs/txtpreva.gif" alt="Previous" border="0" /></a></td><td width="171" valign="top" align="center"><a href="index.htm"><img src="../gifs/txthome.gif" alt="Home" border="0" /></a></td><td width="172" valign="top" align="right"><a href="ch05_05.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0" /></a></td></tr><tr><td width="172" valign="top" align="left">5.3. Generating Output with CGI.pm</td><td width="171" valign="top" align="center"><a href="index/index.htm"><img src="../gifs/index.gif" alt="Book Index" border="0" /></a></td><td width="172" valign="top" align="right">5.5. Handling Errors</td></tr></table></div><hr align="left" width="515" /><img src="../gifs/navbar.gif" alt="Library Navigation Links" usemap="#library-map" border="0" /><p><font size="-1"><a href="copyrght.htm">Copyright © 2001</a> O'Reilly & Associates. All rights reserved.</font></p><map name="library-map"><area href="../index.htm" coords="1,1,83,102" shape="rect" /><area href="../lnut/index.htm" coords="81,0,152,95" shape="rect" /><area href="../run/index.htm" coords="172,2,252,105" shape="rect" /><area href="../apache/index.htm" coords="238,2,334,95" shape="rect" /><area href="../sql/index.htm" coords="336,0,412,104" shape="rect" /><area href="../dbi/index.htm" coords="415,0,507,101" shape="rect" /><area href="../cgi/index.htm" coords="511,0,601,99" shape="rect" /></map></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -