[xquery-talk] variable references in location steps

Michael Kay mike at saxonica.com
Fri Feb 25 09:45:36 PST 2011

Let's simplify this down to essentials: what does //a/$e return when $e 
is a sequence of nodes? (We'll assume $e contains no duplicates and is 
in document order.) The answer is, it returns $e. Technically, it 
evaluates $e once for each node in //a, combines the results and sorts 
them into document order and eliminates duplicates; and the result of 
doing that is the original value of $e.

You seem to be working on the assumption that $e is not a set of nodes, 
but some kind of function or expression which only reduces to a set of 
nodes when it is called, and that it can return different sets of nodes 
depending on the context when it is called. That's not the case. 
Evaluation might well be deferred until first use, but the context for 
evaluation is the context at the point where the variable is 
initialized, not the context where it is used.

Looks like a serious bug in eXist to me.

Now, what are you trying to achieve? If it's code reuse, you need 
functions. If it's performance, just try to avoid that double "//" in a 
single path expression. I know evaluation strategies for path 
expressions vary between one engine and another, and a leading "//" 
sometimes makes things slower and sometimes faster, but I would imagine 
that repeated use of "//" in a single path will always cause trouble.

Michael Kay

On 25/02/2011 01:17, Ron Van den Branden wrote:
> Hi,
> I'm trying to optimize a complex XQuery expression by defining 
> variables for reused context nodes. Until recently, I assumed that 
> those variable references could be used in location steps as 
> substitution for the nodes they hold, but apparently it doesn't work 
> exactly like that. I'll try to clarify with following XQuery (note: I 
> realize this question is XPath/XSLT related, but since the practical 
> angle is XQuery-oriented, I'll post it here.):
> let $test :=
> <test>
> <a><el1/></a>
> <b><el2/></b>
> </test>
> let $el1 := $test//el1
> let $el2 := $test//el2
> return
> <result>
> <step>
> <el1.a>{$test//a//$el1}</el1.a>
> <el2.a>{$test//a//$el2}</el2.a>
> <el1.b>{$test//b//$el1}</el1.b>
> <el2.b>{$test//b//$el2}</el2.b>
> </step>
> <predicate>
> <a.el1>{$test//a[.//$el1]}</a.el1>
> <a.el2>{$test//a[.//$el2]}</a.el2>
> <b.el1>{$test//b[.//$el1]}</b.el1>
> <b.el2>{$test//b[.//$el2]}</b.el2>
> </predicate>
> </result>
> Developing against the eXist XML database, I assumed that the queries 
> in <el1.a> and <el2.b> would only return the <el1> and <el2> elements 
> in their respective contexts, while <el2.a> and <el1.b> would return 
> nothing. Instead, they all return the respective <el1> and <el2> 
> elements, even for context nodes in which they don't occur (see 
> <el2.a> and <el1.b>). Later I found out that the variable used in this 
> last location step doesn't resolve to the nodes it contains, but 
> instead is interpreted as a filter, which consequently returns the 
> entire nodeset held in the $el1 and $el2 variables (see Jeni 
> Tennison's clarification at 
> <http://markmail.org/message/hss4auv23t6y2ep2>). Note: my assumption 
> came from my experience with the eXist XML database to filter down 
> ancestor nodes containing other nodes by means of a variable reference 
> in a predicate: see the queries in the <predicate> section. In eXist, 
> only <a.el1> and <b.el2> return the respective <a> and <b> elements, 
> while <a.el2> and <b.el1> are empty, which suggests that in this case 
> the variable reference is resolved to the nodes it contains. However, 
> this behaviour apparently differs from Saxon's which also returns the 
> <a> and <b> nodes in <a.el2> and <b.el1>.
> Assuming Saxon is right, this makes me wonder: is my thinking based on 
> an incorrect implementation, or *is* there a way to make use of 
> variable references for filtering down nodesets in location steps?
> Any help much appreciated!
> Kind regards,
> Ron Van den Branden

More information about the talk mailing list