Hello again,
This is the second part to my PHP XML/XSLT tutorial.
In this tutorial i will be going through a very simple XSL using the XML data produced from part one.
I just going to briefly go over the point to all this, because, many people (including myself) learn things a lot quicker if the technology has a point, or to put it in better words the technology isn't described as a long list of mumbo jumbo and there is a clear cut point to answer the question 'why would i need that?'.
Ok, we already know that XML is a standard for creating markup languages which describe the structure of data, and it comes in very handy, for example Ajax uses xml to transfer data between server and client, through xmlhttprequest. Most of us already know this, but what a few may not know (including myself until a few months ago) is that you can apply a style sheet to XML and produce HTML from it, the style sheets are called XSL or eXtensible Stylesheet Language.
There are 3 main ways of doing this:
the first way is to add a XSL style sheet to an XML file then let the browser do the 'transformation' in other words render the xml data according to the XSL style, much like css. Although this method works, it wont however work on non XSLT aware browsers.
The second way of doing it is by using javascript to do the transformation, but, once again, browser incompatibilities limit the success of this method.
So then how do we do it?, well the third way is to use PHP(or any other server side script like php or asp will do the trick) to do the transformation, then generate the HTML so that any browser can see it properly, this is the method that i will be showing you in this tutorial.
Ok, first off we need an XSL file, i've got one pre made, ill paste it in then go over it.
xml Code:
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method='html'/>
<xsl:param name="title">Car List Generated by PHP/XML/XSTL</xsl:param>
<xsl:template match="/">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title><xsl:value-of select="$title"/></title>
<style type="text/css">
<![CDATA[
<!--
caption { font-weight: bold; }
th {
background: #A2A2A2;
color: #fff;
font-family: arial;
font-weight: normal;
font-size: 12px;
}
tr {
font-family: arial;
color: #000;
font-size: 12px;
background: #7D90A1;
}
-->
]]>
</style>
</head>
<body>
<div class="center" style="width: 300px; margin: 0 auto">
<table border="0" style="width: 300px">
<caption><xsl:value-of select="$title"/></caption>
<thead>
<tr>
<th>Car Name</th>
<th>BHP</th>
<th>Year Released</th>
</tr>
</thead>
<tbody>
<xsl:for-each select="carlist/car">
<tr>
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="bhp"/></td>
<td><xsl:value-of select="year_released"/></td>
</tr>
</xsl:for-each>
</tbody>
</table>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Ok, alot of code to get through here so i better get started :)
Because XSL is still XML we must start it as we would an XML file:
The next line is an XMLns (XML Name Space) declaration, this is so that we can get access to the XSLT elements, attributes and features through the namespace 'xsl', the url just represents an URL that contains the list of elements, attributes and features that we can now use.
xml Code:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
Next we need to define what output form our XSL will take:
xml Code:
<xsl:output method='html/>
We will be outputting to HTML so i have selected HTML, but according to W3schools this is the following accepted values:
xml Code:
method="xml|html|text|name"
Its important to note that Netscape 6 only supports xml and html in the output method.
Next we define a parameter, this will contain our final output title:
xml Code:
<xsl:param name="title">Car List Generated by PHP/XML/XSTL</xsl:param>
Dont worry if you dont understand that, it will become clear soon :)
Next we start our template:
This is where a bit of xPath knowledge comes in, the match attribute is used to associate a template with an XML element. The value of the match attribute is an XPath expression (i.e. match="/" defines the whole document, because "/" in xPath is used to select the root node) so we are starting a template for the whole document.
Again if that still makes no sense, it will become clear eventually :)
Ok now i can start some html to start buiding up our template:
xml Code:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title><xsl:value-of select="$title"/></title>
you can see that i have normal html tags <head>/<meta>/<title> then im back into an xsl tag:
xml Code:
<xsl:value-of select="$title"/>
Remember our parameter?, well that one little tag grabs the data from it.
Parameters allow us to have values that we can access from anywhere within the XSL file, the way we access them is by using the value-of method, normally this is used to get values of XML element by using an xPath statement like 'car/name' but because we prefixed the name with '$' it knows that it is a parameter and not an XML element we want.
So basically that produces the HTML code:
html Code:
<title>Car List Generated by PHP/XML/XSTL</title>
Next we are back into HTML again (tags aren't prefixed with xsl, so the xsl parser will just ignore them and present them to the browser 'as is', a bit like the way php ignores any html outside of the <?php ?> tags.
Here we start a 'style' tag and give it some CSS:
xml Code:
<style type="text/css">
<![CDATA[
<!--
caption { font-weight: bold; }
th {
background: #A2A2A2;
color: #fff;
font-family: arial;
font-weight: normal;
font-size: 12px;
}
tr {
font-family: arial;
color: #000;
font-size: 12px;
background: #7D90A1;
}
-->
]]>
</style>
Notice the use of the <![CDATA[ ... ]]> tags, this basically tells the parser to ignore anything between them, this is because the parser will try to interpret the css and produce errors, for example the '<' character may appear in javascript, but if left without <![[CDATA ]]> tags wrapping it, it will be misinterpreted by the parser as being a start of a new element, so you must either replace '<' with its entity reference '<' or use <![CDATA[]]> to wrap around the code, thus making the parser ignore them.
There are other characters that will be wrongly interpreted, they are:
< less than
> greater than
& ampersand
' apostrophe
" quotation mark
In the case of javascript and indeed CSS we cannot replace the characters for there entity references because it will break the script, so we must wrap the code in the CDATA.
Phew that was a long winded explanation of something relatively simple .
Anyway onwards we must plod, we have much to cover.
I'm going to skip most of the HTML because it should be self explanatory.
The next xsl tag we come across is:
xml Code:
<xsl:value-of select="$title"/>
which does exactly the same as it did previously for the title tag
xml Code:
<xsl:for-each select="carlist/car">
<tr>
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="bhp"/></td>
<td><xsl:value-of select="year_released"/></td>
</tr>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Ok heres just a very quick html table row, but notice the for-each statement, that is going to loop through every 'car' node then fill the td's with the relevant data for each row, we know its looping through 'car' s because of the xPath expression in the select attribute 'carlist/car/'.
Then we end the 'for-each', then the template (match="/") and then end the stylesheet.
Ok, so thats our XSL roughly described, ON WITH THE PHP!!!
The first thing we do is to create a new XsltProcessor object, this will allow us to process the xsl and perform our 'transformation':
PHP Code:
$xsltProcessor = new XsltProcessor();
Next we have to load the xsl document we just created then import it so that we can process it:
PHP Code:
// create a DOM document and load the XSL stylesheet
$xsl = new DomDocument;
$xsl->load('car.xsl');
// import the XSL styelsheet into the XSLT process
$xsltProcessor->importStylesheet($xsl);
Here we create a new DOMdocument object, load the xsl and then we pass it into the importStylesheet() method of XsltProcessor().
Next we need to load our XML file:
PHP Code:
// create a DOM document and load the XML
$xmlDoc = new DomDocument;
$xmlDoc->load('cars.xml');
Then we invoke the transformation, I've wrapped it in a try - catch to catch errors:
PHP Code:
try
{
$html = $xsltProcessor->transformToXML($xmlDoc);
echo $html;
}
catch(Exception $pEx)
{
echo $pEx->getMessage();
}
That (hopefully) will display the complete page (I've attached a working example)
Hopefully that has shown the usefulness and power of using these technology's. The main point of this script is to separate presentation layer from the logic layer so that any one of these layers can be modified without affecting the other, and I personally prefer this method from the templating systems out there for php, with this you have more flexibility with the XSL file, I haven't even gone over half of the capabilities of XML
You could also save the HTML file instead of echoing it out like so:
.
PHP Code:
try
{
$fh = fopen('cars.html','w+');
fwrite($fh, $xsltProcessor->transformToXML($xmlDoc));
fclose($fh);
}
catch(Exception $pEx)
{
echo $pEx->getMessage();
}
We can also set parameters (like the title) dynamicaly using php:
PHP Code:
$xsltProcessor->setParameter('', 'title', 'new value for title');
And there is so much more.
Like for example we want alternating row background colors, the way that i can think of, is to have 2 classes 'r0' and 'r1', and then call this in the xsl:
xml Code:
<tr class="r{position() mod 2}">
the 'position()' call is yet again some more xPath magic! Basicaly it returns the index position of the node that is currently being processed, so the first one will be 1, second 2 and so on, then we call 'mod' on that value, which is 'modulus' (division remainder) and then divide by 2, so basically if you have never seen mod before in programming, it finds to see if there is a remainder from the division and returns 1 and 0 depending on if the number divided without leaving a remainder, so basically its to see if the number is odd or even, then we put the result next to the text for the class name using the {}, so to cut a long story short its gonna produce: r1, r0, r1, r0 etc..
There is an example of this in the attachment.
Anyway i hope i have explained everything and got my facts right, and i hope you guys find it useful, XML/XSLT and xPath are all powerful tools and i think we will see more and more of this kind of stuff in the future.