BaseX XQuery error: root(): no context value bound

2.9k views Asked by At

I am trying to run the following XQuery expression in BaseX to extract elements between two succeeding headings. (as an article section).

xquery for $x in doc("test.xq")//h2, 
$y in $x/following-sibling::h2[1]  
return //*[$x/following::* and $y/preceding::*]

But it gives the error

Error:
Stopped at D:/Program Files/BaseX/data/test.xq, 1/74:
[XPDY0002] root(): no context value bound.

By the expression I mean if $x is heading and $y is the first heading following $x, then select the common text for $x/following::* and $y/preceding::*

However I am not sure my expression works, but my question here is how can execute my intended query without error?

If you have also an expression which works for my need, that is welcomed.

2

There are 2 answers

2
Ian Roberts On BEST ANSWER

[...] to extract elements between two succeeding headings [...]

You need something more like:

for $x in doc("test.xq")//h2
return $x/following-sibling::*[preceding-sibling::h2[1] is $x]

but on its own it won't give you anything useful because the XPath and XQuery data model only has flat sequences, not "multi-dimensional arrays". When you have a for that returns a sequence of values for each "iteration", the overall result of the for expression is the concatenation of all the result sequences, so as written above this expression will simply return you all the elements in every "section" in a single flat list. If you want to group the elements by section then you'd need to construct a new XML element for each group

for $x in doc("test.xq")//h2
return
  <section>{$x/following-sibling::*[preceding-sibling::h2[1] is $x]}</section>
2
LarsH On

The error (as documented here) comes from this expression:

//*[$x/following::* and $y/preceding::*]

which begins with //. The abbreviation // stands for /descendant-or-self::node()/, which of course begins with /. The XPath standard says:

A / by itself selects the root node of the document containing the context node. If it is followed by a relative location path, then the location path selects the set of nodes that would be selected by the relative location path relative to the root node of the document containing the context node.

But from what you've shown us, there is nothing indicating that you've established a context node. So XPath doesn't have any way to know what document contains the context node. That's what the error message is referring to when it says

root(): no context value bound

To fix the error, you could precede the // with an explicit doc(...) or any other explicit way to set the context:

doc("test.xq")//*[$x/following::* and $y/preceding::*]

or

root($x)//*[$x/following::* and $y/preceding::*]

This should get rid of the error, but as Ian Roberts has written, it won't give you the result you want. See his answer for that.