-----Original Message----- From: owner-cgi-list@jann.com [mailto:owner-cgi-list@jann.com]On Behalf Of Lucenius, Jon (FUSA) Sent: Friday, November 16, 2001 12:28 PM To: 'Vuillemot, Ward W'; 'Mike Gossland'; cgi-list@jann.com Subject: RE: [CGI] RE: [CGI] Using <%...%> I use [....] for a few reasons. <%...%> are tags in a few languages already. I do want my tags to show up on a page if I miss them, in which case they are bolded and in red. I would think that if I missed a commented tag like the ones below and it was optional, I would have a hard time finding it. The syntax used below is very similiar to using custom JSP tags syntaxwise. HTH and HAND, Jon You could check out my module called Template::Parser.pm It let's you choose the tags you use for the embedded tokens in all your template files. It is found in the Perl archives I host at my website: http://www.atrixnet.com/cgi-bin/archive.pl/pub/modules/Template/Parser.pm To see a complete example of how this works, take a look at my archives in the following directory: http://www.atrixnet.com/cgi-bin/archive.pl/pub/examples/Template/parser/ Use your browser function which lets you right click on a link and 'save target as' in order to get a hold of the template files. Otherwise, IE thinks they are un-parseable XML files and won't render them for you. You'll get an error message from Bill Gates instead. Taking a look at that code in addition to the template files it uses will give you a better idea how to use it. You'll have to visit the archives if you want to know how to build your template files for the parser because I can't attatch any templates to the email per Jann's list rules. For a quick run down, Template::Parser works something like this: # use template parser module use Template::Parser; # make a customized template parser object # that uses your own opening and closing tags # for the embedded tokens you put in your templates. # make your tags like PHP, ASP, JSP, or SSI, or # whatever you like. The open and closing tags # don't have to match if you don't want them to. my($parser) = Template::Parser-> new ( 'config' => { {'open token tag'} => ' '?>', } ); # load up the main template used to house parsed output my($template) = $main->{'DIR'}{'templates'}.'/page_template.html'; # specify the directory where html object templates are located. # one may use the files to create html objects such as tables, charts # formatted DB listings, auto-generated forms, etc. To create these # html objects, you have to make the header, body, and footer for each # thing you build. When you want to get a new row in your calendar, # a new cell in your table, a new point on your chart... you just # loop through the listings of whatever values you want to display in # the html object (table, chart, calendar, form, whatever...) and in # each iteration of your loop you parse the body template, adding its # parsed output onto the end of the html object you are creating. # When the loop is exausted, you just parse the header and footer # cat them onto the top and bottom ends of the object you just made. # html objects can be nested indefinitely. Once all your page's # dynamic parts have been created, you name them and finally stick # them all into their respective places in your main template. # let's take a look at a simple example: # load up the object template files to create a table # to dynamically show the contents of a directory on the server # we use the convention of storing all the object template files # in a directory named with the same name as the object you are # going to create and then embed into your template. # first we specify the directory name which contains the object # files. Then we use a function which loads them all up into # memory as strings that get stored into a hash as key->value # pairs, the keys are the names of your object template files # minus the file suffix. The values are the strings we created # from the content of each file. Of course, those files are # made up of html tags with parseable tokens inside. Instead # of opening and closing them each time we iterate over the # list of directory contents which we want to display in our # table. # here's the directory path where we put have put header.html, # body.html, and footer.html for the directory listings object my($object_directory) = $main->{'DIR'}{'objects'}.'/dir_obj'; # this $layout variable becomes the hash, accessed by reference, # containing the object components that get loaded into memory when # read from their files. Keep in mind that by default, this load_object # method will load up all of the files in the directory name you pass # to it. That's why it is a good idea to keep your object templates in # their own directory, or in other words one directory per object # header-body-footer set. Whatever you want those objects to be called # in your main template tokens, name the object directories accordingly. # an example might be: /home/tommy/chart_obj, /home/tommy/dir_obj, etc. my($layout) = $parser->load_object( $object_directory ); # now start saving the information we want the parser to have access # to. We use a simple method that lets us easily set the names and # values of each token we want to create. Tokens are implemented as # hashes containing the token names and token values, where the hash # is referenced by the name you give it -- usually the name you give # the html object you're creating. # now we'll start creating token name->value pairs for the parser # to stuff into the template strings we loop over. In this case, we # save the directory name for the template parser which contains the # files we want to display in our formatted table. $parser-> set_object ( 'name' => 'dir_obj', # this is the name we give to then # main token object used by parser 'param' => 'directory_name', # a single token object name 'value' => $dir, # a single token object value ); # once we are satisfied that we have set enough name->value pairs for the # parser to see during its scans, we can begin the scanning of our templates # get the directory listings we want to show in our table, # and save the names of each file in an array that we'll loop # over with the parser... # note that I'm reading the directory contents here with the # Futils.pm module I used in the example of OO code posted yesterday # the list_dir_a method returns a list of all the files in the directory # name you specify, but each listing it sends back to you is a hash # (accessed by reference) containing all of the individual file's # attributes: Last Modified, Created, Content-Type, Size, etc. # We use this method here because we want to make all of that information # available to the parser when it scans over the object body template # for each file item in our directory listing. @dirlist = $futils->list_dir_a( $main->{'DIR'}{'archives'}.qq[/$dir] ); # now we get to start looping over the list of file contents we just # retrieved. foreach $file (@dirlist) { # once inside our loop, we can still set more # token name->value pairs. This time, we can # make a new token object, that contains as its # name->value pairs all of the file listings hash # key->value pairs. You see, when you pass a full # hash of name->value pairs to the parser, it sets # up each name and its corresponding value in the # token object for parsing. $parser->set_object( 'name' => 'file', 'value' => $file, ); # start creating the html object by concatenating # the parsed output of each template into a seperate # hash entry in our $layout hash. We'll retrieve all # of the parsed output from that hash entry when we're # done parsing... $layout->{'tmp'} .= $parser->parse( $layout->{'body'} ); } # OK, now that we're done parsing all of the object template files # for each file item in the directory listing we stored in @dirlist, # its time to retrieve the parsed output for the html object we made. # Then we'll stick on the header and footer. # But just in case we didn't get any parsed output because the directory # was empty, and the @dirlist array had no file items to loop over, we'll # check to see if any special action needs to be taken. Otherwise, we'll # proceed with the default action of setting up the parsed output into # another name->value pair in our main dir_obj token that was created at # the point of our script right before we started parsing over the directory # items. # if there was some parsed output, sandwich it between the header # and footer, which get parsed now as well. The header might contain # a token value for the 'directory_name' entry we stuffed into the main # 'dir_object' when we first made it. if ($layout->{'tmp'}) { $parser->set_object ( 'name' => 'dir_obj', 'param' => 'formatted_output' 'value' => $parser->parse( $layout->{'header'} ). $layout->{'tmp'}. $parser->parse( $layout->{'footer'} ) ); } # if there was not some parsed output, we can't sandwich it between the # header and footer, but we'll still parsed anyway now. The header would # still contain a token value for the 'directory_name' entry we stuffed # into the main 'dir_object' when we first made it, but instead of stuffing # an empty block of parsed output, we'll parse over a file called # 'empty.html' which we also created and put into our object directory in # the event that the object we created from those templates was empty. # This way we can handle that situation by providing an appropriate error # message like one of the following: # # 'there were no files in the archive directory' # # 'the listings are unavailable at this time, check back later' # # 'there were no entries in our database which matched your query' # else { $parser->set_object ( 'name' => 'dir', 'param' => 'formatted_output', 'value' => $parser->parse( $layout->{'header'}. $layout->{'empty'}. $layout->{'footer'} ) ); } # cool! now we're done making the directory listings object, so we'll stuff # it into the main page template and our dynamic page will be complete: print($cgi->header()); print($parser->parse_file( $template )); Tommy Butler Internet Strategies, Inc. Everything is Possible web http://www.istrat.com email mailto:tommy@istrat.com tel 214·393·1000 ext 207 fax 800·307·8105 2200 North Lamar, Suite 307 Dallas, TX 75202