2012-01-02 18 views
7

¿Hay alguna forma de consultar un documento XML para devolver el máximo de un atributo determinado utilizando Xpath 1.0?Cómo encontrar el atributo máximo de un documento XML utilizando Xpath 1.0

Por ejemplo, ¿hay alguna manera de obtener la identificación máxima?

<?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, para la piña: P –

+0

¿Cuál es su idioma de host para ejecutar XPath? Si está utilizando XPath 1.0 (que no tiene una función 'max'), probablemente sea más rápido seleccionar primero todos los elementos y encontrar el máximo en su PL. –

+0

Estoy usando Perl 5.10. – HerbSpiral

Respuesta

0

Este ejemplo se puede utilizar para encontrar el máximo.

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

Para otros temas similares en XPath y LINQ echa un vistazo a http://rmanimaran.wordpress.com/2011/03/20/xml-find-max-and-min-value-in-a-attribute-using-xpath-and-linq/

3

La siguiente XPath selecciona el libro con mayor Identificación:

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

Esto de hecho funciona, sin embargo, el rendimiento no es tan bueno (cuando miles de identificadores están presentes en el documento) – HerbSpiral

+0

+1 - Repetí el núcleo de su respuesta, pero solo quería proporcionar información adicional en mi respuesta, incluidos algunos de lo que se ha extendido alrededor de los comentarios. –

+0

@lwburk No hay problema;) – timbooo

2

Si usted está dispuesto a utilizar herramientas externas - el cual Depende de su implementación con implementaciones de estas herramientas: pruebe la función EXSLT:Mathhighest().

El hecho de que EXSLT implemente esto implica que tal característica no está directamente disponible en plain xpath, por supuesto. Si no está utilizando Transformaciones, o quiere adherirse exclusivamente al marcado que cumpla con los estándares, las sugerencias de otros carteles serían una mejor opción.

7

En XPath 2.0, use la función max. Para encontrar el libro con el más alto id, hacer

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

Parece que la función máxima no es parte de Xpath 1.0 :( – HerbSpiral

+0

@HerbSpiral: hmm. Probé esto en modo XQilla XPath 1.0 compatible y funciona , pero tal vez eso no es realmente XPath 1.0. –

2

Nota: La siguiente información asume el uso de XPath 1.0.

La siguiente expresión devuelve el elemento (s) con el mayor id valor:

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

Tenga en cuenta que esto es ligeramente diferente a la de @ timbooo respuesta en que esto va a devolver más de un elemento cuando hay duplicados con el mismo valor máximo (@ timbooo's no devolvería ninguno). Si solo quieres un elemento en este caso, entonces necesitas una estrategia de resolución. Para elegir el primero de esos elementos en el orden del documento, utilice esto:

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

para elegir el último, utilizar esto:

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

Este enfoque es muy ineficiente (O(n^2)), ya que requiere que usted pueda comparar cada elemento a cada otro potencial max. Por este motivo, probablemente sea mejor usar el lenguaje de programación de su host para seleccionar el elemento máximo. Simplemente seleccione todos los elementos book primero y luego elija el máximo de esa lista. Esta es (muy probablemente) una operación lineal (O(n)), que sería notablemente más rápida en documentos muy grandes. Por ejemplo, en Java (JAXP) es posible hacerlo de esta manera:

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

Tenga en cuenta que esto es sólo una manifestación; asegúrese de incluir null-checks cuando corresponda.

1

He encontrado que las respuestas como la de lwburk o timbooo funcionan bien para atributos que representan números que tienen solo un dígito. Sin embargo, si el atributo es un número que tiene más de un dígito, cosas extrañas parecen suceder cuando se comparan los valores de los atributos. Por ejemplo, trate de cambiar los datos XML originales con algo como esto:

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

Ejecución de los fragmentos sugeridas no funcionarán. Tengo una solución utilizando los xs operador de calidad: int() aplicada sobre atributo id, como en:

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

que le dará la respuesta correcta!

Cuestiones relacionadas