12.6.1 Problem
You have a XML document and a XSL stylesheet. You want to transform
the document using XSLT and capture the results. This lets you apply stylesheets
to your data and create different versions of your content for different media.
12.6.2 Solution
$xml = 'data.xml';
$xsl = 'stylesheet.xsl';
$xslt = xslt_create( );
$results = xslt_process($xslt, $xml, $xsl);
if (!$results) {
error_log("XSLT Error: #".xslt_errno($xslt).": ".xslt_error($xslt));
}
xslt_free($xslt);
The transformed text is stored in $results.
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.
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);