views:

431

answers:

4

If I have XML like:

<foo>
  <bar id="1" score="192" />
  <bar id="2" score="227" />
  <bar id="3" score="105" />
  ...
</foo>

Can I use XPath to find the minimum and maximum values of score?

Edit: The tool i'm using (Andariel ant tasks) doesn't support the XPath 2.0 solution.

+2  A: 

This should work ...

max(foo/bar/@score)

... and ...

min(foo/bar/@score)

... check out this function reference.

JP Alioto
Ok. This is XPath 2.0, I will check it out.
brass-kazoo
Yes, XPath 2.0.
JP Alioto
+1  A: 

Try this:

//foo/bar[not(preceding-sibling::bar/@score <= @score) and not(following-sibling::bar/@score <= @score)]

Maybe this will work on XPath 1.0.

kuy
+3  A: 

Turns out the tool does not support XPath 2.0.

XPath 1.0 doesn't have the fancy min() and max() functions, so to find these values we need to be a little tricky with the XPath logic, and compare the values on the siblings of the node:

Maximum:

/foo/bar[not(preceding-sibling::bar/@score &gt;= @score) 
    and not(following-sibling::bar/@score &gt; @score)]/@score

Minimum:

/foo/bar[not(preceding-sibling::bar/@score &lt;= @score) 
    and not(following-sibling::bar/@score &lt; @score)]/@score
brass-kazoo
+3  A: 

Here's a slightly shorter solution.

Maximum:

/foo/bar/@score[not(. &lt; ../../bar/@score)][1]

Minimum:

/foo/bar/@score[not(. &gt; ../../bar/@score)][1]

I've edited the predicate so that it's applicable to any sequence of bar, even if you decide to change the path. Note that parent of attribute is the element to which it belongs.

Pavel Minaev
Cool...but I can't guarantee that the there won't be (for example) multiple maximum values of `score`. This would list a value for each element that contained the maximum..
brass-kazoo
True - edited to account for that.
Pavel Minaev