Itay Maman
Itay Maman

Reputation: 30723

xsl:element + xsl:function = weirdness? (Saxon,Java)

I've been battling this XSL (Saxon/Java) code for several hours now, and still can't figure it. I narrowed the problem down to this snippet:

<xsl:function name="my:fff" >
  <xsl:element name="p0">
    <p1 aaa='AAA' />
  </xsl:element>
</xsl:function>

<xsl:function name="my:ggg">

  <xsl:variable name="v" select="my:fff()" />

  <!-- Debug messages -->
  <xsl:message>
    $v          '<xsl:sequence select="$v" />'
    $v/*        '<xsl:sequence select="$v/*" />'
    $v/*/@aaa   '<xsl:value-of select="$v/*/@aaa" />'
    $v/p0       '<xsl:sequence select="$v/p0" />'
  </xsl:message>
    ...
</xsl:function>

The output printed by the in my:ggg is as follows:

  $v          '<p0><p1 aaa="AAA"/></p0>'
  $v/*        '<p1 aaa="AAA"/>'
  $v/*/@aaa   'AAA'
  $v/p0       ''

The first three lines are fine. But the fourth line which outputs an empty string is weird. I mean, if $v is <p0><p1 aaa="AAA"/></po> (as indicated in the first line) then why is it that $v/p0 isn't <p1 aaa="AAA"/> ?

What am I missing?

Upvotes: 1

Views: 191

Answers (3)

Michael Kay
Michael Kay

Reputation: 163322

You would find it easier to diagnose this kind of problem if you made a habit of always declaring the argument and return types of a function. That would force you to think about what my:fff returns. In this case it's a (parentless) element node: you can declare the result as as="element(p0)". It would then stick out much more clearly that a p0 element is unlikely to have any p0 children, so my:fff()/p0 is probably wrong.

Upvotes: 1

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243449

Your reasoning would be OK if the my:fff() function was returning a document node -- not an element (p0 that itself doesn't have a p0 child).

So, if you change the function to be the following:

 <xsl:function name="my:fff" as="document-node()" >
        <xsl:document>
         <xsl:element name="p0">
            <p1 aaa='AAA' />
         </xsl:element>
        </xsl:document>
 </xsl:function>

And the complete transformation would be:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:sequence select="my:ggg()"/>
 </xsl:template>

 <xsl:function name="my:fff" as="document-node()" >
        <xsl:document>
         <xsl:element name="p0">
            <p1 aaa='AAA' />
         </xsl:element>
        </xsl:document>
 </xsl:function>

 <xsl:function name="my:ggg">
    <xsl:variable name="v" select="my:fff()" />
    <!-- Debug messages -->
    <xsl:message>
         $v          '
        <xsl:sequence select="$v" />
        '     $v/*        '
        <xsl:sequence select="$v/*" />
        '     $v/*/@aaa   '
        <xsl:value-of select="$v/*/@aaa" />
        '     $v/p0       '
        <xsl:sequence select="$v/p0" />'
    </xsl:message>     ...
 </xsl:function>
</xsl:stylesheet>

then applying this transformation on any XML document (not used), produces now the following debugging output:

     $v          '<p0><p1 xmlns:my="my:my" aaa="AAA"/></p0>'
     $v/*        '<p0><p1 xmlns:my="my:my" aaa="AAA"/></p0>'
     $v/*/@aaa   ''
     $v/p0       '<p0><p1 xmlns:my="my:my" aaa="AAA"/></p0>'

which is probably what you want, with the exception of the aaa attribute, which needs to be accessed as: $v/*/*/@aaa

Upvotes: 1

rsp
rsp

Reputation: 23373

$v is the element returned by my:fff, so it is the tag <p0> including children. $v/p0 tries to select a <p0> as child of the tag in $v, which is empty as the tag <p0> selected by $v does not contain a <p0>.

Upvotes: 1

Related Questions