Here’s an update to my post on XML/XSLT, which comes first?, and the revelations that came to pass when I tried to do something I believed to be relatively simple (despite being made to feel rather unorthodox in my approach).
So, I installed Sablotron and interminglated (my new techno-jargon for the day. Can you guess my mood?) it with PHP4, tested it with a straightforward XML datafile and XSLT stylesheet. Wow! It actually worked. Now, I have an XML file of elements of the periodic table and set about creating an XSLT stylesheet that would display it in the usual manner as show below.

This isn’t exactly an easy task, considering the way XML data is searched and processed by XSLT stylesheets/transformations. With a simple stylesheet I got a basic list of elements, nowhere near my final goal. I had to find a way to create the correct shaped table (as above) but I had no way of getting the stylesheet to insert the empty table cells needed to do so, e.g. those between Hydrogen (H) and Helium (He). Having been a programmer for nigh on 23 years now, I instinctively cast my mind to nested loops and inserting row and column values for each element. The problem here is that there is no XSLT loop functionality apart from using for-each, but this traverses XML nodes, not values from say, 1 to 18 (as I needed for the columns).
One solution would be to include empty nodes in the XML data in order to create the empty table cells, but there are no empty elements in the periodic table, so this data has no place in my XML tree. But as luck would have it I stumbled upon an example stylesheet using templates that are called recursively by passing a template an initial value, if that value was less than the end of the loop then it would do it’s work and then call itself with the value it was passed +1. So I set about creating a stylesheet that used this to create two nested loops:
A sample of my XML file with all the interesting data removed, like atomic mass, density, number of protons and neutrons, etc. etc.
<?xml version="1.0"?>
<periodic_table>
<atom name="Hydrogen" symbol="H">
<row>1</row>
<col>1</col>
<atomic_number>1</atomic_number>
</atom>
<atom name="Helium" symbol="He">
<row>1</row>
<col>18</col>
<atomic_number>2</atomic_number>
</atom>
</periodic_table>
The full XSLT stylesheet I finally achieved.
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="periodic_table">
<html>
<body>
<table cellspacing="1" cellpadding="2" border="0">
<xsl:call-template name="proc_row">
<xsl:with-param name="trow">1</xsl:with-param>
</xsl:call-template>
</table>
</body>
</html>
</xsl:template>
<xsl:template name="proc_row">
<xsl:param name="trow"/>
<xsl:choose>
<xsl:when test="$trow < 10">
<tr>
<xsl:call-template name="proc_col">
<xsl:with-param name="trow" select="$trow"/>
<xsl:with-param name="tcol">1</xsl:with-param>
</xsl:call-template>
</tr>
<xsl:call-template name="proc_row">
<xsl:with-param name="trow" select="$trow + 1"/>
</xsl:call-template>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="proc_col">
<xsl:param name="trow"/>
<xsl:param name="tcol"/>
<xsl:choose>
<xsl:when test="$tcol < 19">
<td style="border:1px solid #666;text-align:center;">
<xsl:text disable-output-escaping="yes"><span style="text-align:center;font-size:0.6em;font-weight:bold;font-family:verdana;" title="</xsl:text><xsl:value-of select="//periodic_table/atom[row=$trow and col=$tcol]/@name"/>"<xsl:text disable-output-escaping="yes">></xsl:text>
<xsl:value-of select="//periodic_table/atom[row=$trow and col=$tcol]/@symbol"/>
<xsl:text disable-output-escaping="yes"></span></xsl:text>
</td>
<xsl:call-template name="proc_col">
<xsl:with-param name="trow" select="$trow"/>
<xsl:with-param name="tcol" select="$tcol + 1"/>
</xsl:call-template>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
To begin with I directly linked the XML file to this stylesheet to see the outcome and voila! it worked, very quickly indeed. Since I didn’t want to limit this data to the one stylesheet, as I also wanted pages showing the details of each element in full on separate pages, linked by their names in the full periodic table, I tried using good ol’ PHP and my newly installed Sablotron. I quickly knocked together a PHP file to load both the XML data and XSLT stylesheet and transform the data using xslt_process() (see the link a the top of this post for example code on how I did this), but to my dismay the script timed-out in the browser. I tried running this PHP script from the command line and found it took a full minute to come back with the resulting page! Sablotron is just too damn slow!!!
I then discovered that PHP5 includes it’s other functionality for handling XML data and applying XSLT stylesheets through libxml, so I quickly set about bombarding my Linux server with numerous source installs, configures and makes to get PHP5 installed with XSLT support and also took the opportunity to upgrade to Apache 2.0 for good measure. Then I set about using this new functionality with the following PHP5 code:
<?php
//Create the XSLT processor
$xp = new XsltProcessor();
//Load our XSLT stylesheet
$xsl = new DomDocument;
$xsl->load('./pt2.xsl');
//Import the stylesheet into the processor
$xp->importStylesheet($xsl);
//Load the XML data
$xml_doc = new DomDocument;
$xml_doc->load('./pt2.xml');
//Apply the stylesheet to the data to generate the html
if ($html = $xp->transformToXML($xml_doc))
{
//If successful, output the html to the browser
print $html;
}
else
{
//If not, scream and throw your toys out of the pram
trigger_error('Transformation failed.',E_USER_ERROR);
}
?>
The page loaded in about 15 seconds, not exactly an ideal amount of time for a page to load, especially from a local network machine (could be a swine loading over the net), but a definite improvement on having the script time-out. Unfortunately, the fact that directly specifying the XSLT stylesheet within the XML data produces the page instantly in the browser leaves me entirely unsatisfied with this result. Of course directly applying the stylesheet runs client-side, but why can’t Sablotron or even PHP5 using libxml do this as quickly on the server? What is IE and Firefox/Mozilla doing that PHP5/libxml isn’t?
If you have any ideas, please don’t hesitate to pluck them out and superglue them into a comment on this post.
