Tim
Tim

Reputation: 963

xquery matches - allow non existing nodes in loop

I have a for loop and want to filter some nodes, which works fine:

matches($doc/abc/@def, $filterA)
matches($doc/qwert/@xyz, $filterB)

What also works is, when $filterA, $filterB or both are empty, to return every node. What does not work however is to return the node if node abc or qwert do not exist. For the default value i currently use "" (empty string), is there another default value or another function I can use to make it work?

Upvotes: 1

Views: 105

Answers (1)

Mads Hansen
Mads Hansen

Reputation: 66783

You can test whether the abc and qwert elements exist with the fn:exists() function. If you want it to pass if either of those elements do not exist, you can use fn:not() to negate a test for abc and qwert existence:

fn:not(fn:exists($doc/abc) and fn:exists($doc/qwert))

If you want a condition to pass if either $filterA or $filterB is empty:

fn:not(fn:exists($filterA) and fn:exists($filterB)) 

You can consolidate the matches() expressions a predicate to avoid repeating $doc (not a huge savings, but something to think of more generally when writing XPath expressions.

$doc[matches(abc/@def, $filterA) and matches(qwert/@xyz, $filterB)] 

Putting it all together:

let $filterA := "a"
let $filterB :="b"
let $doc := <doc><abc def="a"/><qwert xyz="b"/></doc>
return
  if (fn:not(fn:exists($doc/abc) and fn:exists($doc/qwert))
      or fn:not(fn:exists($filterA) and fn:exists($filterB)) 
      or $doc[matches(abc/@def, $filterA) and matches(qwert/@xyz, $filterB)])
  then "pass - copy nodes"
  else "fail"

Upvotes: 1

Related Questions