home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Book HomePHP CookbookSearch this book

12.6. Transforming XML with XSLT

12.6.3. Discussion

XML documents describe the content of data, but they don't contain any information about how those data should be displayed. However, when XML content is coupled with a stylesheet described using XSL (eXtensible Stylesheet Language), the content is displayed according to specific visual rules.

The glue between XML and XSL is XSLT, which stands for eXtensible Stylesheet Language Transformations. These transformations apply the series of rules enumerated in the stylesheet to your XML data. So, just as PHP parses your code and combines it with user input to create a dynamic page, an XSLT program uses XSL and XML to output a new page that contains more XML, HTML, or any other format you can describe.

There are a few XSLT programs available, each with different features and limitations. PHP currently supports only the Sablotron XSLT processor, but in the future you'll be able to use other programs, such as Xalan and Libxslt. You can download Sablotron from http://www.gingerall.com. To enable Sablotron for XSLT processing, configure PHP with both --enable-xslt and --with-xslt-sablot.

Processing documents takes a few steps. First, you need to grab a handle to a new instance of an XSLT processor with xslt_create( ). Then, to transform the files, use xslt_process( ) to make the transformation and check the results:

$xml = 'data.xml';
$xsl = 'stylesheet.xsl';

$xslt = xslt_create( );
$results = xslt_process($xslt, $xml, $xsl);

You start by defining variables to store the filenames for the XML data and the XSL stylesheet. They're the first two parameters to the transforming function, xslt_process( ). If the fourth argument is missing, as it is here, or set to NULL, the function returns the results. Otherwise, it writes the resulting data to the filename passed:

xslt_process($xslt, $xml, $xsl, 'data.html');

If you want to provide your XML and XSL data from variables instead of files, call xslt_process( ) with a fifth parameter, which allows you to substitute string placeholders for your files:

// grab data from database
$r = mysql_query("SELECT pages.page AS xml, templates.template AS xsl
                  FROM pages, templates
                  WHERE pages.id=$id AND templates.id=pages.template") 
     or die("$php_errormsg");

$obj = mysql_fetch_object($r);
$xml = $obj->xml;
$xsl = $obj->xsl;

// map the strings to args
$args = array('/_xml' => $xml,
              '/_xsl' => $xsl);

$results = xslt_process($xslt, 'arg:/_xml', 'arg:/_xsl', NULL, $args);

When reading and writing files, Sablotron supports two types of URIs. The PHP default is file:, so Sablotron looks for the data on the filesystem. Sablotron also uses a custom URI of arg:, which allows users to alternatively pass in data using arguments. That's the feature used here.

In the previous example, the data for the XML and XSL comes from a database, but, it can arrive from anywhere, such as a remote URL or POSTed data. Once you've obtained the data, create the $args array. This sets up mappings between the argument names and the variable names. The keys of the associative array are the argument names passed to xslt_process( ); the values are the variables holding the data. By convention, /_xml and /_xsl are the argument names; however, you can use others.

Then call xslt_process( ) and in place of data.xml, use arg:/_xml, with arg: being the string that lets the extension know to look in the $args array. Because you're passing in $args as the fifth parameter, you need to pass NULL as the fourth argument; this makes sure the function returns the results.

Error checking is done using xslt_error( ) and xslt_errno( ) functions:

if (!$results) {
    error_log('XSLT Error: #' . xslt_errno($xslt) . ': ' . xslt_error($xslt));
}

The xslt_error( ) function returns a formatted message describing the error, while xslt_errno( ) provides a numeric error code.

To set up your own custom error handling code, register a function using xslt_set_error_handler( ). If there are errors, that function is automatically called instead of any built-in error handler.

function xslt_error_handler($processor, $level, $number, $messages) {
    error_log("XSLT Error: #$level");
}

xslt_set_error_handler($xslt, 'xslt_error_handler');

Finally, PHP cleans up any open XSLT processors when the request ends, but here's how to manually close the processor and free its memory:

xslt_close($xslt);


Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.