如何使用Xpath 1.0从XML文档中查找max属性

时间:2012-01-02 14:33:17

标签: xml xpath xpath-1.0

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

例如,有没有办法获得最大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>

7 个答案:

答案 0 :(得分:7)

在XPath 2.0中,使用max函数。要查找具有最高id的图书,请执行

/library/book[@id = max(/library/book/@id)]

答案 1 :(得分:4)

以下XPath选择ID最高的图书:

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

答案 2 :(得分:2)

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

EXSLT实现这一点的事实意味着当然不能在普通的xpath中直接使用这样的功能。如果你没有使用变形,或者想要坚持使用符合标准的标记,那么其他海报的建议将是更好的选择。

答案 3 :(得分:2)

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

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

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

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

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

请注意,这只是一个示范;请务必在适当的地方加入空值检查。

答案 4 :(得分:1)

我发现像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>

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

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

这将给出正确的答案!

答案 5 :(得分: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-linq/

答案 6 :(得分:0)

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 2 max()