XQuery fn:distinct-values detaches result nodes from context

It turns out that


for $a in fn:distinct-values(input()//tag/text())
return $a/parent::node()

displays “Invalid step in path” error while the next query


for $a in input()//tag/text()
return $a/parent::node()

succeds.

Now, the question: how to output a list of nodes whith distinct child nodes? Is there a workaround?

Does a nested query do what you want? Something like:

let $a := distinct-values(input()//tag/text())
for $b in input()//tag
where $b/text() = $a
return $b/…

Nope, there should be as many $b/… as $a in the result. That is, I need one $b/… for every distinct $a.

Anyway, I solved the problem for my particular case but I can not see a generic solution for the above problem.

The question is also, why to detach the attributes at all? The spec is pretty clear on this subject.

I suppose that may in the second quote does not mean that the parent::node() is optional for the implementation but that the attribute can exist unattached, without being a child of any node per se, as when manipulating DOM structures.

Hi Alexander,

though I don’t completely understand what you are trying to do, I can tell you
why your first query fails.
input()//tag/text() seletcs text nodes (no attributes) and distinct-values is a
function working on atomic values (not nodes). Thus when applying the function
upon the node set the nodes are converted to strings. The result of distinct-values
is a sequence of strings and a string is no proper expression to begin a path with.

Regards,
Juliane.

Yes, Juliane, I used the word “attributes” when I had to use “text nodes”.

As for your explanation, I see that I was wrong in thinking that fn:distinct-values() returns a set of text nodes.

But I finally figured out a generic solution for my problem by using the implicit loop in the XPath comparaison:

for $a in distinct-values(input()//tag/text())
let $b := input()//tag[text()=$a]
  return $b[1]/..

This returns one tag/parent::node() for every distinct //tag/$text().

Hi,

One general remark to your query that might be of public interest: Don’t use the “text()” node test for extracting values from elements or attributes! Please use the data() function, which is the function of choice for extracting the typed value from a given node. In contrast to the data() function the “text()” node test does something weird. You might get some surprisingly results if you apply it for example on mixed-content nodes. Moreover the XQuery draft specifies that during a call of a function that expects a simple type value, node arguments are automatically converted. This particularly holds for the distinct-values() function. This means you can state your query like this:

for $a in distinct-values(input()//tag)
let $b := input()//tag[.=$a]
return $b[1]/…

Like the query shows you also do not have to apply the “text()” node test for doing comparisons.
Beside the sometimes weird results a major drawback of the “text()” node test is that you are loosing all type information. Especially you are using all the information of existing indexes which are defined on element and attribute nodes not on text nodes.

Best Regards,

Thorsten