Как я могу использовать XPath, чтобы найти минимальное значение атрибута в наборе элементов? - PullRequest
29 голосов
/ 15 июля 2009

Если у меня есть XML как:

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

Могу ли я использовать XPath, чтобы найти минимальное и максимальное значения score?

Редактировать : инструмент, который я использую ( Andariel задачи муравья) не поддерживает решение XPath 2.0.

Ответы [ 6 ]

39 голосов
/ 15 июля 2009

Вот немного более короткое решение.

Максимум:

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

Минимум:

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

Я отредактировал предикат, чтобы он применим к любой последовательности bar, даже если вы решите изменить путь. Обратите внимание, что родителем атрибута является элемент, которому он принадлежит.

Если вы встраиваете эти запросы в файлы XML, такие как XSLT или ant-скрипты, не забывайте кодировать < и > как &lt; с учетом &gt;.

19 голосов
/ 15 июля 2009

Оказывается, инструмент не поддерживает XPath 2.0.

XPath 1.0 не имеет причудливых функций min() и max(), поэтому, чтобы найти эти значения, нам нужно немного хитрить с логикой XPath и сравнить значения на элементах узла:

Максимум:

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

Минимальные требования:

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

Если вы встраиваете эти запросы в XML-файлы, такие как XSLT или ant-скрипты, не забудьте закодировать < и > как &lt; относительно &gt;.

6 голосов
/ 15 июля 2009

Это должно работать ...

max(foo/bar/@score)

... и ...

min(foo/bar/@score)

... проверить эту ссылку на функцию .

4 голосов
/ 30 мая 2012

Я наткнулся на ветку и не нашел ответ, который работал для меня, так где же я в конечном итоге использовал ...

Выводит наименьшее значение, конечно, вы можете выбрать вывод @id из узла с наименьшим значением вместо того, чтобы выбрать.

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

То же самое для максимального значения:

<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>
3 голосов
/ 18 ноября 2013

Я знаю, что это пять лет. Просто добавьте еще несколько вариантов для тех, кто может искать и сталкиваться с этим.

Что-то похожее на это работало у меня в XSLT 2.0.

min(//bar[@score !='']/@score)

!='' должен был избегать нулей, которые приводили к значениям NaN (возможно, есть лучший способ сделать это)

Вот рабочий xpath / xquery:

//bar/@score[@score=min(//*[@score !='']/number(@score))]
3 голосов
/ 15 июля 2009

Попробуйте это:

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

Может быть, это будет работать на XPath 1.0.

...