Re: [xsl] Re: XSLT 2.0: On xsl:sequence and xsl:copy-of

Subject: Re: [xsl] Re: XSLT 2.0: On xsl:sequence and xsl:copy-of
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Tue, 14 Oct 2003 10:15:09 +0100
Hi Dave,

>> > Assuming such a cast is viable/allowed, any use of $foo will be as a
>> > decimal thereafter in the stylesheet?
>> 
>> The value of the variable is an xs:integer, and it will remain so:
>> the xs:integer isn't cast to a xs:decimal because an xs:integer can
>> always be used where a xs:decimal is expected because xs:integer is
>> a subtype of xs:decimal.
>
> ... In which case the as attribute is redundant.. unless I 'invent'
> content (i.e. use a literal) since I can't change the type (my
> 'cast' idea above) using the as attribute.
>
>   I.e. any xsl:variable which contains source document content will 
> 'determine its own data type' irrespective of the as attribute? 
>   The user concern only needs to be that our 'as' type is a subtype of
> the actual result?

There are three scenarios:

  1. The value that's provided for the variable matches the
     SequenceType specified in the 'as' attribute. In this case, the
     value is fine as it is and that value is used as the value of the
     variable. The case where you provide an xs:integer as the value
     of a variable that's declared as an xs:decimal is an example.

  2. The value that's provided for the variable does not match the
     SequenceType specified in the 'as' attribute, but can be
     implicitly cast to the appropriate type. In this case, the value
     is cast to the appropriate type and that value is used as the
     value of the variable. An example is if (in basic XSLT) you
     provide an attribute as the value of a variable that's declared
     as a xs:decimal; the value of the attribute is cast to a
     xs:decimal, and that is the value of the variable.

  3. The value that's provided for the variable does not match the
     SequenceType specified in the 'as' attribute, and cannot be
     implicitly cast to the appropriate type. In this case, you get an
     error. An example is if you provide a xs:string as the value of a
     variable that's declared as an xs:decimal.

So, you *can* use the 'as' attribute to do implicit casting. In XPath
2.0, the only implicit casting that goes on is from xdt:untypedAtomic
values, which come from untyped nodes. (Text nodes are always untyped;
nodes in basic XSLT are always untyped.) For example:

  <xsl:variable name="foo" type="xs:decimal">2</xsl:variable>

actually implicitly casts the xdt:untypedAtomic value of the text node
generated through the content of the <xsl:variable> element to the
type xs:decimal. Another example; in basic XSLT:

  <xsl:variable name="date" type="xs:date" select="@dob" />

implicitly casts the xdt:untypedAtomic value of the dob attribute to
an xs:date -- the variable $date actually holds a date, not a dob
attribute. In comparison, if you just had:

  <xsl:variable name="date" select="@dob" />

then the value of the variable is a single attribute node.

What you can't do is:

  <xsl:variable name="foo" type="xs:decimal" select="'2'" />

and expect the XSLT processor to cast the xs:string '2' to an
xs:decimal.

Using the 'as' attribute on <xsl:variable> (and the other
variable-binding elements) is good practice because it catches some
dumb errors and helps document your stylesheet. It's also essential if
you want to use the content of the variable-binding element to set the
variable to something other than a temporary tree. But in most cases
it doesn't do casting: you have to do that yourself.
     
>> >> As long as the dynamic type (the type of the value that the
>> >> variable gets set to) is a subset of the static type (the type of
>> >> the variable as declared by the 'as' attribute), you're OK.
>> >
>> > 'Can be cast to' I guess.
>> 
>> Well, "matches" would be the correct terminology, I guess. I should
>> rephrase to:
>> 
>>   "As long as the value the variable gets set to matches the static
>>    type, you're OK."
>
> Is your 'is a subtype of' still a valid alternative Jeni?

I think that we should only use 'is a subtype of' when talking about
the relationships between two atomic data types. So it's true to say
that xs:integer is a subtype of xs:decimal, but it's not true to say
that an xs:integer is a subtype of the SequenceType "xs:decimal+".

>> > Is there a difference (to a user) between sequence types and data
>> > types?
>> 
>> The term "data type" is usually used to refer to atomic data types
>> such as xs:decimal, xs:date and so on. A "sequence type" refers to
>> the type of a sequence, such as "one or more elements". So yes,
>> there is a meaningful difference.
>
> Is this a break point between xsd and xslt+xpath? 
> We pull data types from XSD, then add sequence types?

XSD defines "simple types", which can be atomic, lists or unions.
XPath 2.0 only really talks about atomic data types. I guess that
SequenceTypes are similar to list types in XSD, but they are both less
powerful (you can't talk precisely about how many items are allowed in
the sequence) and more powerful (you can talk about sequences of nodes
as well as sequences of atomic values).

>  I was checking my understanding of the nesting?
>   Is it the 'subtype' mentioned above?
>     E.g. you had 
>              "a node()
>                 "element()
>                    "element(Name, Type)
>
> Can I read that as element is a subtype of node,

No, you can't read the list like that. But it is true that an element
node would match a SequenceType of "node()".

>     the last line I'm less sure of.
>     What's the 'type' (is it one from int, decimal, string etc,
>        referring to the element content?)

The last line being:

>     - an atomic type, which can be any QName; common ones are:
>       - "xdt:anyAtomicType"
>       - "xs:string"
[snip]

I'll try to explain it more, but I'm not sure what bit you don't
understand.

The way to create SequenceTypes that match atomic values, such as the
xs:integer 2, is to give the name the atomic data type of the atomic
value. For example, the SequenceType "xs:decimal" matches atomic
values of the type xs:decimal or any of xs:decimal's subtypes (such as
xs:integer).

Atomic values are usually the result of some expression (such as 2+2),
but you can also get them by accessing the typed value of a node,
either explicitly using the data() function or implicitly by supplying
the node when an atomic value is expected (e.g. in 2 + @value).

Cheers,

Jeni

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


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


Current Thread