Latest: buggy behaviour of parent:: in PHP 5.3.3

Content with Style

Web Technique

XSL: the other way of styling up content

by Pascal Opitz on May 21 2005, 11:24

Buzz-words

Two of the best known acronyms around right now are XML and XSL, often being mentioned as “the way to go” or some abstract technique that stands for a new direction within the whole web. Rather than dealing with the languages itself in detail I'll try to give a pragmatic approach and to show basic examples how to transform data into browser-ready HTML.

Data?

To transform XML we will need XML.

To say it very simple, an XML-file is just structured Data. It works with tags as well, and we'll leave out that validating thing so far and be just working with well-formed XML.

This article will deal with a piece of well formed XML code, that stands for data coming straight out of a database. Download the example files

Getting started

Simple way

Now we are going to transform that using XSLT. To do that we first have to know how we apply the XSL to the XML file.
There is several ways to do that.
First possibility would be to just have a reference to the XSL within the XML. The code for that would look like that:

<?xml-stylesheet type="text/xsl" href="example.xsl"?>

To test if the XSL is applied we will use an XSL-file that is doing nothing but having “Hello world” as output which looks like this:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="html" indent="yes" encoding="iso-8859-1"/> 

<xsl:template match="/">
  <test>Hello world</test>
</xsl:template> 

</xsl:stylesheet> 

Scripting way

Using IE and MSXML we could use Active Scripting to load the XML and the XSL. For example you could, in any XHMTL-File, embed a javascript contaiming code for that would look simmilar to this:

// Load XML file
xmlDoc = new ActiveXObject("Msxml2.DOMDocument.4.0");
xmlDoc.async = false;
xmlDoc.load("data.xml");

// Load XSL file
xslDoc = new ActiveXObject("Msxml2.FreeThreadedDOMDocument.4.0");
xslDoc.async = false;
xslDoc.load("example.xsl");

// XSL Transformation
xslTpl = new ActiveXObject("Msxml2.XSLTemplate.4.0");
xslTpl.stylesheet = xslDoc;
xslProc = xslTpl.createProcessor();
xslProc.input = xmlDoc;

xslProc.transform;
// Transform
document.write(xslProc.output);

Like this the XSL and the XML will be pulled in without changing them in any kind of way. This obviously just works with javascript activated.

For Mozilla it would look like this:

function onload() {
  processor.importStylesheet(xslDoc);
}

function transform() {
  doc = processor.transformToDocument(xmlDoc);
  var xmls = new XMLSerializer();
  document.write(xmls.serializeToString(doc));
}

var processor = new XSLTProcessor();

var xslDoc = 
document.implementation.createDocument("", "xslDoc", null);
// onload handler
xslDoc.addEventListener("load", onload, false);
xslDoc.load("example.xsl");

var xmlDoc = document.
implementation.createDocument("", "xmlDoc", null);
xmlDoc.addEventListener("load", transform, false);
xmlDoc.load("data.xml");

Server-side way

Rather than having all the transformation on the client, we also could use server-sided transformation using sablotron or something similar. The PHP-code for using Sablotron would loke like this:

//create the processor
$my_xslt=xslt_create();

//filepath on UNIX
$xml = getcwd()."data.xml";
$xsl = getcwd()."example.xsl";

//process the fiel and echo the result
echo xslt_process($my_xslt,$xml,$xsl,NULL,$arguments);

//free the processor
xslt_free($my_xslt);

Note that on win32-systems you need to put in a path like this:

$xml = "file://".getcwd()."data.xml";

See an example of a transformed file here

So what do I do?

Depends. Obviously the stylesheet-reference is a nice and easy way, but you have to modify the XML-file and you cannot pass parameters or anything to the XSL, which would make things like expanding menus or highlighted table-rows possible.
This is possible when using client-side scripting, but you have to provide a sophisticated script for IE and Mozilla.
Anyway, for any client-side solution IE needs to have the MSXML-parser installed.
So you could let the server do the work, IIS with MSXML or an apache with PHP and Sablotron should do the job. The output can be any kind of HTML and XHTML you specify. But that obviously requires a server.

Ok, let’s transform

find your node

The first thing to get is that in XSL you can break the structure down to different templates and apply those on nodes of the DOM-tree found in the XML Document. That means that first you have to navigate through the DOM-tree using XPATH-commands. We will begin carefully with creating our basic output-document by inserting the title and finding the page element. The example files are here.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" 
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="html" indent="yes" encoding="iso-8859-1"/> 

<xsl:template match="/site">

  <html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title><xsl:value-of select="current()/title" /></title>
  </head>
  <body>
    <xsl:value-of select="current()/page/@label" />
  </body>
</html>

</xsl:template> 

</xsl:stylesheet> 

