2012-01-02 9 views
7

Esiste un modo per eseguire una query su un documento XML per restituire il massimo di un determinato attributo utilizzando Xpath 1.0?Come trovare l'attributo max da un documento XML utilizzando Xpath 1.0

Ad esempio c'è un modo per ottenere l'ID max?

<?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, per l'ananas: P –

+0

Qual è la lingua host per l'esecuzione dell'XPath? Se stai usando XPath 1.0 (che non ha una funzione 'max'), probabilmente è più veloce selezionare prima tutti gli elementi e trovare il massimo nel tuo PL. –

+0

Sto usando Perl 5.10. – HerbSpiral

risposta

0

Questo esempio può essere utilizzato per trovare il massimo.

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); 

Per altri argomenti simili su XPath e LINQ controllare http://rmanimaran.wordpress.com/2011/03/20/xml-find-max-and-min-value-in-a-attribute-using-xpath-and-linq/

3

Il seguente XPath sceglie il libro con la più alta id:

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

Questo funziona davvero, tuttavia le prestazioni non sono così buone (quando sono presenti migliaia di ID nel documento) – HerbSpiral

+0

+1 - Ho ripetuto il nocciolo della tua risposta, ma volevo solo fornire ulteriori informazioni nella mia risposta, incluse alcune di cosa è stato diffuso intorno ai commenti. –

+0

@lwburk Nessun problema;) – timbooo

2

Se siete disposti a utilizzare attrezzature esterne - che dipende dalla tua implementazione con implementazioni di questi strumenti: prova la funzione EXSLT:Mathhighest().

Il fatto che EXSLT implementa questo implica che tale funzione non è direttamente disponibile in plain xpath, ovviamente. Se non stai usando Transforms, o vuoi semplicemente aderire al markup conforme agli standard, i suggerimenti di altri poster sarebbero una scelta migliore.

7

In XPath 2.0, utilizzare la funzione max. Per trovare il libro con la più alta id, fare

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

Sembra che la funzione max non faccia parte di Xpath 1.0 :( – HerbSpiral

+0

@HerbSpiral: hmm. Ho provato questo in XQilla XPath 1.0 compat mode e funziona , ma forse non è proprio XPath 1.0. –

2

Nota: Le seguenti informazioni assume uso di XPath 1.0.

La seguente espressione restituisce l'elemento (s) con il valore più grande id:

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

noti che questo è un po 'diverso da quello @ timbooo di risposta che questo tornerà più di un elemento, quando ci sono i duplicati con lo stesso valore massimo (@ timbooo non restituirebbe nessuno). Se vuoi un solo elemento in questo caso, allora hai bisogno di una strategia di risoluzione. Per scegliere il primo tale elemento al fine del documento, utilizzare questo:

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

Per scegliere l'ultimo, utilizzare questo:

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

Questo approccio è molto inefficiente (O(n^2)), perché richiede di confrontare ogni elemento a ogni altro potenziale max. Per questo motivo, probabilmente è meglio usare il linguaggio di programmazione dell'host per selezionare l'elemento massimo. Seleziona prima tutti gli elementi book e poi scegli il massimo da quell'elenco. Questa è (molto probabilmente) un'operazione lineare (O(n)), che sarebbe notevolmente più veloce su documenti molto grandi. Ad esempio, in Java (JAXP) si potrebbe fare in questo modo:

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

Si noti che questo è solo una dimostrazione; assicurati di includere i controlli null, ove appropriato.

1

Ho trovato che risposte come lwburk o timbooo funzionano bene per attributi che rappresentano numeri con una sola cifra. Tuttavia, se l'attributo è un numero con più di una cifra, sembra che le cose estranee si verifichino quando si confrontano i valori degli attributi. Per esempio, provare a cambiare i dati XML originale con qualcosa di simile:

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

Esecuzione dei frammenti suggerite non funzioneranno. Ho una soluzione che utilizza i xs operatore casting: int() applicato su attributo id, come in:

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

che darà la risposta corretta!

Problemi correlati