Separating HTML from server-side scripting

Over the last couple of years I’ve learned to separate HTML content, CSS presentation, and JavaScript behavior into separate files that link on download. Keeping them apart has helped my web design work become cleaner, faster to code, and much easier to maintain, modularize, and clone.

However, too many of my ASP server-side scripts that generate HTML have remained messes of HTML tag fragments tangled in the vines of scripting logic:

<li><%
	if sHref(i) <> "" then
		%><a href="<% =sHref(i) %>"><%
	end if
%><% =aMenuItems(i) %><%
	if sHref(i) <> "" then
		%></a><%
	end if
%></li>

Ugly and inelegant, difficult to read, awful to maintain. Having to change either the logic or the markup meant fighting through that brambly marsh.

Wouldn’t it be great if they existed in different rooms? No more counting quotation marks and angle-brackets!

Is it possible to keep all HTML markup in one file and all logic and database access in a separate script and still generate satisfyingly dynamic pages?

The route I’m taking currently is to save an HTML file on the server as a plain text file, e.g. about.txt. When the corresponding web page about.asp is requested, my ASP script opens the text file and merges it with content generated from server-side logic and databases, delivering the result down to the client.

The technique I’m using to merge static HTML with dynamic content relies primarily on element ids and classes, the same as CSS and javascript. For example, the script can search for an element with a given id and insert generated content before its closing tag:

<h1 id="pagetitle"></h1>

becomes:

<h1 id="pagetitle">Aarvarks in Space</h1>

Sometimes I plant keywords in the HTML that the script can search for and replace:

<p>Welcome to [SITETITLE]</p>

(Admittedly, augmenting HTML markup with special codes that exist purely for the benefit of the server-side script veers dangerously back in the direction of mixed script & HTML, but it’s a compromise I feel quite comfortable with at this time.)

(One coding caveat: Microsoft’s VBscript, the dialect of Visual Basic that powers ASP pages, has a gawdawful replace function that eats memory like candy. Apparently, each time it executes a replacement, it copies the entire string in memory and doesn’t clean up behind it. Prolific use of global replacement in a script can cost heavily in server memory and CPU cycles. I don’t imagine this is a problem with PHP.)

Inserting and replacing works well enough for simple applications, but server-side scripts don’t just provide variable content within fixed tags, they also determine whether certain elements should exist in the markup at all. Fortunately it’s easy enough for the server-side script to search for elements with specific ids and delete them from the markup before downloading to the client. To work well, a search-&-delete operation must be able to parse HTML confidently, counting start-tags and end-tags to make sure that an entire element is deleted with all of the child nodes it contains.

It’s also possible to generate CSS on the fly to suppress selected elements from display. However, in the case of security layers, when a logged-on user will be served page elements that an anonymous user will not, it’s important to eliminate the secure elements from the page completely and not merely suppress them from display with CSS.

Another common function of scripted output is to generate a series of list items or paragraphs from an array or a table of values whose size cannot be predicted:

do until cms.eof
   InsertListItem cms("NavMenuItem"), cms("NavMenuLink")
   cms.MoveNext
loop

Typically and notoriously, the subroutine InsertListItem() will consist of something ugly like:

sub InsertListItem(argText, argLink)
	Response.Write "<li><a href=""" & argLink & """>" & argText & "</a></li>"
end sub

In separating HTML from scripting logic, how do you mark up static HTML to accommodate a variable number of iterations? One approach is to construct templates for duplication:

<ul id="navmenu">
	<li><a href="[HREF]">[TEXT]</a></li>
</ul>

The scripting logic locates the element with id=navmenu and uses its inner HTML — in this case the list item — as a template for generating any number of siblings, here replacing the pseudotags [HREF] and [TEXT] with variable values. The same method can be used to generate table rows, paragraphs of text, and other iterative series.

Have you been thinking about these issues? If so, I’d like to hear from you.

– Paul Novitski