Transforming Dynamically Generated XML with XSLT
Note that the code listings in this article assume the existence of a MySQL database and a familiarity with PHP's database access functions (specifically, its MySQL functions). In case you don't already have MySQL, you can download it from http://www.mysql.com/, and SQL dump files for the database tables used in this article may be obtained from this book's companion web site (http://www.xmlphp.com).
The most common use of dynamically generated XML usually involves transforming it into some other format via an XSL Transformation. I will do just that by using the very simple XSLT stylesheet illustrated in Listing 1.
Listing 1An XSLT Stylesheet Displays a Table of CDs and Tracks (cds.xsl)
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- set up page template --> <xsl:template match="/"> <html> <head> <basefont face="Arial" /> </head> <body> <h3>My CD Collection</h3> <table border="1" cellspacing="0" cellpadding="5"> <tr> <td align="center">Artist</td> <td align="center">Title</td> <td align="center">Track list</td> </tr> <xsl:apply-templates /> </table> </body> </html> </xsl:template> <!-- look for CDs --> <xsl:template match="//cd"> <tr> <td align="center" valign="top"><xsl:value-of select="artist" /></td> <td align="center" valign="top"><xsl:value-of select="title" /></td> <td align="left" valign="top"> <ol> <!-- iterate through track list, print each <track> element as list item --> <xsl:for-each select="tracks/track"> <li><xsl:value-of select="." /></li> </xsl:for-each> </ol>  </td> </tr> </xsl:template> </xsl:stylesheet>
Listing 2 uses PHP's XSLT and DOM functions to dynamically generate an XML document from a MySQL database and format it using the stylesheet above.
Listing 2Dynamically Constructing and Transforming an XML DOM Tree
<?php // query database for records $connection = mysql_connect("cdserver", "joe", "cool") or die ("Unable to connect!"); mysql_select_db("db712") or die ("Unable to select database!"); $query = "SELECT id, title, artist FROM cds"; $result = mysql_query($query) or die ("Error in query: $query. " . mysql_error()); if(mysql_num_rows($result) > 0) { // create DomDocument object $doc = new_xmldoc("1.0"); // add root node $root = $doc->add_root("cds"); // iterate through result set while(list($id, $title, $artist) = mysql_fetch_row($result)) { $record = $root->new_child("cd", ""); $record->set_attribute("id", $id); $record->new_child("title", $title); $record->new_child("artist", $artist); // add <tracks> node $tracks = $record->new_child("tracks", ""); // query database for track listing for this CD $query2 = "SELECT track FROM tracks WHERE cd = '$id' ORDER BY indx"; $result2 = mysql_query($query2) or die ("Error in query: $query2. " . mysql_error()); // print each track as a child of <tracks> while($row = mysql_fetch_row($result2)) { $tracks->new_child("track", $row[0]); } } // dump XML document to a string $xml_string = $doc->dumpmem(); } // close connection mysql_close($connection); // don't print the XML // instead, create an XSLT processor and transform it into HTML if ($xml_string) { // XSLT stylesheet $xslt_file = "cds.xsl"; // create the XSLT processor $xp = xslt_create() or die("Could not create XSLT processor"); // read in the XSLT data $xslt_string = join("", file($xslt_file)); // set up buffers $arg_buffer = array("/xml" => $xml_string, "/xslt" => $xslt_string); // process the two files to get the desired output if($result = xslt_process($xp, "arg:/xml", "arg:/xslt", NULL, $arg_buffer)) { // print output echo $result; } else { // else display error echo "An error occurred: " . xslt_error($xp) . "(error code " . xslt_errno($xp) . ")"; } // free the resources occupied by the handler xslt_free($xp); } ?>
The first part of Listing 2 queries the database, retrieves track and title information, dynamically generates an XML document using PHP's DOM functions, and stores it in a string variable.
After the document has been generated, the focus shifts to PHP's XSLT processor, which is initialized with the xslt_create() function:
$xp = xslt_create() or die("Could not create XSLT processor");
Then, the XSLT stylesheet is read into a string variable, and both XML and XSLT strings are stored in the array $arg_buffer as named arguments:
$xslt_string = join("", file($xslt_file)); $arg_buffer = array("/xml" => $xml_string, "/xslt" => $xslt_string);
This argument buffer is then passed to the XSLT processor via xslt_process(), and the result of the transformation is then printed to the browser:
if($result = xslt_process($xp, "arg:/xml", "arg:/xslt", NULL, $arg_buffer)) { // print output echo $result; }
Figure 1 shows what the output looks like.
Figure 1 The result of transforming a dynamically generated XML document with XSLT.
In case you're wondering how the DOM and XSLT functions work...hey, buy the book!
About This Article
This article is excerpted from XML and PHP by Vikram Vaswani (New Riders Publishing, 2002). Refer to Chapter 7, "PHP, XML, and Databases," for more detailed information on the material covered in this article, or drop by the PHP section (http://www.melonfire.com/community/columns/trog/archives.php?category=PHP) on the Melonfire web site (http://www.melonfire.com/) for more tutorials.