carica / xpath-functions
Provides XPath 2/3 like functions for PHPs ext/xslt
Requires
- php: >= 8.0
- ext-dom: *
- ext-intl: *
- ext-json: *
- ext-xsl: *
This package is auto-updated.
Last update: 2024-10-23 21:57:58 UTC
README
This is project tries to add Xpath 2/3 functions to PHPs XSLTProcessor. A complete implementation isn't possible - some of the syntax is not available. But let's see how much can be done.
If you have a function that you would like to have added please open an issue.
How it works:
- Extends the
XSLTProcessor
withCarica\XpathFunctions\XSLTProcessor
- Implements a callback for the XSLTProcessor to call specific PHP functions
- Adds a stream wrapper to load XSLT templates that wrap callbacks to PHP as Xpath functions using EXSLT or implement the function directly.
Install
composer require carica/xpath-functions
Usage
- Define the namespace for the function
- Import a module into your XSLT
- Call the Xpath function
Step 2 is the difference to XSLT 2/3. You need to import the module template with the functions you would like to use.
Compromises
Xpath/XSLT 1.0 does not of the extensive type system of their successors. So most of the functions return more basic types. Arrays and maps are emulated with XDM nodes, sequences as XDM arrays.
Examples
Use String Comparsion
// import extended XSLTProcessor use Carica\XpathFunctions\XSLTProcessor; $xslt = <<<'XSLT' <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="fn"> <!-- ^- define the function namespace --> <!-- import the string comparsion module --> <xsl:import href="xpath-functions://Strings/Comparsion"/> <xsl:output indent="yes" method="xml"/> <xsl:template match="/names"> <html lang="en"> <body> <div> <header>Exactly</header> <xsl:for-each select="name[fn:compare(., 'André') = 0]"> <span><xsl:value-of select="."/></span> </xsl:for-each> </div> <div> <header>Case Insensitive, Ignore Accents</header> <xsl:variable name="collation">http://www.w3.org/2013/collation/UCA?strength=primary</xsl:variable> <xsl:for-each select="name[fn:compare(., 'andre', $collation) = 0]"> <span><xsl:value-of select="."/></span> </xsl:for-each> </div> </body> </html> </xsl:template> </xsl:stylesheet> XSLT; $xml = <<<'XML' <?xml version="1.0"?> <names> <name>Andreas</name> <name>Andre</name> <name>André</name> <name>Andrè</name> </names> XML; $stylesheet = new DOMDocument(); $stylesheet->loadXML($xslt); $input = new DOMDocument(); $input->loadXML($xml); $processor = new XSLTProcessor(); $processor->importStylesheet($stylesheet); echo $processor->transformToXml($input);
Output:
<?xml version="1.0"?> <html lang="en"> <body> <div> <header>Exactly</header> <span>André</span> </div> <div> <header>Case Insensitive, Ignore Accents</header> <span>Andre</span> <span>André</span> <span>Andrè</span> </div> </body> </html>
Wrap Parts Of Text Nodes Using RegExp
// import extended XSLTProcessor use Carica\XpathFunctions\XSLTProcessor; $xslt = <<<'XSLT' <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="fn"> <!-- import RegExp functions --> <xsl:import href="xpath-functions://Strings/RegExp"/> <xsl:template match="speak//text()"> <!-- use RegExp function --> <xsl:for-each select="fn:analyze-string(., '\d+')/*"> <xsl:choose> <xsl:when test="local-name() = 'match'"> <say-as interpret-as="characters"><xsl:value-of select="."/></say-as> </xsl:when> <xsl:otherwise> <xsl:value-of select="."/> </xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:template> <xsl:template match="*"> <xsl:element name="{name()}"> <xsl:copy-of select="@*"/> <xsl:apply-templates/> </xsl:element> </xsl:template> </xsl:stylesheet> XSLT; $xml = <<<'XML' <?xml version="1.0"?> <speak>The test number is 123456789, and some further block of text.</speak> XML; $stylesheet = new DOMDocument(); $stylesheet->loadXML($xslt); $input = new DOMDocument(); $input->loadXML($xml); $processor = new XSLTProcessor(); $processor->importStylesheet($stylesheet); echo $processor->transformToXml($input);
Output:
<?xml version="1.0"?> <speak>The test number is <say-as interpret-as="characters">123456789</say-as>, and some further block of text.</speak>