Conditional predicate
Suggested by a post in the
eXist mailing list .
The task is to select a subset of items with a conditonal filter.
Setup test data
This is just a snippet of data. More realistically this would be a large document which was indexed.
XQuery
<data>
<r type="a">
<activity>A</activity>
</r>
<r>
<activity>X</activity>
</r>
<r type="b">
<activity>B</activity>
</r>
<r type="c">
<activity>C</activity>
</r>
<r type="a">
<activity>AA</activity>
</r>
<r type="b">
<activity>BB</activity>
</r>
<r type="c">
<activity>CC</activity>
</r>
<r>
<activity>Y</activity>
</r>
</data>
Result
<data>
<r type="a">
<activity>A</activity>
</r>
<r>
<activity>X</activity>
</r>
<r type="b">
<activity>B</activity>
</r>
<r type="c">
<activity>C</activity>
</r>
<r type="a">
<activity>AA</activity>
</r>
<r type="b">
<activity>BB</activity>
</r>
<r type="c">
<activity>CC</activity>
</r>
<r>
<activity>Y</activity>
</r>
</data>
suggested by Roy Walter
XQuery
let $type := "a"
let $result := $context//activity
let $activities :=
if ( $type ne '' ) then
for $r in $result[../@type=$type]
order by $r descending
return
$r/..
else
for $r in $result[../@type]
order by $r descending
return
$r/..
return $activities
Result
<r type="a">
<activity>AA</activity>
</r>
<r type="a">
<activity>A</activity>
</r>
suggested by Joe Wickentowski
XQuery
let $type:= "a"
let $result := $context//activity
let $filtered-results :=
if ( $type ne '' ) then
$result[../@type=$type]
else
$result[../@type]
let $activities :=
for $r in $filtered-results
order by $r descending
return
$r/..
return $activities
Result
<r type="a">
<activity>AA</activity>
</r>
<r type="a">
<activity>A</activity>
</r>
if expression in predicate from Adam Retter
The conditional expression can be used in a predicate but this would inhibit any indexes defined.
XQuery
let $type:= "a"
let $result := $context//activity
let $activities :=
for $r in $result[if($type ne '') then ../@type = $type else exists(../@type)]
order by $r descending
return
$r/..
return $activities
Result
<r type="a">
<activity>AA</activity>
</r>
<r type="a">
<activity>A</activity>
</r>
higher-order function from Adam Retter
XQuery
let $type:= "a"
let $result := $context//activity
let $result-fn :=
if($type ne '')
then function($t) { $t eq $type }
else function($t) { exists($t) }
return
for $r in $result[$result-fn(../@type)]
order by $r descending
return
$r/..
Result
user defined function from Chris Wallace
user defined functions can be used in a path expression but this would also inhibit index usage.
XQuery
declare function local:select($r,$type) {
if($type ne '')
then $r/../@type eq $type
else exists($r/../@type)
};
let $type:= "a"
let $result := $context//activity
return
for $r in $result[local:select(.,$type)]
order by $r descending
return
$r/..
Result
<r type="a">
<activity>AA</activity>
</r>
<r type="a">
<activity>A</activity>
</r>
util:eval from Chris Wallace
if there is a complex conditional predicate where we need to make best use of
the indexes, then we canconstruct the expression as a string and use util:eval to evaluate it. In this simple example, the execution line is longer
XQuery
let $type:= "a"
let $result := $context//activity
let $filter := concat("$result",if ($type ne "") then "[../@type = $type]" else "[exists(../@type)]")
return
for $r in util:eval($filter)
order by $r descending
return
$r/..
Result
<r type="a">
<activity>AA</activity>
</r>
<r type="a">
<activity>A</activity>
</r>