Recipe 12.9. Calling PHP Functions from XSLT Stylesheets


12.9.1. Problem

You want to call PHP functions from within an XSLT stylesheet.

12.9.2. Solution

Invoke the XSLTProcessor::registerPHPFunctions( ) method to enable this functionality:

$xslt = new XSLTProcessor(); $xslt->registerPHPFunctions();

And use the function( ) or functionString( ) function within your stylesheet:

<?xml version="1.0" ?> <xsl:stylesheet version="1.0"     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"     xmlns:php="http://php.net/xsl"     xsl:extension-element-prefixes="php"> <xsl:template match="/">     <xsl:value-of select="php:function('strftime', '%c')" /> </xsl:template> </xsl:stylesheet>

12.9.3. Discussion

XSLT parameters are great when you need to communicate from PHP to XSLT. However, they're not very useful when you require the reverse. You can't use parameters to extract information from the stylesheet during the transformation. Ideally, you could call PHP functions from a stylesheet and pass information back to PHP.

Fortunately, there's a method that implements this functionality: registerPHPFunctions( ). Here's how it's enabled:

$xslt = new XSLTProcessor(); $xslt->registerPHPFunctions();

This allows you to call any PHP function from your stylesheets. It's not available by default because it presents a security risk if you're processing stylesheets controlled by other people.

Both built-in and user-defined functions work. Inside your stylesheet, you must define a namespace and call the function( ) or functionString( ) methods, as shown in Example 12-17.

Calling PHP from an XSL stylesheet

<?xml version="1.0" ?> <xsl:stylesheet version="1.0"     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"     xmlns:php="http://php.net/xsl"     xsl:extension-element-prefixes="php"> <xsl:template match="/">     <xsl:value-of select="php:function('strftime', '%c')" /> </xsl:template> </xsl:stylesheet>

At the top of the stylesheet, define the namespace for PHP: http://php.net/xsl. This example sets the namespace prefix to php. Also, set the extension-element-prefixes value to php so XSLT knows these are functions.

To call a PHP function, reference php:function( ). The first parameter is the function name; additional parameters are the function arguments. In this case, the function name is strftime and the one argument is %c. This causes strftime to return the current date and time.

Example 12-18 uses this stylesheet, stored as stylesheet.xsl, to process a single-element XML document.

Transforming XML with XSLT and PHP functions

$dom  = new DOMDocument; $dom->loadXML('<blank/>'); $xsl  = new DOMDocument $xsl->load('stylesheet.xsl'); $xslt = new XSLTProcessor(); $xslt->importStylesheet($xsl); $xslt->registerPHPFunctions(); print $xslt->transformToXML($dom); Mon Jul 22 19:10:21 2004

This works like standard XSLT processing, but there's an additional call to registerPHPFunctions( ) to activate PHP function support.

You can also return DOM objects. Example 12-19 takes the XML address book and mangles all the email addresses to turn the hostname portion into three dots. Everything else in the document is left untouched.

Spam protecting email addresses

function mangle_email($nodes) {     return preg_replace('/([^@\s]+)@([-a-z0-9]+\.)+[a-z]{2,}/is',                         '$1@...',                         $nodes[0]->nodeValue); } $dom  = new DOMDocument; $dom->load('address-book.xml'); $xsl  = new DOMDocument $xsl->load('stylesheet.xsl'); $xslt = new XSLTProcessor(); $xslt->importStylesheet($xsl); $xslt->registerPhpFunctions(); print $xslt->transformToXML($dom);

Inside your stylesheet, create a special template for /address-book/person/email elements, as shown in Example 12-20.

XSL stylesheet to spam protect email address

<?xml version="1.0" ?> <xsl:stylesheet version="1.0"   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   xmlns:php="http://php.net/xsl"   xsl:extension-element-prefixes="php"> <xsl:template match="@*|node()">   <xsl:copy>     <xsl:apply-templates select="@*|node()"/>   </xsl:copy> </xsl:template> <xsl:template match="/address-book/person/email">   <xsl:copy>     <xsl:value-of select="php:function('mangle_email', node())" />   </xsl:copy> </xsl:template> </xsl:stylesheet>

The first template ensures that the elements aren't modified, while the second passes the current node to PHP for mangling. In the second template, the mangle_email( ) function is passed the current node, represented in XPath as node( ), instead of a string. Be sure not to place the node inside quotation marks, or you'll pass the literal text node( ).

Nodes becomes DOM objects inside PHP and always arrive in an array. In this case, mangle_email( ) knows there's always only one object and it's a DOMText object, so the email address is located in $nodes[0]->nodeValue.

When you know that you're only interested in the text portion of a node, use the functionString( ) function. This function converts nodes to PHP strings, which allows you to omit the array access and nodeValue dereference:

function mangle_email($email) {     return preg_replace('/([^@\s]+)@([-a-z0-9]+\.)+[a-z]{2,}/is',                         '$1@...',                         $email); } // all other code is the same as before

The new stylesheet template for /address-book/person/email is:

<xsl:template match="/address-book/person/email">   <xsl:copy>     <xsl:value-of        select="php:functionString('mangle_email', node())" />   </xsl:copy> </xsl:template>

The mangle_email( ) function now processes $email instead of $nodes[0]->nodeValue because the template now calls the functionString( ) function.

The function( ) and functionString( ) methods are incredibly useful, but using them undermines the premise of XSL as a language-neutral transformation engine. When you call PHP from XSLT, you cannot easily reuse your stylesheets in projects that use Java, Perl, and other languages, because they cannot call PHP. Therefore, you should consider the trade-off between convenience and portability before using this feature.

12.9.4. See Also

Documentation on XSLTProcessor::registerPHPFunctions( ) at http://www.php.net/manual/function.xsl-xsltprocessor-register-php-functions.php; XSLT by Doug Tidwell (O'Reilly).




PHP Cookbook, 2nd Edition
PHP Cookbook: Solutions and Examples for PHP Programmers
ISBN: 0596101015
EAN: 2147483647
Year: 2006
Pages: 445

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net