Re: [xsl] The Perils of Sudden Type-Safety in XPath 2.0

Subject: Re: [xsl] The Perils of Sudden Type-Safety in XPath 2.0
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Wed, 19 Feb 2003 17:02:33 +0000
Hi Chuck,

> I'm only now starting to play around with XSLT 2.0, so this is a
> question I am posing to you , not an argument. Can you give me an
> example where automatic casting takes place? I tried to create one
> multiplying two values and assumed, based on this thread, it would
> return an integer, but it didn't happen. Can you clarify the
> situation for my muddled mind?

I'm not exactly sure what you're asking for, but here's an example
that illustrates what happens when you multiply two values under XSLT
2.0.

Say you had the following unvalidated (and hence untyped) XML:

  <problem risk="3" severity="4">...</problem>

and you wanted to create a number of exclamation marks equal to the
value of @risk * @severity. @risk and @severity are both always
integers, but the XML is untyped so the XSLT processor doesn't know
this.

Since neither @risk nor @severity is typed, an XSLT 2.0 processor
will assume that since you want to multiply them together they must be
of type xs:double. When you multiply two doubles, the result is a
value of type xs:double. If you try to use a double as an argument or
operand to a function or operator that expects an integer (or indeed
most other types), you will get a type error. For example, if you try
to do:

  <xsl:value-of select="string-pad('!', @risk * @severity)" />

or:

  <xsl:for-each select="1 to @risk * @severity">!</xsl:for-each>

then you will get errors because string-pad() expects an integer as
its second argument and the 'to' operator expects integers for its
arguments.

You have to do one of:

  - add types to your document by validating it against a schema or by
    creating a temporary tree in which the attributes are assigned types
    
  - cast the values to integers explicitly within the code

  - use a variable to create an untyped node containing the value
    which will then be automatically cast to the right type

Explicit casts look like:

  <xsl:value-of select="string-pad('!', xs:integer(@risk * @severity))" />

Creating the variable looks like:

  <xsl:variable name="danger">
    <xsl:value-of select="@risk * @severity" />
  </xsl:variable>
  <xsl:value-of select="string-pad('!', $danger)" />

This latter works because the $danger variable holds the document node
of a tree that contains the value of @risk * @severity. The typed
value of the document node is the value 7 of the type
xdt:untypedAtomic [*]. Since the type is xdt:untypedAtomic, the value
is cast automatically to the required type of xs:integer when the
variable is used.
  
Cheers,

Jeni

[*] I mistakenly talked about the type xdt:anyAtomicType in an earlier
mail when I meant xdt:untypedAtomic.

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread