2010-04-11 15 views
43

Estoy tratando de hacer una búsqueda xpath en los nodos devueltos por la búsqueda xpath, pero no parece funcionar como esperaba. Los XPaths ejecutados en los nodos secundarios de un documento parecen ejecutarse contra h el nodo raíz del documento (en el ejemplo, la etiqueta de inventario), en lugar de la raíz del nodo proporcionado.Ejecutando XPath en el nodo hijo

¿Falta algo aquí? Soy nuevo en XPath.

Además, no responda "just do // book [author = 'Neal Stephenson'/title". Tengo un caso de uso legítimo, y este es un ejemplo simplificado.

Fragmento de código

DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); 
domFactory.setNamespaceAware(true); 
DocumentBuilder builder = domFactory.newDocumentBuilder(); 
Document doc = builder.parse("src/main/java/books.xml"); 

XPathFactory factory = XPathFactory.newInstance(); 
XPath xpath = factory.newXPath(); 

Node book = (Node) xpath.evaluate("//book[author='Neal Stephenson']", doc, XPathConstants.NODE); 
Node title = (Node) xpath.evaluate("/title", book, XPathConstants.NODE); // I get null here. 
Node inventory = (Node) xpath.evaluate("/inventory", book, XPathConstants.NODE); // this returns a node. 

book.xml

<inventory> 
<book year="2000"> 
    <title>Snow Crash</title> 
    <author>Neal Stephenson</author> 
    <publisher>Spectra</publisher> 
    <isbn>0553380958</isbn> 
    <price>14.95</price> 
</book> 

<book year="2005"> 
    <title>Burning Tower</title> 
    <author>Larry Niven</author> 
    <author>Jerry Pournelle</author> 
    <publisher>Pocket</publisher> 
    <isbn>0743416910</isbn> 
    <price>5.99</price> 
</book> 

<book year="1995"> 
    <title>Zodiac</title> 
    <author>Neal Stephenson</author> 
    <publisher>Spectra</publisher> 
    <isbn>0553573862</isbn> 
    <price>7.50</price> 
</book> 

<!-- more books... --> 

</inventory> 
+1

Otros han proporcionado buenas respuestas a su pregunta. Tenga en cuenta que '// book' y otras expresiones que comienzan con' // 'pueden afectar el rendimiento, ya que se debe buscar en todo el árbol DOM. '/ inventory/book' es más eficiente. En la misma nota, si una expresión XPath se va a usar varias veces, probablemente debería compilarla una vez con 'XPath.compile()' y ejecutar 'XPathExpression.evaluate()' en el resultado, en lugar de llamar repetidamente 'XPath .evaluate() '. – markusk

+1

Respondido aquí: http://stackoverflow.com/questions/8358994/xpath-search-on-subtree – Benj

+0

Funciona de esta manera no solo en Java. .NET hace lo mismo. – ajeh

Respuesta

43

/foo/foo seleccionará basado en el nodo raíz, ignorando el contexto que está evaluando contra el xpath. foo (sin la barra) es lo que desea; que selecciona basado en el nodo actual.

https://www.w3schools.com/xml/xpath_syntax.asp da un poco más de información.

+4

Gracias por esa aclaración. Me mantendría alejado de w3schools, que tiene muy poco contenido o la mayoría de los temas xml. – MonoThreaded

+2

w3schools es limitado y falta de enfoque, seguro, pero es muy accesible. Internet carece de una buena explicación básica de la tecnología. Si bien es posible que usted y yo no necesitemos tal cosa, w3schools es un gran lugar para que los no iniciados tengan una buena idea de lo que están tratando antes de ir a un lugar más importante. – meustrus

+0

¿Qué pasa si quiero con "// book [@ year = '2000']/title" using book node? –

7

acaba de tomar la barra en la apertura de sus sub consultas y que debe estar bien. Así que obtienes tus libros a través del "//book", y luego desde allí solo está "title", "inventory" etc. para obtener los bits hijos.

3

Lo que es realmente extraño en la implementación de Java es que un Nodo extraído de un Documento aún hace referencia al Documento principal (ver Node.getOwnerDocument()) y xpath lo usa para encontrar la raíz.

Otros han mencionado una manera de modificar el xpath para realmente no comenzar desde la raíz quitando las barras.

Tuve un problema similar pero quería que xpath manejara tanto los documentos raíz como los nodos secundarios (con un xpath como /title). La solución fue clon el nodo: Node.cloneNode(true). Tenga en cuenta el parámetro true que hace que el nodo agite su documento principal.

... Al final, duele mucho el rendimiento y es preferible tener xpaths separados para manejar el nodo y el documento.

+0

¡Si el rendimiento no es un problema, esta es una gran solución (o solución alternativa ...)! – Ice09

+0

No creo que esto sea específico de Java. Utilicé DOM en Java, PHP y JavaScript, y en los tres idiomas, la interfaz es casi idéntica, incluida la forma en que los nodos continúan recordando sus documentos principales hasta que se clonan en un nuevo contexto. – meustrus

19

en Xpath, "." (Punto) representa el documento actual. Por lo tanto, escriba su cadena XPATH después de un "." (Punto).

ejemplo:

"./title" 

o

".//title" 

Lo que quieras ....

la eliminación de la barra sólo funciona si es un hijo del nodo. ¿Qué sucede si desea utilizar la funcionalidad // (en el documento actual)?

lo tanto, utilizar el punto (.)

Gracias mucho por las respuestas anteriores también :).

Cuestiones relacionadas