XQuery and XPath subscripting

Today I took a long time, together with folks from the eXist-DB Community (thanks Luca Guariento and line0 for the brainstorming), to figure out why a function was receiving a node sequence instead of a single node.

The question was why using this code was not working:

for $entry in functx:distinct-nodes($entries)
    let $term := $entry//tei:orth[1]
    let $lcterm := fn:lower-case($term/text())

And fn:lower-case was complaining for receiving a sequence of nodes, instead of a single one. Our main dig was looking into the structure of the orth tag, and their contents. But we were looking into the wrong side of the road. It was interesting to learn some more details on XQuery, but it did not help on understanding the problem.

Some time later, I tried this one, and it looked like it was working:

for $entry in functx:distinct-nodes($entries)
    let $term := ($entry//tei:orth)[1]
    let $lcterm := fn:lower-case($term/text())

But it was not clear why. How the parenthesis are relevant? I tried a couple of small documents, and the usage of the parenthesis or not was not making any difference.

It took a while until I get to this small example:

xquery version "3.1";

let $x :=
<r>
    <foo>
       <tag>a</tag>
       <bar>
         <tag>b</tag>
       </bar>
    </foo>
    <foo>
        <tag>c</tag>
        <tag>d</tag>
    </foo>
</r>

for $foo in $x//foo
let $ans1 := $foo//tag[1]
let $ans2 := ($foo//tag)[1]
return <ans><a> {$ans1} </a><b> {$ans2} </b></ans> 

The result from this query looks like this:

<ans>
    <a>
        <tag>a</tag>
        <tag>b</tag>
    </a>
    <b>
        <tag>a</tag>
    </b>
</ans>
<ans>
    <a>
        <tag>c</tag>
    </a>
    <b>
        <tag>c</tag>
    </b>
</ans>

Can you notice the difference?

So, basically

$foo//tag[1]  — first tag from any child

($foo//tag)[1] — first tag from the result set

Hope this helps someone.

Leave a Reply