2012-01-02 78 views
7

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

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

+1,菠萝:P – 2012-01-02 14:35:06

+0

执行XPath的主机语言是什么?如果您使用的是XPath 1.0(它没有'max'函数),那么首先选择所有元素并在您的PL中查找最大值可能会更快。 – 2012-01-03 01:33:32

+0

我使用Perl 5.10。 – HerbSpiral 2012-01-03 08:53:24

回答

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/

3

以下XPath选择书最高ID:

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

这确实有效,但是表现并不好(当文档中有成千上万的ID时) – HerbSpiral 2012-01-02 15:19:35

+0

+1 - 我重复了你答案的核心,但我只是想在我的答案中提供更多信息,包括一些评论周围散布着什么。 – 2012-01-03 02:09:31

+0

@lwburk没问题;) – timbooo 2012-01-03 15:41:22

2

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

EXSLT实现这一点的事实意味着这样的功能当然不能直接在简单xpath中使用。如果你不使用变换,或者想纯粹遵守标准兼容标记,其他海报的建议将是更好的选择。

7

在XPath 2.0中,使用max函数。为了找到这本书具有最高id,做

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

看起来max函数不是Xpath 1.0的一部分:( – HerbSpiral 2012-01-02 15:07:45

+0

@HerbSpiral:hmm。在XQilla XPath 1.0 compat模式下试过了,它起作用,但也许这不是真正的XPath 1.0。 – 2012-01-02 15:54:37

2

注:以下信息假设使用的XPath 1.0。

下面的表达式返回具有最大id值的元素(S):

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

注意,这仅仅是一个示范;务必在适当的地方包含空值检查。

1

我发现像lwburk's或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)] 

这会给出正确的答案!