1

Let's assume we have the following XML response:

<People>
    <Person>
        <Age>29</Age>
    </Person>
    <Person>
        <Age>25</Age>
    </Person>
    <Person>
        <Age>18</Age>
    </Person>
    <Person>
        <Age>45</Age>
    </Person>
</People>

I want an xpath 2.0 expression that will return true if there is at least one person with age between 18 and 22.

My current expression is:

boolean(//*:Person[xs:integer(substring(//*[local-name() = 'Age']/text(), 2)) >= 18 and 22 >= xs:integer(substring(//*[local-name() = 'Age']/text(), 2))])

But this expression is not recursive so it produces the following error:

A sequence of more than one item is not allowed as the first argument of substring() ("29", "25", ...)

Any idea as to how I can achieve what I need?

xray1986
  • 1,148
  • 3
  • 9
  • 28

3 Answers3

3

In XPath 2.0 this is exists(//Person[Age = (18 to 22)])

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
1

This XPath,

boolean(/People/Person[Age > 18][Age < 22])

will return true iff at least one Person has an age between 18 and 22, exclusive.

Notes:

  • Be sure to use &lt; for < if this XPath is embedded in XML/XSLT.

  • Use >= and/or <= for inclusive endpoints.

  • There is no reason to use local-name() and *: unless you are trying to defeat namespaces, which

    1. are not in play here anyway, but
    2. can and should be accommodated, not defeated.
kjhughes
  • 106,133
  • 27
  • 181
  • 240
  • 1
    you could also use: `boolean(/People/Person[Age[ . > 18 and . < 22]])` – Siebe Jongebloed Jun 01 '23 at 16:03
  • Or `count(/People/Person[Age[ . > 18 and . < 22]]) > 0` ;-) – LMC Jun 01 '23 at 16:34
  • 1
    I have simplified my example by changing data structure to something more understandable and also removing namespaces. I should have also removed local-name() for this example, you are right! – xray1986 Jun 02 '23 at 05:56
0

here's a twisted one that uses count and translate

count(//Age[translate(translate(., "1", "X"),"89","YY") = "XY" or .="22" or translate(translate(., "2", "X"),"01","YY") = "XY"]) > 0

22 is an special case since translate turns it into XX

LMC
  • 10,453
  • 2
  • 27
  • 52