Main Page Content
Separating Asp Code From Html In Templates
Not so long ago, I got introduced to server side scripting for websites. I
really began to enjoy myself. I could create my HTML and go around embedding my neat little <%%> asp tags. Man... it was fun. Then came a time when the client wanted me to change some of the visual design. "Just move this image from over here to there..." That's when my nightmares began.It turned out to be an experience just about as pleasant as piercing needles
through your eyes. Somewhere down the line my embedded ASP got jumbled. Something had to be wrong with what I was doing.I needed a framework that would allow:
- Single point of modification for templates on a site
- Some kind of templating. I didn't want to use templating features of a specific HTML editor, since a lot of the time I end up editing html manually
- Separate ASP from HTML
- Allow reusability.
Some Nuclear Physics
The first part of our technique is basically about breaking up an HTML page
into usable bits, when we need to display it on the website (some HTML Fission).The second part is about rejoining the various bits, when we need to see the
HTML as a whole (some HTML Fusion).Fission
Why do I breakup a decent HTML page into pieces? There are quite a few advantages
to this. For one, most websites have a common look and feel throughout, but when the look does need to change I would like to make it in 1 place. Sometimes only small things need to be changed like a navigation menu moving from the left hand side of the page to the right hand side. And many times the only thing different between look and feel of pages is something technically minor like the banner table being a 3-column table instead of a single column table, I didn't want to maintain a duplicate of the page template just to accommodate stuff likethis.There are additional advantages to this scheme. It's very easy to provide
additional features like "print version" and also hidden/alternate navigation on specific pages.Fissile Material
A typical page layout for my example would look like:
As you can see I have divided the page into manageable tables.
I break up the page further to my convenience by demarcating specific parts
of the page. For example, I mark the starting of the page header into 3 parts in the following way:<!--[_part_start_:000.01.head_beg]--> <html> <head> <title><!--_VAR_TITLE_--></title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"><!--[_part_start_:000.02.head_scr]--><script>function dummy(){return 0;}</script><!--[_part_start_:000.99.head_end]--></head>
As you can see I divided the HTML by using comment tags named in a particular
way:<!--[_part_start_:xxx.xx.section_name]-->
. I used a naming convention as it allows me to later extract specific sections of this file using regular expressions. There are certain advantages to using a naming schema based on comment tags. For one, most HTML editors find them palatable and generally don't screw around with them (though personally Iuse the editor to make the initial layout, after that I hand-edit it...). There is also a comment called <!--_VAR_TITLE_-->
within
<title>
tag. I use many of these _VAR_..._ type of comments in the page and I use them as "display" variables. These are searched and replaced at runtime. For example my ASP page replaces the <!--_VAR_TITLE_-->
tag with the page title and the <!--_VAR_CONTENT_1_-->
with the meat of the content at the time of script execution.Blowin' it up
I have been using windows scripting to automate a lot of stuff on my PC, which
means I use it again to make a script that would break up the HTML. I make use of the powerful JavaScript regexp object to do this. I execute the script on the layout HTML file in which I have also inserted my special comments. The cscript.exe interpreter that comes installed with windows takes care of interpreting and executing theJavaScript. I find windows scripting quite useful when I install ActivePython/Perl. I can even usePython or Perl scripts in it.I execute my script on the HTML file using a command line syntax similar to
this:d:\files>cscript tools.wsf //job:SplitHtml file.html input_folder
Incidentally the .wsf script file is called a package file and can contain
scripts for multiple tasks (or <job> as Microsoft documentation calls it), so the SplitHtml is a job in the wsf file. The SplitHtml job executes on the html file and creates multiple text files. The text files are named using the tag we defined the section to be e.g.:For a section that was marked as:
<!--[_part_start_:000.01.head_beg]-->
the HTML code in the section denoted by this comment tag gets extracted to a file called 000.01.head_beg.txt.
The SplitHtml script uses regular expression matching to extract the specific
_part_start_ sections of the HTML page. The regular expression was defined in Javascript as:re=new RegExp("\<\!--\\[_part_start_:([0-9]{3}.[0-9]{2}.[A-Za-z_]+)\\]--\>","g");
The script creates files for every such designated section.
I used a naming scheme for the comment tags, which ensures that the generated
text files maintain the same sequence as the section dividing comments. Additionally the naming scheme allows me to add a new section comment without changing or disrupting the existing sequence. For instance if I needed to add some new HTML code between 000.02.head_scr and 000.99.head_end (head_end marks the</head>
tag..) sections, I can insert up to95 individual parts in between by naming them as 000.03.tag1, 000.04.tag2.....When I sort the files in Windows Explorer by name, they are in exactly the same sequence as the _part_start_ comments were in the originating HTML file. Maybe a better method of maintaining the sequence, would be to store the individual
splits in a database table. Well, this works for me so I use it.My ASP page scripts read the split parts sequentially (discussed later below)
and renders the page.When I want to see the page as a single HTML file, I again use a windows script
called BuildHtml that rebuilds the HTML file from the parts text files. This job uses a very similar syntax to the SplitHtml method. I can also now use any HTML editor to edit the page layout.All the source code for SplitHtml & BuildHtml with a couple of other script
functions to query display tags & variable tags in a HTML file can be downloaded from:source.zip
Fusion
We use some ASP fusion to create our dynamically generated page out of all
the pieces we divided our HTML page into. Let's start with the basics. If my ASP page is called display.asp, I have a corresponding definition file for it called def.display.asp .Defining The Ingredients
The definition file defines the sequence in which the individual HTML section
files (the text files we just created) should be looked up & allows defining of a condition for looking up the section. This file is included at the beginning of every ASP file it defines the structure. For instance when display.asp is executed, the def.display.asp is first executed and a String variable is built which contains the HTML code for the page.The def.display.asp file would look something like this:
<%/**************************Section 1 -- HTML Lookups ***************************//*now we being lookup the html sections *//*this should always be shown..*//*Settings for this page*//* Header section */ HtmlLookup("000.01.head_beg",true); HtmlLookup("000.02.head_scr",true); HtmlLookup("000.99.head_end",true); /* Banner section */ HtmlLookup("001.00.body",true); HtmlLookup("001.01.banner",printable()); HtmlLookup("001.02.horiz_nav",printable()); /* Page Vertical Navigation */ HtmlLookup("002.01.main_tbl_begin",true); HtmlLookup("002.02.vertical_nav_beg",true); HtmlLookup("002.03.vertical_nav",printable()); HtmlLookup("002.04.vertical_nav_end",true); HtmlLookup("002.05.content_begin",true); HtmlLookup("002.08.content_end",true); HtmlLookup("002.09.main_tbl_end",true); HtmlLookup("003.01.footer",true); HtmlLookup("009.99.end_page",true);%>
The HtmlLookup function takes the section name as the 1st parameter (this happens
to be the primary name for the text file) and a 2nd parameter which can be used to conditionally display the section. For instance, in the sample with this article I hide a part of the navigation when the page is being viewed in printable mode (I set a page to printable mode by passing a query string parameter).The multiple calls to HTMLLookup builds a string variable with the HTML code for the page. Based on the section name that has been passed the lookup function opens the corresponding .txt file and builds up the HTML.
Concocting the page for the final output
Now to the structure of our main ASP file display.asp . This page has a few
SSI includes, and importantly this is where our main code to pick up the content from a database would reside. The specific content is then updated into the specific comment _VAR_iables I described earlier. I have a helper function called HtmlTransform which takes the _VAR_ variable name as the 1st parameter and the actual content to be displayed in place of that variable as a string parameter.In the HtmlTransform function I search and replace every instance of the comment
variable with the content string. Which means that I could have _VAR_TITLE_ or any other display tage appearing more than once. My search & replace function would appear as: replace(strHtml, "\<\!--"+strVariable+"--\>",
where strVariable is anything like (_VAR_TITLE_, _VAR_CONTENT_1_ etc.), (the
replace function is some code taken from one of the gazillion javascript sites...)There is an additional advantage to using a _VAR_ style of variable. For instance
if my vertical navigation menu bar (typically on the left or hand side of a page) is not to appear on the print version or a hidden navigation version of the page, I can save the overhead of a lookup to the database for that information (This would be relevant if the menu navigation or any of the display element which is to be hidden in a print version is picked up from a database), by simply checking if the _VAR_ variable for the menu exists in my HTML string. Something like:if (getHtml().indexOf("<!--_VAR_LEFTMENU_-->") != -1) //only if the HTML string contains a leftmenu display //variable pickup the content for it{ strVertMenuOut = LookupFromDatabase(); }
So my display.asp script would look something like this:
<%@ LANGUAGE=JScript%><!--common ssis--><!--#include file="inc/globvars.asp"--><!--#include file="inc/funcs.asp"--><!--#include file="inc/setprintable.asp"--><!--end common includes--><!--page defintion ssi--><!--#include file="def.display.asp"--><% /* Section 2 -- HTML Transforms */ //Code to fetch content from database //Code to fetch stuff like page title etc. var strContent1; var strContent2; //here we just fill with dummy info strContent1 = "<h2>My Content1</h2>"; strContent2 = "<h2>My Content2</h2>"; //Code to fetch Navigation menus etc. //..... //again I fill up some dummy links for my vertical menu strVertNav = "<br><a href=\"http://dir.evolt.org\"> Evolt directory</a><br><a href=\"http://browsers.evolt.org\">Evolt Browsers</a>"; //.... //.....//begin transforms
HtmlTransform("_VAR_TITLE_", "HTML Templating sample code"); HtmlTransform("_VAR_CONTENT_1_", strContent1); HtmlTransform("_VAR_CONTENT_2_", strContent2); HtmlTransform("_VAR_VERT_NAV_", strVertNav);%> <!--output page html here--> <%=getHtml()%><!--page end-->
Main advantages of this method
- Separation of HTML from ASP code
- Splitting of page HTML increases flexibility & makes changes easier
- Makes creation of print versions, alternate navigations easier
- Easy to adapt to other non-asp languages (hopefully!)
Some drawbacks of this method
- The method is very much dependent on a proper sequential naming scheme for named _part_ comments (I maintain a sequential documented list of _part_ and _VAR_ comments in an excel sheet just for my reference)
- Additional Scripts like SplitHtml & BuildHtml need to be used to view the HTML file as a whole when required (and this is dependent on a proper naming scheme)
- There might be a higher performance overhead since all the HTML is looked up and filled in a string and then the named comments replaced
Sample code
All the sample ASP & WSF script code with sample files can downloaded
from:source.zip
Related links
I found some similar methods & ideas discussed at:
These are a couple of sites on Windows Scripting that I have found useful:
WinScripter.com
Ian Morrish's site on Windows scripting
Just as I was posting this article, I saw this nice article on regex by sprocket:
Regular Expression basics