Background
Recently I've been forced to write a lot of fairly complex ASP code to interact
with a database and present stuff on a nicely formatted web page. As you all know
it is no fun working with HTML and ASP code jumbled together in a single file. Once you
have to either change the code logic or redo the layout it is even less fun. So I went
searching for some solution to this problem.
I found a bunch of different systems, both free and commercial, but none that did
precisely what I wanted, so I decided to roll my own template processor. And with
the help of the RegEx
object available in IIS 5.0 or better, this is
what I came up with:
Details
The guy that runs the show is a VBScript class called ASPTemplate
.
From now on you'll use two files for each web page: One that contains only code, and
one that is pure HTML.
The ASPTemplate
class exposes two mechanisms you'll use
to enter dynamic data in the HTML template: Slots
and Blocks
.
A Slot
is a property and works just like a variable that renders the value you assign to it in the
ASP file.
You put a slot name between double braces (like this {{Name}}) when you
use them in the HTML template.
A Block
is a piece of HTML that can be shown or hidden from the ASP
code using the ShowBlock
method.
What makes Blocks
truly useful is that they can be repeted using the
RepeatBlock
method. Whenever you call this method the block
contents is repeated using the slot values that are current at that moment. In this way
you can fill a table with database information easily and conveniently.
But wait, there is more! Blocks
can also be nested to an arbitrary depth (though
the processing time tends to increase a lot when you nest deeply), allowing you
to create very complex structures with a minimum of code.
How to use ASPTemplate
A little example will probably make this clear. As stated above, you'll use two files for each page. Here is the first one:
File Test.asp
This is the code file, or the driver file if you like. As you can see, the first thing to do
is to include the ASPTemplate.asp file and create an instance of the
ASPTemplate
object. We then tell the object what HTML template
to use. In this case it is loaded from the default directory Templates/. You
can change this with the TemplateDir
property if you like.
The rest is just to fill the nested structures with some varying data so you can see
it actually does something. Note that you can control the Blocks
One
and
Two
with QueryString
parameters like so: test.asp?Block=One.
All Blocks
are hidden by default and shown with ShowBlock
or RepeatBlock
. The call to ClearBlock
before the
loop that fills a nested block is needed to remove the contents from the previous loop.
<!---->
<script language="VBScript" runat="Server">
dim t : set t = new ASPTemplate
t.Debug = false
t.Template = "test.html"
t.Slot("Title") = "This is a test"
t.Slot("Now") = Now()
t.Slot("Title") = t.Slot("Title") + " - and some more"
t.Slot("Test") = "Test text"
for i = 1 to 8
t.Slot("Cell1") = i
if t.Slot("Cell1") > 5 then t.Slot("Test") = t.Slot("Test") + " ..."
t.ClearBlock "Block1"
for j = 1 to i
t.Slot("Cell2") = i*j
t.ClearBlock "Block2"
for k = 1 to i-j+1
t.ClearBlock "Block3"
for l = 1 to 3
t.Slot("Cell3") = k+j*l+t.Slot("Cell2")
t.RepeatBlock "Block3"
next
t.RepeatBlock "Block2"
next
t.RepeatBlock "Block1"
next
t.RepeatBlock "TBody"
next
for each block in Request.QueryString("Block")
t.ShowBlock block, true
next
t.Generate
set t = nothing
</script>
File test.html
And this is what a template file looks like. The important thing with the code/template
dichotomy is that the template file can be formatted using a wysiwyg-editor without
the need to switch to code view.
Well, that might not be entirely accurate, since the block markers needs to be expressed
as HTML comments since they tend to appear in places where it is not valid to put text or
normal HTML tags. But most wysiwyg editors can show the comments as a symbol or
something, so the layout person can still see where they are.
Another nice thing with ASPTemplate
, not shown in the demo, is that
you could switch to an entirely different template from the .asp file, depending
on some condition or parameter, and, as long as the other template uses the same slots
and block structure, no changes to the ASP code are needed. Isn't that neat?
<html>
<head>
<title>{{Title}}</title>
</head>
<body>
<p>This is a test. Here is the title <b>{{Title}}</b></p>
<p>This is now: {{Now}}</p>
<p>This is unused {{Nada}} more text.</p>
<!----><p>This is block <b>One</b></p><!---->
<!----><p>This is block <b>Two</b></p><!---->
<table border="1">
<tr>
<th width="70">Col 1</th>
<th>Col 2</th>
</tr>
<!---->
<tr>
<td align="center">{{Cell1}}</td>
<td>
<table border="1">
<!---->
<tr>
<td valign="top">{{Cell2}}</td>
<td><font size="2">
<!---->
<i>{{Test}}</i>
<!---->
{{Cell3}}!
<!---->
<!---->
</font>
</td>
</tr>
<!---->
</table>
</td>
</tr>
<!---->
</table>
</body>
</html>
The nitty gritty stuff
The code for the ASPTemplate
relies heavily on the regular
expression object introduced in IIS 5.0. One slight problem with the RegEx object is that
the catch-all .*
doesn't match newlines. I first used (\n|.)*
to solve this, which worked fine, but very slowly. So I instead switched to replacing all
newlines with a single space as soon as I read in the template file. This made subsequent
processing much faster.
I used a compact coding style and not many comments in the ASPTemplate.asp
file to keep the file size small, but it should still not be too hard to figure out how it works.
Caveat
I have been asked about the performance of this class. As all template processors it will slow things down - by how much depends on how you use it. I have not done any real benchmarking on the code compared to a pure ASP approach. It has performed well enough for my needs so far, although I will probably not recommend it's use in any high traffic web sites. Still, if you'd like to try, be my guest.
History
6/3 2002 |
First version released to the world. |
27/3 2002 |
Changed the Slot to use properties instead of methods. This saves variables in the code since you can use a Slot just like a normal variable. Also changed ShowBlock to do both showing and hiding depending on a boolean parameter. |
Direct all questions and comments to Sven Axelsson
(svenax@bredband.net).