6

I am trying to get the text elements of a table that follows a paragraph that contains a specific text element using XQuery on MS SQL Server. The problem is whenever I use the axes "following", "following-sibling" or "previous-sibling", I get an error saying this is not supported in SQL Server (I'm using version 2008). So for instance, I can get the first paragraph node that contains a text node whose value is "blah":

//w:p[descendant::w:t = "blah"]

And I can get the text from a table element using:

//w:tbl//w:t/text()

I don't see any way I can force the query to only return the first table element that follows the previously captured paragraph node since:

//w:tbl[following:://w:p//w:t = "blah"]//w:t/text()

Gives the error: "XQuery [Specification.document.query()]: The XQuery syntax 'following' is not supported."

And the same for:

//w:tbl[following-sibling::w:p[descendant::w:t = "blah"]]//w:t/text()

Gives "XQuery [Specification.document.query()]: The XQuery syntax 'following-sibling' is not supported."

That ain't right, y'all know! XPath has supported following and following-sibling since 1.0 back in 1999 AFAICT so MS SQL Server seems to be severely deficient in terms of standard compliance but either way, does anyone see a way I can do this without those axes? Thanks in advance!

TimeHorse
  • 510
  • 3
  • 14
  • Your expression: `//w:tbl[following:://w:p//w:t = "blah"]//w:t/text()` is not syntactically legal XPAth expression. This has nothing to do with "following". – Dimitre Novatchev Jul 14 '10 at 01:12
  • What about: `//w:tbl[preceding-sibling::w:p[descendant::w:t = "blah"]]//w:/text()` I know that is valid since it works in the .NET Framework. But not in SQL Server. Seems to me SQL server is XPath non-conformant. – TimeHorse Jul 15 '10 at 14:31

1 Answers1

7

Document order of nodes in XQuery can also be evaluated by using node comparison operators.

Operator >> applies to two nodes and returns true if the left hand side node follows the right hand side node in document order. For solving your problem, you'd select the first such node.

In the following code, $blah and $text are the given expressions. The returned value is the first node in $text that follows the first node in $blah.

let $blah := //w:p[descendant::w:t = "blah"]
let $text := //w:tbl//w:t/text()
return $text[. >> $blah[1]][1]

Or, combined into a single expression,

(//w:tbl//w:t/text()[. >> (//w:p[descendant::w:t = "blah"])[1]])[1]
Gunther
  • 5,146
  • 1
  • 24
  • 35
  • I don't have SQL Server installed anymore but will trust your work-around and so here's a solution point for you! Thanks for your help! – TimeHorse Apr 09 '13 at 21:02
  • It was a strange debate in the early days of the XQuery working group when the database vendors wanted to drop the "backwards" axes like "preceding" and "ancestor" (which were already present in XPath 1.0). They argued that these axes were very inefficient. Then they argued that the functionality could be achieved in a different way using `<<` and `>>`. Others pointed out that if that were the case, the optimiser could rewrite the axes to use the alternative formulation. But somehow, they weren't persuaded. – Michael Kay Jul 05 '21 at 10:35