|
 
Using PHP and XML with Apache Cocoon
Darren Beale
First off, for those of you who don't know what Cocoon is, check out
http://xml.apache.org where you can
download the source and read up on it. In short Cocoon is a suite of
Java Servlets that sit on your server waiting for .xml pages and then -
if applicable - it applies the relevant XSL transformations. With one XML
page and different XSL pages you can deliver rendered output suitable for
your Browser, for example HTML for your Desktop or WML for your WAP device.
I've been playing with Cocoon as a "learning" project for some time now but
my main problem has been that of generating the XML dynamicly by using PHP
and then using Cocoon to do the transformations. You can’t embed PHP into a
.xml page because Cocoon doesn't recognise it and to write XSP's I needed to
learn Java, which at the current time is not an option for me.
Prompted by a few postings to the PHP4Beta list I realised that it would be
possible to employ a workaround and still use PHP, so I set off to see if I
could get it to work. Needless to say I did, so here is a very simple example
of using PHP to generate XML dynamically and then using Cocoon to give me browser friendly mark-up.
Stage 1) Static XML
How to write XML is outside of the scope of this article, but here is a simple XML page called phpbuilder.xml so you can see how it is laid out.
Initially we have our "Prolog" including a declaration that tells Cocoon that we want to do an XSLT transformation:
<?xml version="1.0"?>
<?xml-stylesheet href="phpbuilder.xsl" type="text/xsl"?>
<?cocoon-process type="xslt"?>
Now we write out our body elements that contain a message that you've seen once or twice before:
XML/XSL/Cocoon Transformation
Hello World
');
?>
My browser (almost certainly) wants HTML, so I use an XSL page to make sense out of the XML:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="phpbuilder">
<xsl:processing-instruction name="cocoon-format">type="text/html"
<html>
<head>
<title>XML/XSL/Cocoon Transformation</title>
</head>
<body>
<p>
<h1><div align="center">
<xsl:value-of select="heading" />
</div></h1>
</p>
<p>
<xsl:value-of select="message" />
</p>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Notice that the HTML is embedded in the Stylesheet with references to my "heading"
and my message
Also notice that all of my HTML tags have their end equivalents, e.g. </p>.
You cannot get away without closing a particular tag with XML as it does not conform, if you had a
tag such as <br>, it would be written <br/> which indicates that it is an empty tag.
By saving the above example out as phpbuilder.xsl and navigating to my phpbuilder.xml file on a server with Cocoon installed, I would get the resulting HTML:
Cocoon Static Transformation
This is an XML/XSL Transformation – Stage 1
Hello World
'); ?>
Stage 2) Bring on the PHP
Ok, so this is all well and good, but It’s static mark-up, I want to use PHP to generate the XML dynamically, so lets look at the next example, phpbuilder.php:
<?php
/* I want to print out a greeting to a number of countries, not just the World, so in no particular order */
$countries = array ( "UK", "USA", "France", "Germany", "Holland", "Belgium", "Spain", "Denmark", "Finland", "Sweden", "Japan", "China", "New Zealand", "Australia" );
//Now open up a file on the server called dynamic-phpbuilder.xml
$handle = fopen("./dynamic-phpbuilder.xml","w");
/* Now we build up a string that we can save out to our file, notice that the "<?" tags have been separated so we don't confuse the PHP interpreter. */
$tofile = "<" . "?" . "xml version=\"1.0\"" . "?" . ">\n"; $tofile .= "<" . "?" . "xml-stylesheet href=\"dynamic-phpbuilder.xsl\" type=\"text/xsl\"" . "?" . ">\n"; $tofile .= "<" . "?" . "cocoon-process type=\"xslt\"" . "?" . ">\n\n"; $tofile .= "<phpbuilder>\n"; $tofile .= "\t<heading>This is a Dynamically Generated XML that has been Transformed using XSLT</heading>\n";
/* We now do a very simple loop and output our greeting to all the countries in our example array: */
for ($x=0;$x<sizeof($countries);$x++) { $tofile .= "\t<message>\n"; $tofile .= "\t\t<greeting>" . $countries[$x] . "</greeting>\n"; $tofile .= "\t</message>\n"; }
$tofile .= "</phpbuilder>\n";
//Write the string to our file and close the handle
fwrite($handle,$tofile); fclose($handle);
//Finally we redirect to the newly created dynamic-phpbuilder.xml file.
header("Location: dynamic-phpbuilder.xml");
?>
We've also had to modify our earlier stylesheet
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="phpbuilder">
<xsl:processing-instruction name="cocoon-format">type="text/html"</xsl:processing-instruction>
<html>
<head>
<title>PHP-XML/XSL/Cocoon Transformation</title>
</head>
<body>
<p>
<h1><div align="center">
<xsl:value-of select="heading" />
</div></h1>
</p>
<xsl:for-each select="message">
<p>
Hello <xsl:value-of select="greeting" />
</p>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
The only difference here is the
<xsl:for-each select="message">
this allows us to apply the transformation to any instance of a <greeting> within a <message>
So navigating to phpbuilder.php gives us the following markup to our browser:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html> <head> <title>PHP-XML/XSL/Cocoon Transformation</title> </head> <body> <p><h1> <div align="center">This is a Dynamically Generated XML that has been Transformed using XSLT</div> </h1></p> <p>Hello UK</p> <p>Hello USA</p> <p>Hello France</p>
To summarise, we have started with a php script that writes some valid XML to a file and then
redirects to that .xml page. As it's .XML Cocoon wakes up and starts to parse it, combined
with the XSL we have browser friendly code that was Dynamically generated by PHP.
Create a new Stylesheet for WML and Cocoon will allow you to use the same php code to make a WAP freindly page =)
Good luck
--Bealers
|