Как найти атрибут max из документа XML с использованием Xpath 1.0 - PullRequest
10 голосов
/ 02 января 2012

Есть ли способ запросить документ XML, чтобы вернуть максимум заданного атрибута, используя Xpath 1.0?

Например, есть ли способ получить максимальный идентификатор?

<?xml version="1.0" encoding="utf-8"?>
<library>
        <book id="2" name="Dragon Tatoo"/>
        <book id="7" name="Ender's Game"/>
        <book id="3" name="Catch 22"/>
        <book id="1" name="Lord of the rings"/>
</library>

Ответы [ 6 ]

7 голосов
/ 02 января 2012

В XPath 2.0 используйте функцию max. Чтобы найти книгу с самым высоким id, выполните

/library/book[@id = max(/library/book/@id)]
4 голосов
/ 02 января 2012

Следующий XPath выбирает книгу с наибольшим идентификатором:

/library/book[not(@id <= preceding-sibling::book/@id) and not(@id <=following-sibling::book/@id)]
2 голосов
/ 03 января 2012

Примечание: Следующая информация предполагает использование XPath 1.0.

Следующее выражение возвращает элемент (ы) с наибольшим значением id:

/*/book[not(@id < preceding-sibling::book/@id) and 
        not(@id < following-sibling::book/@id)]

Обратите внимание, что это немного отличается от ответа @ timbooo в том, что он вернет более одного элемента, когда есть дубликаты с одинаковым максимальным значением (@ timbooo's не вернет ни одного). Если вам нужен только один элемент в этом случае, вам нужна стратегия разрешения. Чтобы выбрать первый такой элемент в порядке документа, используйте это:

/*/book[not(@id < preceding-sibling::book/@id) and 
        not(@id < following-sibling::book/@id)][1]

Чтобы выбрать последний, используйте это:

/*/book[not(@id < preceding-sibling::book/@id) and 
        not(@id < following-sibling::book/@id)][last()]

Этот подход очень неэффективен (O(n^2)), поскольку он требует, чтобы вы сравнивали каждый элемент с каждым другим потенциальным макс. По этой причине, вероятно, лучше использовать язык программирования хоста, чтобы выбрать максимальный элемент. Просто сначала выберите все элементы book, а затем выберите максимум из этого списка. Это (скорее всего) линейная операция (O(n)), которая была бы заметно быстрее на очень больших документах. Например, в Java (JAXP) вы можете сделать это так:

XPath xpath = XPathFactory.newInstance().newXPath();
NodeList nodes = (NodeList) xpath.evaluate("/*/book", doc,
        XPathConstants.NODESET);
Node max = nodes.item(0);
for (int i = 0; i < nodes.getLength(); i++) {
    int maxval = Integer.parseInt(max.getAttributes()
            .getNamedItem("id").getNodeValue());
    int curval = Integer.parseInt(nodes.item(i).getAttributes()
            .getNamedItem("id").getNodeValue());
    if (curval >= maxval)
        max = nodes.item(i);
}
System.out.println(max.getAttributes().getNamedItem("name"));

Обратите внимание, что это просто демонстрация; при необходимости обязательно включите нулевые проверки.

2 голосов
/ 02 января 2012

Если вы хотите использовать внешние инструменты - которые зависят от вашей реализации с использованием этих инструментов - попробуйте функцию EXSLT: Math highest().

Тот факт, что EXSLT реализует это, подразумевает, что такая функция напрямую не доступна в обычном xpath, конечно. Если вы не используете Transforms или хотите просто придерживаться разметки, соответствующей стандартам, лучше подойдут предложения других авторов.

1 голос
/ 23 января 2014

Я обнаружил, что ответы, такие как работа lwburk или timbooo, отлично подходят для атрибутов, представляющих числа, имеющие только одну цифру. Однако, если атрибут представляет собой число, имеющее более одной цифры, при сравнении значений атрибутов могут возникать странные вещи. Например, попробуйте изменить исходные данные XML следующим образом:

<?xml version="1.0" encoding="utf-8"?>
<library>
        <book id="250" name="Dragon Tatoo"/>
        <book id="700123" name="Ender's Game"/>
        <book id="305" name="Catch 22"/>
        <book id="1070" name="Lord of the rings"/>
</library>

Запуск предложенных фрагментов не будет работать. Я получил решение, используя оператор приведения xs: int (), примененный к атрибуту id, как в:

/library/book[not(xs:int(@id) <= preceding-sibling::book/@id) and not(xs:int(@id) <=following-sibling::book/@id)]

Это даст правильный ответ!

0 голосов
/ 02 января 2012

Этот пример может быть использован для поиска макс.

XmlDocument doc = new XmlDocument();                    
doc.Load("../../Employees.xml");
XmlNode node = doc.SelectSingleNode("//Employees/Employee/@Id[not(. <=../preceding-sibling::Employee/@id) and not(. <=../following-sibling::Employee/@Id)]");
int maxId = Convert.ToInt32(node.Value);

Для других аналогичных тем на xpath и linq посмотрите http://rmanimaran.wordpress.com/2011/03/20/xml-find-max-and-min-value-in-a-attribute-using-xpath-and-linq/

...