2012-01-02 112 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)] 

這會給出正確的答案!