tags:

views:

326

answers:

1

The following works for me:

<xsl:variable name="core" select="document('CoreMain_v1.4.0.xsd')" />
<xsl:variable name="AcRec" select="document('AcademicRecord_v1.3.0.xsd')" />

<xsl:template match="xs:element">    
  <xsl:variable name="prefix" select="substring-before(@type, ':')" />
  <xsl:variable name="name" select="substring-after(@type, ':')" />

  <xsl:choose>
    <xsl:when test="$prefix = 'AcRec'">    
      <xsl:apply-templates select="$AcRec//*[@name=$name]">
        <xsl:with-param name="prefix" select="$prefix" />
      </xsl:apply-templates>       
    </xsl:when>
    <xsl:when test="$prefix = 'core'">     
      <xsl:apply-templates select="$core//*[@name=$name]">
        <xsl:with-param name="prefix" select="$prefix" />
      </xsl:apply-templates>       
    </xsl:when>    
  </xsl:choose>
</xsl:template>

But I use the same logic to handle the lookup of elements in the current or other documents based on the prefix, matching the node name in numerous places within the stylesheet. So, after changing the stylesheet version to 2.0, I tried:

<xsl:template match="xs:element">
  <xsl:value-of select="my:lookup(@type)" />
</xsl:template>

<xsl:function name="my:lookup">
  <xsl:param name="attribute" />

  <!-- parse the attribute for the prefix & name values -->
  <xsl:variable name="prefix" select="substring-before($attribute, ':')" />
  <xsl:variable name="name" select="substring-after($attribute, ':')" />

  <!-- Switch statement based on the prefix value -->
  <xsl:choose>
    <xsl:when test="$prefix = 'AcRec'">    
      <xsl:apply-templates select="$AcRec//*[@name=$name]">
        <xsl:with-param name="prefix" select="$prefix" />
      </xsl:apply-templates>       
    </xsl:when>
    <xsl:when test="$prefix = 'core'">    
      <xsl:apply-templates select="$core//*[@name=$name]">
        <xsl:with-param name="prefix" select="$prefix" />
      </xsl:apply-templates>    
    </xsl:when>    
  </xsl:choose> 
</xsl:function>

In my reading, I have only found examples of functions that return text - none call templates. I have the impression that an xsl:function should always return text/output...

After more investigation, it is entering the my:lookup function and the variables (prefix & name) are getting populated. So it does enter the xsl:choose statement, and the hits the appropriate when test. The issue appears to be with the apply-templates - value-of is displaying the child values; copy-of does as well, which I think is odd (shouldn't the output include the xml element declarations?). Why would there be a difference if code that works in a template declaration is moved to an xsl:function?

+1  A: 

It's been a while since I did any serious XSLT, but IIRC your problem is not in the function, but in your template:

<xsl:template match="xs:element">
  <xsl:value-of select="my:lookup(@type)" />
</xsl:template>

The value-of statement won't inline the result tree returned by your function. Instead, it's going to try and reduce that result tree down into some kind of string, and inline that instead. This is why you're seeing the child values and not the elements themselves.

To inline the result tree returned by your function, you'll need to use some templates to copy the result tree into place.

So, your main template will need to change to this:

<xsl:template match="xs:element">
  <xsl:apply-templates select="my:lookup(@type)" />
</xsl:template>

and you'll need some templates to do the recursive call. A quick google found a good discussion of the identity template that should do what you need.

(Please forgive any syntax errors, as I said, it's been a while ...)

Bevan
Nothing to forgive - you are 100% correct, thanks!
OMG Ponies