3

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.

LarsH
  • 27,481
  • 8
  • 94
  • 152
Ahmad
  • 8,811
  • 11
  • 76
  • 141
  • You may want to use `group-by` (http://www.w3.org/TR/xquery-30/#id-group-by), e.g. `group by preceding-sibling::h2[1]`. – LarsH Jun 09 '15 at 15:36

2 Answers2

3

[...] 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>
Ian Roberts
  • 120,891
  • 16
  • 170
  • 183
  • Thank you! your answer and @LarsH are complementary, you may like to include some parts of it or address his answer in your answer. – Ahmad Jun 09 '15 at 16:25
  • Before I ask about the error origin here, I had a similar question http://stackoverflow.com/questions/30710968/xpath-or-xquery-to-exclude-article-sections-which-only-contains-lists, in which another condition for the sections was required, could you please check it too, sorry, if I seem so naive – Ahmad Jun 09 '15 at 16:44
1

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.

LarsH
  • 27,481
  • 8
  • 94
  • 152
  • Thank you. you mean the document should be specified, if the query is not trace back to the root through a variable? Your answer and the Ian are complementary and answer the question, don't know which to accept. – Ahmad Jun 09 '15 at 16:22
  • Ahmad, if there is no context node, then you can't used an XPath expression starting with `/`. You could use `doc(...)/...`, or `root($x)/...`, or something of that sort. You asked two questions; I answered the first, and Ian the second. I suspect Ian's answer is of more practical value to you. I won't object if you accept his. :-) – LarsH Jun 09 '15 at 18:37