I wonder if and how it is possible to register a PHP userspace function with the XSLT processor that is able not only to take an array of nodes but also to return it?
Right now PHP complains about an array to string conversion using the common setup:
function all_but_first(array $nodes) {
array_shift($nodes);
shuffle($nodes);
return $nodes;
};
$proc = new XSLTProcessor();
$proc->registerPHPFunctions();
$proc->importStylesheet($xslDoc);
$buffer = $proc->transformToXML($xmlDoc);
The XMLDocument ($xmlDoc
) to transform can for example be:
<p>
<name>Name-1</name>
<name>Name-2</name>
<name>Name-3</name>
<name>Name-4</name>
</p>
Within the stylesheet it's called like this:
<xsl:template name="listing">
<xsl:apply-templates select="php:function('all_but_first', /p/name)">
</xsl:apply-templates>
</xsl:template>
The notice is the following:
Notice: Array to string conversion
I don't understand why if the function gets an array as input is not able to return an array as well?
I was also trying other "function" names as I've seen there is php:functionString
but all tried so far (php:functionArray
, php:functionSet
and php:functionList
) did not work.
In the PHP manual it's written I can return another DOMDocument
containing elements, however then those elements aren't from the original document any longer. That does not make much sense to me.
Something that works for me is to return an instance of DOMDocumentFragment
instead of an array. So to try it on your example, I saved your input as foo.xml
. Then I made foo.xslt
look like this:
<xsl:stylesheet version="1.0" xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
xmlns:php="http://php.net/xsl">
<xsl:template match="/">
<xsl:call-template name="listing" />
</xsl:template>
<xsl:template match="name">
<bar> <xsl:value-of select="text()" /> </bar>
</xsl:template>
<xsl:template name="listing">
<foo>
<xsl:for-each select="php:function('all_but_first', /p/name)">
<xsl:apply-templates />
</xsl:for-each>
</foo>
</xsl:template>
</xsl:stylesheet>
(This is mostly just your example with a xsl:stylesheet
wrapper to invoke it.) And the real heart of the matter, foo.php
:
<?php
function all_but_first($nodes) {
if (($nodes == null) || (count($nodes) == 0)) {
return ''; // Not sure what the right "nothing" return value is
}
$returnValue = $nodes[0]->ownerDocument->createDocumentFragment();
array_shift($nodes);
shuffle($nodes);
foreach ($nodes as $node) {
$returnValue->appendChild($node);
}
return $returnValue;
};
$xslDoc = new SimpleXMLElement('./foo.xslt', 0, true);
$xmlDoc = new SimpleXMLElement('./foo.xml', 0, true);
$proc = new XSLTProcessor();
$proc->registerPHPFunctions();
$proc->importStylesheet($xslDoc);
$buffer = $proc->transformToXML($xmlDoc);
echo $buffer;
?>
The important part being the call to ownerDocument->createDocumentFragment()
to make the object that gets returned from the function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With