How can I use XPath to find the minimum value of an attribute in a set of elements?

38,442

Solution 1

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 >= @score) 
    and not(following-sibling::bar/@score > @score)]/@score

Minimum:

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

If embedding these queries in XML files like XSLT or ant scripts, remember to encode < and > as &lt; respecting &gt;.

Solution 2

Here's a slightly shorter solution.

Maximum:

/foo/bar/@score[not(. < ../../bar/@score)][1]

Minimum:

/foo/bar/@score[not(. > ../../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.

If embedding these queries in XML files like XSLT or ant scripts, remember to encode < and > as &lt; respecting &gt;.

Solution 3

This should work ...

max(foo/bar/@score)

... and ...

min(foo/bar/@score)

... check out this function reference.

Solution 4

I stumbled upon the thread and didn't find an answer that worked for me, so where is what I eventually ended up using...

Outputs the lowest value, of course you could choose to output the @id from the node with the lowest value instead of you choose.

<xsl:for-each select="/foo">
  <xsl:sort select="@score"/>
  <xsl:if test="position()=1">
    <xsl:value-of select="@score"/>
  </xsl:if>
</xsl:for-each>

The same for the maximum value:

<xsl:for-each select="/foo">
  <xsl:sort select="@score" order="descending"/>
  <xsl:if test="position()=1">
    <xsl:value-of select="@score"/>
  </xsl:if>
</xsl:for-each>

Solution 5

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.

Share:
38,442
brasskazoo
Author by

brasskazoo

I am a Software and Cloud Solutions Engineer with a passion for building quality and automation into the development, testing and deployment lifecycles. Currently working with a large AWS hybrid-cloud integration project, including VPC architecting and solution design, serverless applications and shifting applications to EC2. Primarily I work with terraform, node.js, react and java, with side projects currently in react-native and GraphQL for cross-platform mobile applications. Agile, DevOps culture, Code Quality and Continuous Integration are cornerstones of my development efforts.

Updated on November 19, 2020

Comments

  • brasskazoo
    brasskazoo over 3 years

    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.