[xquery-talk] some ... satisfies with positional variable

Benedikt Linse linse at cip.ifi.lmu.de
Sat Aug 20 00:57:39 PDT 2005


Dear Tim,

> Dear Benedikt,
>
> if I catch your intention right, you wish to return the context node if
> and only if it has a child with some tag "tag0" at a position greater
> than 3 among all the children (that's what the later queries seem to
> indicate) and all that in XQuery Core, i.e., the fragment used in the
> XQuery Formal Semantics, right? Since positional predicates are not
> allowed in XQuery Core, you can't use
>
>     .[child::*[3][name() = "tag0"]]
> or
>     if (child::*[3][name()="tag0"]) then . else ()


That's exactly, what I meant. Just that the important point is, that I
would like to use a positional variable in the condition of a satisfies
clause.

>
> But you can express that, e.g., using nested FLWOR expressions:
>
>     if (not(empty(for $child at $pos in child::* return $child where
> $pos > 3 and fn:node-name($child) eq "tag0"))) then . else ()
>
> In the surface syntax you can, of course, leave out the not(empty()) as
> the "effective boolean value" for sequences is defined this way.
>

This would yield the results that I was looking for, however, I was
wondering if there is a more efficient way to formulate this query.

Obviously, a some-satisfies-clause can be implemented more efficiently
than a for-clause, because it only needs to check for the existence of a
value that satisfies the given condition. In contrast, the for-clause is
bound to return all values satisfying an optional where clause.

So while the intended results are returned using your expression (or my
version with "." instead of "$fs:dot"), a straightforward implementation
of XQuery would carry out dispensible work, right?

> Or, if you wanted to test that there are more than 3 tag0 children

No, your first guess was right.

> (that's what your first query does)
> Or, if you wanted to test that there are more than 3 tag0 children
> (that's what your first query does), you could use
>     if(count(child::tag0) > 3) then . else ()
> or (if you don't like count)
>    if (not(empty(for $child at $pos in child::tag0 return $child where
> $pos > 3))) then . else ()

The correct version of my first expression returns the parent nodes
((number of children) - 3) times, but you could not know the correct
version :-). Here it is:

Expr1 =

let $x := doc("foo.xml")/bar return
    for $y at $pos in $x/child::* return
        if ($pos > 3) and (fn:node-name($y) == "tag0) then $x else ()

As you explained, this could also be achieved by the use of the count
function, but I do not want to lose the positional variable, because I
need it in nested for clauses on a deeper level (in the then part of the
if-clause).

Maybe I just should not care so much about optimization and go for the
for-clauses...

Benedikt

>
> Best regards,
>
> --
> Tim Furche, <http://www.furche.net>,
> research assistant REWERSE <http://rewerse.net>
>
> Benedikt Linse wrote:
>
>>Hello,
>>
>>Here's a question about an XQuery language construct I would appreciate.
>>
>>in for-clauses it is possible to include a positional variable and return
>>the context node $fs:dot - or any other node - based on the position of
>>its child elements.
>>
>>for $x at $pos in child::tag0 return
>>    if ($pos > 3) then return $fs:dot
>>
>>If the context node has more than 4 children, the above expression will
>>return it more than once. This could be avoided by wrapping the result in
>>a distinct-doc-order function, but it wouldn't prevent the compiler from
>>executing extra work, does it?
>>
>>Without positional variables extra work can be evaded by using the some
>>... satisfies ... clause:
>>
>>if (some $x in%



More information about the talk mailing list