So according to our XML-Structure we navigate to the node named “site”, the slash in front of it indicates that it is child of the root element. With the “xsl:value-of” statement we get the data that is held in the selected node, in this case “current()/title” where current() points to the node that the template is applied on, in this case “/site”
It is also possible to display values of attributes, in this case the “label”-attribute of the “page”-node

Check the output transformed with sablotron

templates

Now we'll apply templates to repeating nodes. Let's have a look on the new code first! Get the example files here.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="html" indent="yes" encoding="iso-8859-1"/> 


<xsl:template match="/site">
  
  <html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title><xsl:value-of select="current()/title" /></title>
    <style>@import url(css/example.css);</style>
  </head>
  <body>
    <div class="content">
      <h1><xsl:value-of select="current()/page/@label" /></h1>
      <xsl:for-each select="current()/page/contentblock">
        <xsl:call-template name="contentblock"/>
      </xsl:for-each> 
    </div>
  
    <div class="right">
      <xsl:for-each select="current()/page/box">
        <xsl:call-template name="box"/>
      </xsl:for-each> 
    </div>

    <div class="clear"></div>
  </body>
</html>

</xsl:template> 


<xsl:template name="contentblock">

  <xsl:param name="url" select="current()/image/@url" />
  <xsl:param name="width" select="current()/image/param/@width" />
  <xsl:param name="height" select="current()/image/param/@height" />

  <div class="contentblock">
    <p><xsl:value-of select="current()/text" /></p>
    <div class="img">
      <img src="{$url}" width="{$width}" height="{$height}" /> 
      <p><xsl:value-of select="current()/image/subtitle" /></p>
    </div>
  </div>
</xsl:template> 

<xsl:template name="box">
  <div class="box">
    <h2><xsl:value-of select="current()/headline" /></h2>
    <p><xsl:value-of select="current()/boxtext" /></p>
  </div>
</xsl:template> 

</xsl:stylesheet> 

Ok, first thing you should put your eye on is the code, that loops through all nodes with a particular name. I have used this code for all elements named “contentblock” and “box”. The xsl-command for looping in this case was

 <xsl:for-each select="current()/page/contentblock">

Within this loop I have called different templates. The xsl-command for calling a template is

 <xsl:call-template name="contentblock"/>

Annother interesting thing that you will have noticed is the possibility to insert values inline using {@attribute}. Like this its becomes easily possible to insert values into attributes of tags,
which would be not possible with <xsl:value-of />

The other way to do that would be <xsl:attribute />, wich I hardly ever use, but feel free to search google for it.

You also may have noticed that I introduced the use of variables by using

<xsl:param name="width" select="current()/image/param/@width" />

The value of this variable can now be called with {$width} or <xsl:value-of select="$width" />. Using javascript or server-side techniques for XSLT, working with these variables becomes more important (and makes more sense as well). But I am afraid that this would be to much in-depth for just the start.

Style it up

Now we have our XML-document already transformed into browser-ready HTML. All we need to add now is some CSS, and I guess you allready have noticed the <style>@import url(css/exaple.css);</style> in the document-head. Have a look at the final output with sablotron or the xml file including a stylesheet-link!

Conclusion

benefits

Even without looking into the really dynamic bits of XSL we can see that XSL is esspecially usefull when it comes to repeating data-patterns which have to be displayed as table-row or something simmilar. This keeps your data lean and the look seperated from the content. It gets even more interesting when we start using dynamic scripting to call the transformation and variables within the XSL. In addition it becomes possible to test the output without being sure about how the data will be transformed, either on the server or on the client side.

problems

XSL on the client is not really implemented yet. To use dynamic processing you have to script solutions for every browser, and many don't even support it. This problem is solved when you are using XSLT on the server.

Comments

  • Really useful tutorial. Cheers :)

    by Dan Bailey on May 25 2005, 20:28 - #

  • Very welcome.

    by Pascal Opitz on May 26 2005, 03:08 - #

  • Very concise and informative. Discusses the XML/XSL transformation in a nutshell.

    by Joseph De Guzman on January 23 2006, 21:58 - #

  • Thanks :)

    by Pascal Opitz on January 30 2006, 09:41 - #

  • Just to remind everyone that this article was written when PHP4 was still on. With PHP5 things are different:

    
    $xmlDoc = new DOMDocument();
    $xmlDoc->load('file.xml');
    
    $xslDoc = new DOMDocument();
    $xslDoc->load('stylesheet.xsl');
    
    $proc = new XSLTProcessor();
    $proc->importStylesheet($xslDoc);
    echo $proc->transformToXML($xmlDoc);
    

    by Pascal Opitz on February 28 2009, 21:36 - #

Leave your comment

Comments are moderated.
Tags allowed: a, strong, em, code, ul, ol, li, q, blockquote, br, p

Advertisement
Advertisement