0
votes

Hi I am trying to select XML items using xpath with multiple AND OR operators with no success.

I need to filter where a field equals a certain value and also one ore more other fields equals another value eg.

field1[contains[value1]] and field2[contains[value2]] or field3[contains[value3]] or field4[contains[value4]]

The problem I am having is this still gives result where field one DOES NOT contain value1 because field3 contains value3. I need it to only give results if field1 DOES contain value1 and any one or more of the other fields contain there respective value.

This is what I currently have (note some elements in square brackets are variables)... //item[SubCategory[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),translate('[data:row("Title")]', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'))] and Group[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),translate('[session:naroomaShown]', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'))]|Group[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),translate('[session:moruyaShown]', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'))]|Group[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),translate('[session:batemansShown]', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'))]]

2
FYI, | is not the or operator in XPath. - Tomalak

2 Answers

4
votes

The and operator binds more tightly than or in XPath (see the note at the end of ยง3.4 in the spec), so

cond1 and cond2 or cond3 or cond4

is treated as

(cond1 and cond2) or cond3 or cond4

You need to use explicit parentheses to control the precedence

cond1 and (cond2 or cond3 or cond4)

Also, as noted by Tomalak in the comments, the | is not actually the boolean OR operator in XPath, but rather the union operator between node sets. In this particular case it won't make a difference, because for node sets X and Y the boolean value of X or Y (== "either X is not empty or Y is not empty or both") will be the same as the boolean value of X | Y (== "the set which is the union of all the nodes in X and all the nodes in Y is not empty") but they are different operators.

0
votes

Here's the correct way to structure (and a nicer way to format) your entire expression:

//item[
  SubCategory[
    contains(
      translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),
      '[data:row("title")]'
    )
  ]
  and Group[
    contains(
      translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),
      '[session:naroomashown]'
    )
    or contains(
      translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),
      '[session:moruyashown]'
    )
    or contains(
      translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),
      '[session:batemansshown]'
    )
  ]
]

There is no need to call translate() on fixed values like '[session:batemansShown]'. Just use lowercase right from the start.