2008-10-22 8 views
79

Quelqu'un sait comment obtenir la position d'un nœud en utilisant xpath?Trouver la position d'un nœud en utilisant xpath

Dire que j'ai le code XML suivant:

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

I peut utiliser la requête XPath suivante pour sélectionner la troisième <b> noeud (<b> tsr </b >):

a/b[.='tsr'] 

Ce qui est bien, mais je veux retourner la position ordinale de ce nœud, quelque chose comme:

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

(mais un peu plus de travail!)

Est-il possible?

edit: J'ai oublié de mentionner que j'utilise .net 2 donc c'est xpath 1.0!


Mise à jour: Ended à l'aide James Sulak « s excellent answer. Pour ceux qui sont intéressés, voici mon implémentation 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); 
} 

Répondre

84

Essayez:

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

'Coz J'utilise .net et soit il ou je ne peux pas gérer la puissance avec laquelle je suis allé: int position = doc.SelectNodes ("a/b [. =' Tsr ']/previous-Sibling :: b ") .Compte + 1; si (position> 1 || doc.SelectSingleNode ("a/b [. = 'tsr']")! = null) // Vérifiez le nœud {// existe réellement Faites de la magie ici} –

+0

en zéro langues indexées vous n » t besoin le +1 –

8

Vous pouvez le faire avec XSLT mais je ne suis pas sûr de XPath droite.

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

Le problème est que la position du nœud ne signifie pas grand-chose sans contexte.

Le code suivant vous donnera l'emplacement du nœud dans ses nœuds enfants parents

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

donc pas vraiment un outil de recherche XPath maintenant, mais un chercheur C#. – jamesh

0

Je fais beaucoup de choses de Novell Identity Manager, et XPath dans ce contexte est un peu différent.

Supposons que la valeur que vous cherchez est dans une variable de chaîne, appelée cible, la XPATH serait:

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

En outre, il a été signalé que pour sauver quelques caractères d'espace, ce qui suit serait travailler ainsi:

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

J'ai aussi posté une version plus jolie de ce à cool Solutions de Novell: Using XPATH to get the position node

3

Contrairement à Previou déclaré sly 'previous-sobling' est vraiment l'axe à utiliser, pas 'previous' qui fait quelque chose de complètement différent, il sélectionne tout dans le document qui est avant la balise de début du noeud courant. (Voir http://www.w3schools.com/xpath/xpath_axes.asp)

+4

Non compris les nœuds ancêtres. Ne faites pas confiance à w3schools sur les détails! Mais je suis d'accord ... bien que précédant :: fonctionne dans ce cas, car il n'y a pas d'éléments avant les éléments b pertinents autres que l'ancêtre a, c'est plus fragile que le précédent-frère. OTOH, l'OP ne nous dit pas quel contexte il a voulu connaître la position à l'intérieur, donc précédent :: pourrait avoir raison. – LarsH

5

Je me rends compte que le poste est ancien .. mais ..

replace'ing l'astérisque avec le nodename vous donnera de meilleurs résultats

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

au lieu de

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

Juste une note à la réponse faite par James Sulak.

Si vous voulez prendre en considération le fait que le noeud ne peut pas exister et que vous voulez le garder purement XPATH, essayez ce qui suit qui renverra 0 si le nœud n'existe pas.

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

Si vous mettez à niveau jamais XPath 2.0, notez qu'il offre une fonction index-of, il résout le problème de cette façon:

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

Où:

  • 1er paramètre est séquence pour la recherche
  • 2 est quoi chercher
+0

Il convient de noter que cela ne fonctionnera qu'avec XPath 2+. Tout ce qui est en dessous devra utiliser la fonction de comptage "bizarre". –

+1

@ Dan, il a été noté dans le lien vers docs d'origine, a ajouté un avis explicite, merci! – CroWell

Questions connexes