2008-10-22 26 views
79

¿Alguien sabe cómo obtener la posición de un nodo usando xpath?Buscar la posición de un nodo usando xpath

Decir que tengo la siguiente xml:

<a> 
    <b>zyx</b> 
    <b>wvu</b> 
    <b>tsr</b> 
    <b>qpo</b> 
</a> 

I puede usar la siguiente consulta XPath para seleccionar la tercera <b> nodo (<b> tsr </b >):

a/b[.='tsr'] 

Lo cual está muy bien, pero quiero devolver la posición ordinal de ese nodo, algo así como:

a/b[.='tsr']/position() 

(pero un poco más de trabajo!)

¿Es posible?

editar: ¡He olvidado mencionar que estoy usando .net 2, así que es xpath 1.0!


actualización: acabamos utilizando James Sulak 's excellent answer. Para aquellos que estén interesados ​​aquí está mi aplicación en C#:

int position = doc.SelectNodes("a/b[.='tsr']/preceding-sibling::b").Count + 1; 

// Check the node actually exists 
if (position > 1 || doc.SelectSingleNode("a/b[.='tsr']") != null) 
{ 
    Console.WriteLine("Found at position = {0}", position); 
} 

Respuesta

84

Probar:

count(a/b[.='tsr']/preceding-sibling::*)+1. 
+1

'Coz estoy usando .net y, o bien, o no puedo manejar la potencia que fui con: int position = doc.SelectNodes ("a/b [. =' Tsr ']/precedente-Sibling :: b ") .Count + 1; if (position> 1 || doc.SelectSingleNode ("a/b [. = 'tsr']")! = null) // Comprobar que el nodo existe en realidad {// Hacer magia aquí} –

+0

en cero idiomas indexados no lo haces Necesito el +1 –

8

Usted puede hacer esto con XSLT, pero no estoy seguro acerca de XPath recta.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" encoding="utf-8" indent="yes" 
       omit-xml-declaration="yes"/> 
    <xsl:template match="a/*[text()='tsr']"> 
    <xsl:number value-of="position()"/> 
    </xsl:template> 
    <xsl:template match="text()"/> 
</xsl:stylesheet> 
1

El problema es que la posición del nodo no significa mucho sin un contexto.

El siguiente código le dará la ubicación del nodo en sus nodos hijos de padres

using System; 
using System.Xml; 

public class XpathFinder 
{ 
    public static void Main(string[] args) 
    { 
     XmlDocument xmldoc = new XmlDocument(); 
     xmldoc.Load(args[0]); 
     foreach (XmlNode xn in xmldoc.SelectNodes(args[1])) 
     { 
      for (int i = 0; i < xn.ParentNode.ChildNodes.Count; i++) 
      { 
       if (xn.ParentNode.ChildNodes[i].Equals(xn)) 
       { 
        Console.Out.WriteLine(i); 
        break; 
       } 
      } 
     } 
    } 
} 
+1

Entonces realmente no es un buscador de XPath, sino un buscador de C#. – jamesh

0

hago un montón de cosas Gestor de identidades de Novell, y XPath en ese contexto se ve un poco diferente.

asumen el valor que busca está en una variable de cadena, llamado objetivo, entonces el XPath sería:

count(attr/value[.='$TARGET']/preceding-sibling::*)+1 

Además se señaló que para salvar unos pocos caracteres de espacio, lo siguiente sería funciona así:

count(attr/value[.='$TARGET']/preceding::*) + 1 

también he publicado una versión más bonita de esto en Cool Solutions de Novell: Using XPATH to get the position node

3

a diferencia Previou declarado sly 'previous-sibling' es realmente el eje para usar, no 'precedente', que hace algo completamente diferente, selecciona todo en el documento que está antes de la etiqueta de inicio del nodo actual. (Consulte http://www.w3schools.com/xpath/xpath_axes.asp)

+4

Sin incluir los antecesores. ¡No confíes en w3schools en los detalles! Pero estoy de acuerdo ... aunque lo anterior :: funciona en este caso, porque no hay elementos antes de los elementos b relevantes que no sean el antecesor a, es más frágil que el anterior-hermano. OTOH, el OP no nos dijo en qué contexto quería saber la posición dentro, tan potencialmente anterior :: podría ser correcto. – LarsH

5

Me doy cuenta de que la publicación es antigua .. pero ..

replace'ing el asterisco con el nombre de nodo que daría mejores resultados

count(a/b[.='tsr']/preceding::a)+1. 

en lugar de

count(a/b[.='tsr']/preceding::*)+1. 
1

Sólo una nota para la respuesta realizada por James Sulak.

Si desea tener en cuenta que el nodo puede no existir y desea mantenerlo puramente XPATH, intente lo siguiente que devolverá 0 si el nodo no existe.

count(a/b[.='tsr']/preceding-sibling::*)+number(boolean(a/b[.='tsr'])) 
1

Si alguna vez se actualiza a XPath 2.0, tenga en cuenta que proporciona la función de index-of, se resuelve el problema de esta manera:

index-of(//b, //b[.='tsr']) 

Dónde:

  • primera parámetro es la secuencia para la búsqueda
  • 2do es lo que debe buscar
+0

Cabe señalar que esto solo funcionará con XPath 2+. Cualquier cosa debajo de eso tendrá que usar la función de conteo 'raro'. –

+1

@Dan, se indicó en el enlace a los documentos originales, se agregó un aviso explícito, ¡gracias! – CroWell

Cuestiones relacionadas