0
votes

I wonder if it's possible to create a query like when using Saxon 9.9HE (addressed by baseX):

let $where := '$x//element[text() = "content"]'
for $x in db:open("my_db")//something
where $where 
return $x//something_else

In my application, the where-clause is built externaly (PHP) based on some conditions and I simply want to pass that to the xquery script so that I can use one base script for all queries, each of which differing in the passed-by where-clause only. Other variables can be passed easily to the script since they contain no path expressions but just skalars.

Is it possible to have an expression in a variable?

I had some tries with xquery:eval() and xquery:parse() (both baseX functions), without success however. The errors mostly are unknown variable $x , context is undeclared , or expecting return If no error occurs, I get ALL elements since the where-clause seems to evaluate to true, thus returning simply everything

My current workaround is to read the xquery script, replace the $where, and execute it then. Is there a nice way to do it in xquery alone?

2
Which XQuery processor exactly do you use? - Martin Honnen
oh, sorry: it's Saxon 9.9HE - meistermuh
But Saxon 9.9 HE doesn't have xquery:eval or xquery:parse functions. - Martin Honnen
it's behind baseX. I updated that in the question. - meistermuh

2 Answers

2
votes

All query insertion and evaluation is subject to the problem of code injection so be careful with that but in BaseX you would need to declare your variable in the prolog of your "where" string expression and then bind it:

let $where := 'declare variable $x external; $x//element[text() = "content"]'
for $x in db:open("my_db")//something
where xquery:eval($where, map { "$x" : $x })
return $x//something_else

It seems safer to simply write a query function or module and use that instead of constructing code as strings.

0
votes

In Saxon the equivalent is

let $where := '$p1//element[text() = "content"]'
for $p1 in $collection//something
where saxon:evaluate($where, $x)
return $p1//something_else

The variable MUST be named $p1. saxon:evaluate expects an XPath expression, not an XQuery expression, so there must be no prolog (i.e. no variable declaration).

Like other Saxon extensions, saxon:evaluate() requires Saxon-PE or higher.

There's a rather convoluted way to do this without extension functions, provided the processor has a usable implementation of the XPath 3.1 fn:transform() function. You wrap the dynamic expression in a stylesheet:

let $ss := "<xsl:transform....><xsl:function name='Q{zzz}predicate' as='xs:boolean'><xsl:param name="p"><xsl:sequence select='$p/" + $condition + "'/></xsl:transform>"

and then to evaluate the condition you use

fn:transform(map{'stylesheet-string':$ss, 'initial-function':QName('zzz', 'predicate'), 'function-params':map{QName('','p'):$x}})?output