[xsl] Accessing input document from extension function loop (XSL 1.0)

Subject: [xsl] Accessing input document from extension function loop (XSL 1.0)
From: Michael Ludwig <mlu@xxxxxxxxxxxxx>
Date: Fri, 15 Feb 2008 12:57:10 +0100
This question is related to content generated by extension functions and
the context I'm in when using this content in a loop. The example
requires EXSLT support, particularly support for the str:split function
from "http://exslt.org/strings";.

Here's my input document, "ef.xml":

  <Channels>
    <Ch ID="ard">ARD</Ch>
    <Ch ID="zdf">ZDF</Ch>
  </Channels>

Here's my XSL program, "ef.xsl":

  <?xml version="1.0" encoding="UTF-8"?>
  <xsl:stylesheet version="1.0"
   xmlns:php="http://php.net/xsl"; exclude-result-prefixes="php"
   xmlns:str="http://exslt.org/strings"; extension-element-prefixes="str"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

<xsl:output method="xml" indent="yes"/>

   <xsl:template match="Channels">
    <Urmel>
     <U1>
      <xsl:for-each select="/Channels/Ch/@ID">
       <xsl:call-template name="tests"/>
      </xsl:for-each>
     </U1>
     <!-- PHP example <U2>
      <xsl:for-each select="php:function('gen_nodes', 'ard zdf')/*">
       <xsl:call-template name="tests"/>
      </xsl:for-each>
     </U2> -->
     <U3>
      <xsl:for-each select="str:split('ard zdf')">
       <xsl:call-template name="tests"/>
      </xsl:for-each>
     </U3>
    </Urmel>
   </xsl:template>

   <xsl:template name="tests">
    <T1><xsl:copy-of select="."/></T1><!-- works as expected -->
    <T2><xsl:value-of select="."/></T2><!-- ditto -->
    <!-- T3 doesn't work for U2 and U3. -->
    <Cur><xsl:value-of select="current()"/></Cur>
    <T3><xsl:value-of select="/Channels/Ch[ @ID = current() ]"/></T3>
    <!-- Trying to use a variable in T4 doesn't work either. -->
    <xsl:variable name="current" select="."/>
    <Var><xsl:value-of select="$current"/></Var>
    <T4><xsl:value-of select="/Channels/Ch[ @ID = $current ]"/></T4>
   </xsl:template>

</xsl:stylesheet>

My command line:

xsltproc ef.xsl ef.xml

What am I trying to do here? I am doing a lookup using a string value,
which is either 'ard' or 'zdf'. Of course, this lookup is trivial, but
triviality here is for the sake of the example.

The interesting part is where I get this string value from. There are
three cases: U1, U2 (requiring PHP, commented out) and U3 (requiring
EXSLT).

In U1, I get the string from the input document itself. No problem here.

In U2 (commented out) and U3, I get the string from an extension
function, either EXSLT or PHP. And here's the problem, showing up in T3
and T4. (T1 and T2 work as expected and are there to show what's going
on.) From inside the xsl:for-each loop using the content generated by
the extension function, I don't seem to be able to access my original
input document. Am I mistaken here or is this assumption correct?

If it is correct, why is this so?

And is there a remedy? What do I have to do to profit from extension
functions in the way I'm trying to do while maintaining my ability to
access the input document?

For completion's sake, here's the version of libxslt I am using.

    libxslt Version => 1.1.20
    libxslt compiled against libxml Version => 2.6.27
    libexslt Version => 1.1.20

This is XSLT version 1.0, and it has to be: libxslt is 1.0 only.

Optionally, you may comment in the <U2> example and observe the same
thing as in <U3> when processing the stylesheet using the following PHP
program, "ef.php":

  <?php
  function gen_nodes($str) {
          $doc = new DOMDocument;
          $root = $doc->appendChild($doc->createElement('Moin'));
          foreach (explode(' ', $str) as $s)
                  $root->appendChild($doc->createElement('Tach'))
                          ->appendChild($doc->createTextNode($s));
          return $doc->documentElement;
  }
  $docstr = <<<EOS
  <Channels>
          <Ch ID="ard">ARD</Ch>
          <Ch ID="zdf">ZDF</Ch>
  </Channels>
  EOS;
  $Xsl = new XSLTProcessor();
  $Xsl->registerPHPFunctions();
  $Doc = new DOMDocument();
  $Doc->loadXML($docstr);
  $xsldoc = new DOMDocument();
  $xsldoc->load('extension-function.xsl');
  $Xsl->importStyleSheet($xsldoc);
  echo $Xsl->transformToXML($Doc);

I have asked this question on the very low-traffic EXSLT list before but
the answer hasn't clarified things for me.

[exslt] EXSLT str:split() and evaluation context
http://lists.fourthought.com/pipermail/exslt/2007-September/001597.html
http://lists.fourthought.com/pipermail/exslt/2007-October/001600.html

Michael Ludwig

Current Thread