Re: [xsl] Re: . in for

Subject: Re: [xsl] Re: . in for
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Sun, 6 Jan 2002 16:24:12 +0000
Hi Dimitre,

>> Absolutely. I suggested a simple mapping operator as a replacement
>> for the more complex for expression that is currently defined in
>> XPath 2.0. I fully recognise the fact that a simple mapping
>> operator gains in simplicity, but loses in completeness - it cannot
>> achieve everything that the for expression can achieve (it can't do
>> joins). I'm sure that you're right that it also cannot achieve
>> everything that a full mapping operator would achieve (perhaps you
>> can give some examples?).
>
> Anything that cannot be achieved by a single XPath expression, but
> can be produced by a template.

Right, so the comment that a simple mapping operator as I suggested
isn't a full mapping operator also applies to the for expression (and
indeed any expression in XPath), since XPath can only do the things
that XPath can do.

> I hope even in XPath 2.0 / XSLT 2.0 this set is still non-empty?

It depends on whether you view calls to extension functions as being
part of XPath 2.0 or not. You can call/apply templates within
extension functions written in XSLT, so you can construct expressions
that work just like calls to/applying templates.

[snip great explanation of how the functions involved in a functional
composition must be written to take into account the fact they are
part of that composition when working on sequences.]

>> My second question is, whether the above issue is manageable or
>> not, whether implementations could be clever enough to spot where
>> the use of simple mapping operators is equivalent to functional
>> composition, in order to optimise these expressions? Perhaps an
>> implementation could recognise that given:
>> 
>>   $coordinates -> (. * 2)
>>                -> if (position() mod 2) then . + 50 else .
>> 
>> it could compose the two steps on the right hand side of the first
>> -> into a single operation, and use that to give added efficiency?
>
> In the general case if an XSLT processor optimizes your previous
> example, replacing it by a single map with the composition of the
> expressions, it will yield the wrong result as your detailed example
> above shows.
>
> Anyway, if one designs his algorithm having the single mapping in
> mind, such an error will not occur -- it only happens when trying to
> mechanically convert a composition of map-s into a single map, and
> only if the mapping functions depend on the cardinality of their
> inputs.
>
> A more correct answer is that a function like position() must not be
> allowed as an argument of a map function/operator. By definition,
> such a function must have as its ***single*** input only an item of
> the sequence. position() goes beyond the single item and actually
> uses the whole sequence as its input.

I see your point about position(). This kinda ties into one of the
points that came out of my reply to Mike's comment about being able to
call user-defined functions from within for expressions, where I
compared:

  <xsl:for-each select="row">
    <row num="{position()}">...</row>
  </xsl:for-each>

to:

  <xsl:copy-of
    select="for $i in (1 to count($rows))
            return my:create-row($rows[$i], $i)" />

with:

<xsl:function name="my:create-row">
  <xsl:param name="row" type="element row" />
  <xsl:param name="position" type="xs:integer" />
  <xsl:result>
    <row num="{$position}">...</row>
  </xsl:result>
</xsl:function>

This illustrates how the value returned by the position() function has
to be replaced by an explicit counter; the same thing goes for the
other information provided by the evaluation context at the point the
function is called - the context size, dynamic variables and so on.
Pure functions only know what they're passed.

Note that replacing the position() function with an explicit counter
means that the $rows sequence has to be traversed several times - once
to count how many items there are in it, and then once for each item
in the $rows sequence in order to retrieve the relevant item for the
function call.

I think that this is likely to be quite inefficient compared to a
single traversal of the $rows sequence, as in xsl:for-each, where
counters are supported by the position() function. So I think that
banning the position() function would be a mistake.

I imagine that a processor would be able to spot situations where the
position() or last() function had been called and only compose the
steps that were composable.
  
>> Fortunately, with the simple mapping operator this works, because
>> in XPath 2.0 individual values are treated exactly the same as
>> single-item sequences.
>
> Where did you read it? I read in 2.1.2 (Type conversions) the
> following:
>
> "1. If the required type is anything other than a simple type or a
> single node, an error is raised."

The second paragraph of Section 6 of the data model WD
(http://www.w3.org/TR/query-datamodel/#sequences) reads:

  "An important characteristic of the data model is that there is no
   distinction between an item (i.e., a node or a simple typed value)
   and a singleton sequence containing that item, i.e., an item is
   equivalent to a singleton sequence containing that item and vice
   versa."

>> I *think* that if you view the series of operations on the right
>> hand side of the simple mapping operator as being functionally
>> composed, then you have the functional composition operator that
>> you're looking for?
>
> If it is allowed to perform on a single item a function defined on a
> sequence, then yes -- because the mapping operator as defined by you
> is just a functional composition of map-s and a map will (if the
> assumption that this is allowed is right) operate on a simple value
> or a node exactly like its argument-function.

Cool :)

Cheers,

Jeni

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


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


Current Thread