This particular monster was 3,000 lines of VBScript and HTML, not counting includes. There were nested loops; arrays, stored procedures and embedded SQL pulling related data from seven different tables. It was basically a collection of bad habits from multiple developers aged to perfection. This page wasn’t designed, it just happened. A rewrite was desperately needed to improve manageability before any other changes could be considered.
Because ADO recordsets can be saved as XML, initially creating the XML is not only easier than the old method of building arrays, it’s faster. However, problems arose due to the relationships of the various tables. For example, comment table rows can exist for both the order header and the order line items. Unfortunately, merging XML documents using XSLT isn't always a simple matter.
Existing merging methods
The first, and easiest, method to merge XML documents using XSL is to "concatenate" the documents programmatically, as shown in Listing A. A root node is first created, and then clones of the two documents are attached as children of that root. XSLT is then used to rearrange the nodes to the desired layout. Listing B shows an example of how this method of merging is accomplished.
The other accepted methods of merging XML documents is to use either the xsl:import tag or the document() function. The problem with these methods is that because of the way the tag and the function works one of the XML documents needs to be written to a temporary file, which is then read as input. In my opinion, anytime that a file is written to the server there's a lot of overhead. Also, security is another potential issue due to having folder write permission enabled.
Because of the number of XML documents that needed merging and my religious reasons against the use of temporary files on a Web server, I decided to try a different method of merging XML documents. Instead of the concatenate method shown above, a single XML document would serve as the starting point for the merge. Each of the other XML documents would be passed as parameters to the XSLT since XML is essentially text-based.
Listing C contains the XSLT, and Listing D shows how the XSLT is applied in ASP.
The extension function getNode() accepts two or more parameters; the first parameter is the string representation of the XML document, while the other parameters are the nodes' tags to return in the document fragment. The result is shown in Listing E.
The getNode() function helped a lot in increasing the manageability of the “Monster”. It would have fit in all situations, but customers are an unreasonable group—they have a tendency to place orders for more than one item at a time. Customers really don’t have any respect for elegant code; they don’t care about elegant code; and they would rather have code that works in all situations. Customers really have some nerve!
What I needed was a way to merge XML documents on a row-by-row basis. The result was the mergeDocuments() extension function shown in Listing F. The mergeDocuments() function accepts three parameters. The first two parameters are the string representations of XML documents to be merged; and the third is the node to compare. The first document serves as the primary document and is always returned by the function. The second document is then matched to the first document based upon the node name supplied in the third parameter. All of the sibling nodes in the second document are cloned and attached to the parent node in the first document.
Using the XML documents in Listing G, see the results in Listing H.
One of the positive things about being able to rewrite a Web page that nobody wants to touch is that the only thing that really matters is the end result. This means that the choice of tools is up to the developer; in my case, this meant using XML and XSLT. Of course this freedom means that the possibility of creating another monstrous page can be an issue, but while XSLT and extensions aren't silver bullets, they can be used to slay the occasional monster.