Follow Me On Twitter Facebook LinkedIn Flickr
Vmware virtual machines constantly restarting while trying to build a LFS system has introduced me to a brand new level of tedium. 13 hrs ago
A software development and computer technology blog.

Archive for November, 2004

Move over Sablotron, here comes PHP5

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.

Periodic Table

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.

XML / XSLT, which comes first?

When looking at one of my personal projects, where I was using an XML version of some MySQL stored data, I realised there is a very basic issue with using stylesheets.

Which is the more likely scenario? A) You have an XSLT stylesheet, which you wish to apply to several files of XML data, or B) You have one file of XML data which you wish to display in different ways using different stylesheets. In all honesty I think they are equally important. But the standards seem to have set a preference for the former, much to my dismay.

When applying an XSLT stylesheet to some XML data (through XML means alone) you would specify the stylesheet inside the XML file.

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="mytransform.xsl"?>
<data>
...
</data>

Unfortunately this literally binds the XML data to one way of displaying it, not a particularly useful thing to do. For instance, if our XML data represented a shops stock, you might want to show a summary of particular product types, with each type as a link to a page which shows a detailed list of products of that type. To do this with .XML files we would have to duplicate the XML data in another XML file and link that to a separate stylesheet. Of course this way you are free to use this stylesheet for as many different XML files as you like.

Luckily there are solutions to this problem and it doesn’t necessarily revolve around JavaScript. Not that I have anything against JavaScript or client-side scripting in general, but in these cases I would just prefer something more static on the client-side and only send the browser the resulting document. Many server-side scripting languages have support modules for processing XML documents with XSLT stylesheets/transforms including PHP, PERL, Python and I suspect ASP does as well, although I haven’t investigated this yet. For example, using PHP:

<?php
$xm = xslt_create();
$html = xslt_process($xm, 'data.xml', 'transform.xsl');
xslt_free($xm);
echo $html;
?>

Here we create an XSLT parser object ($xm) and use it to transform an XML document using a specified XSLT transform/stylesheet, finally printing the resulting output to the client browser.

If, like me, you are using a Redhat 9 Linux box to serve the pages for this then be warned that you may have to do a little more work, since the standard PHP install with Redhat 9 does not include XSLT support. In the end I had to remove my versions of PHP, apache and mysql and reinstall them along with installing expat, sablot, libxml2, zlib and curl, although not all of these are necessary. The main ones you will need are expat, sablot and libxml.