有没有办法查询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>
答案 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()