Many thanks David. A subtle, but extremely important point.
I figure that others may encounter this problem, so below I have summarized
the problem and its solution. /Roger
Determining the datatype of the value returned by a function
Suppose that you want to create an XSLT function which returns a value that
may be one of any number of different (atomic) datatypes, e.g., xs:integer,
xs:double, xs:decimal, xs:string, etc.
With the value that the function returns you would like to determine its
datatype. For example, if the function returns the integer 5 then:
"$value instance of xs:integer"
should yield true (assume that $value is a variable that holds the value
returned from the function).
Here is an example that shows invoking a function and then testing the value
that is
returned to determine its datatype:
<xsl:template match="/">
<xsl:variable name="test1" select="'A'"/>
<xsl:variable name="value" select="ex:Test($test1)"/>
<xsl:choose>
<xsl:when test="$value instance of xsd:integer">
<xsl:message>INTEGER</xsl:message>
</xsl:when>
<xsl:when test="$value instance of xsd:string">
<xsl:message>STRING</xsl:message>
</xsl:when>
...
<xsl:otherwise>
<xsl:message>OTHER</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
How you design the function is crucial. The below function gives
undesirable results.
It always returns a text node that contains a string value:
<xsl:function name="ex:Test">
<xsl:param name="letter"/>
<xsl:choose>
<xsl:when test="$letter eq 'A'">
<xsl:variable name="num" select="5" as="xsd:integer"/>
<xsl:value-of select="$num"/>
</xsl:when>
<xsl:when test="$letter eq 'B'">
<xsl:variable name="num" select="5.00" as="xsd:decimal"/>
<xsl:value-of select="$num"/>
</xsl:when>
...
<xsl:otherwise>
<xsl:variable name="message" select="'Error'" as="xsd:string"/>
<xsl:value-of select="$message"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
Consider this code snippet:
<xsl:variable name="num" select="5" as="xsd:integer"/>
<xsl:value-of select="$num"/>
You might think that the xsl:value-of element will output an integer 5.
In fact, it will not. The xsl:value-of statement always outputs:
1. A text node, and
2. The datatype of the value in the text node is always string.
That is, with the xsl:value-of element you will always loose
datatype information. Beware!
Now consider this code snippet:
<xsl:variable name="num" select="5" as="xsd:integer"/>
<xsl:sequence select="$num"/>
The xsl:sequence element behaves very differently from the xsl:value-of
element. In the above example, the xsl:sequence element will simply
output the number 5, with the integer datatype intact.
So, if we want to create a function that returns an atomic value, and we
want
the datatype of the atomic value intact, then the function must use
xsl:sequence,
and it must not use xsl:value-of.
Here is the correct way to design the function:
<xsl:function name="ex:Test">
<xsl:param name="letter"/>
<xsl:choose>
<xsl:when test="$letter eq 'A'">
<xsl:variable name="num" select="5" as="xsd:integer"/>
<xsl:sequence select="$num"/>
</xsl:when>
<xsl:when test="$letter eq 'B'">
<xsl:variable name="num" select="5.00" as="xsd:decimal"/>
<xsl:sequence select="$num"/>
</xsl:when>
...
<xsl:otherwise>
<xsl:variable name="message" select="'Error'" as="xsd:string"/>
<xsl:sequence select="$message"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
Here's a complete example, that works as desired:
<xsl:function name="ex:Test">
<xsl:param name="letter"/>
<xsl:choose>
<xsl:when test="$letter eq 'A'">
<xsl:variable name="num" select="5" as="xsd:integer"/>
<xsl:sequence select="$num"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="message" select="'Error'" as="xsd:string"/>
<xsl:sequence select="$message"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
<xsl:template match="/">
<xsl:variable name="test1" select="'A'"/>
<xsl:variable name="result" select="ex:Test($test1)"/>
<xsl:choose>
<xsl:when test="$result instance of xsd:integer">
<xsl:message>INTEGER</xsl:message>
</xsl:when>
<xsl:when test="$result instance of xsd:string">
<xsl:message>STRING</xsl:message>
</xsl:when>
<xsl:when test="$result instance of xdt:anyAtomicType">
<xsl:message>xdt:anyAtomicType</xsl:message>
</xsl:when>
<xsl:when test="$result instance of text()">
<xsl:message>text()</xsl:message>
</xsl:when>
<xsl:otherwise>
<xsl:message>OTHER</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
--~------------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--