15

有没有办法使用 Xpath 1.0 查询 XML 文档以返回给定属性的最大值?

例如有没有办法获得最大 id ?

<?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>
4

7 回答 7

10

在 XPath 2.0 中,使用该max函数。要找到最高的书id,请执行

/library/book[@id = max(/library/book/@id)]
于 2012-01-02T14:43:29.500 回答
5

以下 XPath 选择具有最高 id 的书:

/library/book[not(@id <= preceding-sibling::book/@id) and not(@id <=following-sibling::book/@id)]
于 2012-01-02T14:40:21.153 回答
2

如果您愿意使用外部工具(这取决于您的实现具有这些工具的实现),请尝试EXSLT:Math函数highest()

EXSLT 实现这一点的事实意味着这样的特性在普通的 xpath 中当然不能直接使用。如果您不使用转换,或者只想坚持使用符合标准的标记,其他发帖人的建议将是更好的选择。

于 2012-01-02T14:42:30.690 回答
2

注意:以下信息假定使用 XPath 1.0。

以下表达式返回具有最大值的元素id

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

请注意,这与@timbooo 的答案略有不同,因为当存在具有相同最大值的重复项时,这将返回多个元素(@timbooo 将返回无)。如果在这种情况下您只需要一个元素,那么您需要一个解决策略。要选择文档顺序中的第一个此类元素,请使用以下命令:

/*/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"));

请注意,这只是一个演示;确保在适当的地方包括空检查。

于 2012-01-03T02:05:12.180 回答
2

我发现像 lwburk's 或 timbooo's 这样的答案适用于表示只有一位数字的数字的属性。但是,如果属性是一个多于一位的数字,则在比较属性值时似乎会发生一些奇怪的事情。例如,尝试使用以下内容更改原始 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>

运行建议的片段将不起作用。我使用应用于 id 属性的转换运算符 xs:int() 得到了一个解决方案,例如:

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

那将给出正确答案!

于 2014-01-23T03:04:04.087 回答
1

XPath 1.0

/library/book[not(@id < /library/book/@id)]

这种查询风格更通用,即使书籍被分组也可以工作,即

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

相同的查询仍然有效(应修改路径)

/library/genre/book[not(@id < /library/genre/book/@id)]

甚至

//book[not(@id < //book/@id)]

为避免性能问题,请改用 XPath max()2

于 2019-10-11T13:32:39.867 回答
0

此示例可用于查找最大值。

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-林克/

于 2012-01-02T14:40:02.340 回答