An XQuery Sequence question

Author: Dave Cassel  |  Category: Software Development

A while ago I was posed a question by a colleague:

(1,3,2)[.] -> 1
(1,2,3)[.] -> 1 2 3
(2,3,4)[.] -> no result
why?

To find the answer, we need to think about what’s happening in the brackets. As discussed in one of my earlier posts, the expression in brackets gets evaluated once for each item in the sequence. The result of that evaluation on each item determines whether that item gets selected.

My initial thought was that the answer to this question was pretty simple: the “.” refers to “self”, the current item being evaluated, and the evaluation used the value of the current item. That gets us a number, which when used as a filter expression for a sequence, indicates the index of the item we want to select. We can expand the example above to this:

(1, 3, 2)[fn:data(.) eq fn:position()]

Now it’s pretty clear why we get just (1) as our answer — for this case, 1 is the only item where the value matches the position.

But wait, the plot thickens! XQuery allows us to throw mixed types of items into a sequence. What do we get from this:

(1, <a/>, 3, 2, “blah”)[.]

The answer is (1, <a/>, 3, “blah”). The expansion I gave above doesn’t hold here, because we can’t compare fn:data(<a/>) and fn:position() — I get an error about trying to compare an xs:untypedAtomic(“”) to a number. So what really happens? To find out, I turned to MarkLogic’s own John Snelson, whose familiarity with the XQuery spec is a good deal deeper than mine. Here’s what I found out:

The implicit operation in the predicate is more like this:

typeswitch(.)
case xs:decimal | xs:float | xs:double return . eq position()
default return fn:boolean(.)

The fn:boolean() function returns true for a sequence containing a single node – so the constructed node in your last example passes the predicate. Similarly, a non-zero length string returns true from fn:boolean().

So there we have it. If the value is a number, it’s compared to the position. If it’s not a number, we check whether the value is, to borrow from Douglas Crockford, “truthy”. More precisely, XQuery finds the Effective Boolean Value for the context item and uses that to decide whether the item in the sequence should be returned by the filter expression.

Tags:

One Response to “An XQuery Sequence question”

  1. Joe Says:

    Great post! Thanks so much. More XQuery “puzzlers”, please!

Leave a Reply