picture of 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