2012-01-02 12 views
7

Czy istnieje sposób na zapytanie do dokumentu XML, aby zwrócić maksymalną wartość danego atrybutu za pomocą Xpath 1.0?Jak znaleźć atrybut max z dokumentu XML za pomocą Xpath 1.0

Na przykład czy istnieje sposób na uzyskanie maksymalnego identyfikatora?

<?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, dla ananasa: P –

+0

Jaki jest twój język hosta do wykonywania XPath? Jeśli używasz XPath 1.0 (który nie ma funkcji "max"), prawdopodobnie szybciej będzie najpierw wybrać wszystkie elementy i znaleźć maksimum w twoim PL. –

+0

Używam Perla 5.10. – HerbSpiral

Odpowiedz

0

W tym przykładzie można znaleźć maks.

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

dla innych podobnych tematów na XPath i LINQ sprawdzeniu http://rmanimaran.wordpress.com/2011/03/20/xml-find-max-and-min-value-in-a-attribute-using-xpath-and-linq/

3

Poniższy XPath wybiera książkę z najwyższym ID:

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

To rzeczywiście działa, ale wydajność nie jest tak dobra (gdy w dokumencie są tysiące identyfikatorów) – HerbSpiral

+0

+1 - Powtórzyłem rdzeń twojej odpowiedzi, ale chciałem tylko dostarczyć dodatkowe informacje w mojej odpowiedzi, w tym niektóre z co zostało rozrzucone wokół komentarzy. –

+0

@lwburk Bez problemu;) – timbooo

2

Jeśli jesteś gotów użyć zewnętrznego oprzyrządowania - co zależy od implementacji zawierającej implementacje tych narzędzi - spróbuj funkcji EXSLT:Mathhighest().

Fakt, że EXSLT implementuje to, oznacza, że ​​taka funkcja nie jest dostępna bezpośrednio w zwykłej ścieżce xpath. Jeśli nie używasz transformacji lub chcesz zachować czysto zgodny ze standardami znacznik, sugestie innych posterów będą lepszym wyborem.

7

W XPath 2.0 użyj funkcji max. Aby znaleźć książkę z najwyższym id, zrobić

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

Wygląda na to, że funkcja max nie jest częścią Xpath 1.0 :( – HerbSpiral

+0

@HerbSpiral: hmm. Próbowałem tego w XQilla XPath 1.0 compat i to działa , ale może to nie jest tak naprawdę XPath 1.0. –

2

Uwaga: Poniższe informacje zakłada wykorzystanie XPath 1.0.

Poniższe wyrażenie zwraca element (ów) z największą id wartość:

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

pamiętać, że jest nieco inny niż @ timbooo na odpowiedź, że będzie to powrót więcej niż jeden element, gdy istnieją duplikaty ta sama maksymalna wartość (@ timbooo nie zwróci żadnej). Jeśli potrzebujesz tylko jednego elementu w tym przypadku, potrzebujesz strategii rozwiązywania problemów. Aby wybrać pierwszy taki element w kolejności dokumentu, użyj tego:

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

wybrać ostatni, użyj tego:

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

Takie podejście jest bardzo nieefektywne (O(n^2)), ponieważ wymaga, aby porównać każdy element na każdy inny potencjał max. Z tego powodu najlepiej jest użyć języka programowania hosta, aby wybrać maksymalny element. Po prostu wybierz wszystkie elementy book, a następnie wybierz maksimum z tej listy. Jest to (najprawdopodobniej) operacja liniowa (O(n)), która byłaby zauważalnie szybsza w przypadku bardzo dużych dokumentów. Na przykład w języku Java (JAXP) możesz to zrobić tak:

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

Pamiętaj, że to tylko demonstracja; pamiętaj, aby w razie potrzeby uwzględnić kontrole null.

1

Odkryłem, że odpowiedzi takie jak praca lwburka lub timbooo są dobre dla atrybutów reprezentujących liczby mające tylko jedną cyfrę. Jeśli jednak atrybut jest liczbą zawierającą więcej niż jedną cyfrę, można wydłużyć rzeczy, gdy porównuje się wartości atrybutów. Na przykład, spróbuj zmienić oryginalne dane XML z czymś takim:

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

uruchamiając je fragmenty nie będą działać. Mam rozwiązanie używając xs operatora odlewania: int() zastosowane na atrybut id, jak w:

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

To da prawidłową odpowiedź!

Powiązane problemy