This reminds me that there is such a function in FXSL -- int:type().
I regard this as a very light implementation -- more (as type objects)
is to come in the future.
Cheers,
Dimitre Novatchev.
P.S. The code
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xdt="http://www.w3.org/2005/04/xpath-datatypes"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:f="http://fxsl.sf.net/"
xmlns:int="http://fxsl.sf.net/internal/type"
exclude-result-prefixes="f xs xdt int"
<xsl:output omit-xml-declaration="yes"/>
<xsl:template match="/">
xs:token('abc') : <xsl:value-of select="int:type(xs:token('abc'))"/>
-1 : <xsl:value-of select="int:type(-1)"/>
xs:negativeInteger(-1) : <xsl:value-of
select="int:type(xs:negativeInteger(-1))"/>
xs:nonPositiveInteger(0) : <xsl:value-of
select="int:type(xs:nonPositiveInteger(0))"/>
0 : <xsl:value-of select="int:type(0)"/>
3 : <xsl:value-of select="int:type(3)"/>
3. : <xsl:value-of select="int:type(3.)"/>
3.0E1 : <xsl:value-of select="int:type(3.0E1)"/>
xs:float(3) : <xsl:value-of select="int:type(xs:float(3))"/>
xs:positiveInteger(3) : <xsl:value-of
select="int:type(xs:positiveInteger(3))"/>
'3' : <xsl:value-of select="int:type('3')"/>
/*/*/text() : <xsl:value-of select="int:type(/*/*/text())"/>
data(/*/*/text()[1]) : <xsl:value-of
select="int:type(data(/*/*/text()[1]))"/>
</xsl:template>
<xsl:function name="int:type" as="xs:string">
<xsl:param name="pThis"/>
<xsl:choose>
<xsl:when test="$pThis instance of xs:decimal">
<xsl:choose>
<xsl:when test="$pThis instance of
xs:unsignedByte">xs:unsignedByte</xsl:when>
<xsl:when test="$pThis instance of
xs:unsignedShort">xs:unsignedShort</xsl:when>
<xsl:when test="$pThis instance of
xs:unsignedInt">xs:unsignedInt</xsl:when>
<xsl:when test="$pThis instance of
xs:unsignedLong">xs:unsignedLong</xsl:when>
<xsl:when test="$pThis instance of
xs:positiveInteger">xs:positiveInteger</xsl:when>
<xsl:when test="$pThis instance of
xs:nonNegativeInteger">xs:nonNegativeInteger</xsl:when>
<xsl:when test="$pThis instance of
xs:negativeInteger">xs:negativeInteger</xsl:when>
<xsl:when test="$pThis instance of
xs:nonPositiveInteger">xs:nonPositiveInteger</xsl:when>
<xsl:when test="$pThis instance of xs:byte">xs:byte</xsl:when>
<xsl:when test="$pThis instance of xs:short">xs:short</xsl:when>
<xsl:when test="$pThis instance of xs:int">xs:int</xsl:when>
<xsl:when test="$pThis instance of xs:long">xs:long</xsl:when>
<xsl:when test="$pThis instance of xs:integer">xs:integer</xsl:when>
<xsl:otherwise>xs:decimal</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$pThis instance of xs:double">xs:double</xsl:when>
<xsl:when test="$pThis instance of xs:float">xs:float</xsl:when>
<xsl:when test="$pThis instance of xs:string">
<xsl:choose>
<xsl:when test="$pThis instance of xs:NMTOKEN">xs:NMTOKEN</xsl:when>
<!-- <xsl:when test="$pThis instance of
xs:NMTOKENS">xs:NMTOKENS</xsl:when> -->
<!-- <xsl:when test="$pThis instance of
xs:ENTITIES">xs:ENTITIES</xsl:when> -->
<xsl:when test="$pThis instance of xs:ENTITY">xs:ENTITY</xsl:when>
<!-- <xsl:when test="$pThis instance of
xs:IDREFS">xs:IDREFS</xsl:when> -->
<xsl:when test="$pThis instance of xs:IDREF">xs:IDREF</xsl:when>
<xsl:when test="$pThis instance of xs:ID">xs:ID</xsl:when>
<xsl:when test="$pThis instance of xs:NCName">xs:NCName</xsl:when>
<xsl:when test="$pThis instance of xs:Name">xs:Name</xsl:when>
<xsl:when test="$pThis instance of xs:language">xs:language</xsl:when>
<xsl:when test="$pThis instance of xs:token">xs:token</xsl:when>
<xsl:when test="$pThis instance of
xs:normalizedString">xs:normalizedString</xsl:when>
<xsl:otherwise>xs:string</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$pThis instance of xs:boolean">xs:boolean</xsl:when>
<xsl:when test="$pThis instance of xs:duration">xs:duration</xsl:when>
<xsl:when test="$pThis instance of xs:dateTime">xs:dateTime</xsl:when>
<xsl:when test="$pThis instance of xs:time">xs:time</xsl:when>
<xsl:when test="$pThis instance of xs:date">xs:date</xsl:when>
<xsl:when test="$pThis instance of xs:gYearMonth">xs:gYearMonth</xsl:when>
<xsl:when test="$pThis instance of xs:gYear">xs:gYear</xsl:when>
<xsl:when test="$pThis instance of xs:gMonthDay">xs:gMonthDay</xsl:when>
<xsl:when test="$pThis instance of xs:gDay">xs:gDay</xsl:when>
<xsl:when test="$pThis instance of xs:gMonth">xs:gMonth</xsl:when>
<xsl:when test="$pThis instance of
xs:base64Binary">xs:base64Binary</xsl:when>
<xsl:when test="$pThis instance of xs:hexBinary">xs:hexBinary</xsl:when>
<xsl:when test="$pThis instance of xs:anyURI">xs:anyURI</xsl:when>
<xsl:when test="$pThis instance of xs:QName">xs:QName</xsl:when>
<xsl:when test="$pThis instance of xs:NOTATION">xs:NOTATION</xsl:when>
<xsl:when test="$pThis instance of
xdt:untypedAtomic">xdt:untypedAtomic</xsl:when>
<xsl:otherwise>Unknown xdt:untypedAtomic</xsl:otherwise>
</xsl:choose>
</xsl:function>
</xsl:stylesheet>
On 6/18/05, Roger L. Costello <costello(_at_)mitre(_dot_)org> wrote:
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>
--~--
--~------------------------------------------------------------------
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>
--~--