Re: [xsl] [XSLT 2.0] Determining the datatype of the value returned from a function?

Subject: Re: [xsl] [XSLT 2.0] Determining the datatype of the value returned from a function?
From: Dimitre Novatchev <dnovatchev@xxxxxxxxx>
Date: Sat, 18 Jun 2005 07:38:57 +1000
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@xxxxxxxxx> 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>

Current Thread