2009-07-15 1 views
27

Если у меня есть XML, как:Как я могу использовать XPath для поиска минимального значения атрибута в наборе элементов?

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

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

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

ответ

16

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

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

Maximum :

/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 или муравей с cripts, не забудьте закодировать < и > как &lt; с учетом &gt;.

+0

хорошая работа! Сначала я попробовал решение с наивысшим рангом, но это не исключает дублирования максимумов/минимумов. – udo

5

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

max(foo/bar/@score) 

... и ...

min(foo/bar/@score) 

... проверить это function reference.

+0

Ok. Это XPath 2.0, я проверю его. – brasskazoo

+0

Да, XPath 2.0. –

3

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

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

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

36

Вот несколько более короткое решение.

Максимум:

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

Минимум:

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

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

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

+0

Прохладный ... но я не могу гарантировать, что не будет (например) нескольких максимальных значений 'score'. Это будет отображать значение для каждого элемента, содержащего максимум. – brasskazoo

+1

Истинный - отредактирован для учета этого. –

+0

Возможно, вы хотите использовать 'number (.)', Потому что в противном случае он сравнивает строковые значения атрибутов. Я прав? – DanSkeel

4

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

Выходы наименьшее значение, конечно, вы можете выбрать для вывода @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

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

Нечто похожее на это сработало для меня в XSLT 2.0.

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

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

Здесь рабочий XPath/XQuery:

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