web-dev-qa-db-fra.com

Trouver la position d'un nœud en utilisant xpath

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

Disons que j'ai le XML suivant:

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

Je peux utiliser la requête xpath suivante pour sélectionner le troisième nœud <b> (<b> tsr </ b>):

a/b[.='tsr']

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

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

(mais un peu plus de travail!)

Est-ce même possible?

edit : J'ai oublié de mentionner am utilisant .net 2, donc c'est xpath 1.0!


Update : Nous avons fini par utiliser James Sulak 's excellente réponse . 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);
}
85
Wilfred Knievel

Essayer:

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

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

<?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>
9
Steven Huwig

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

remplacer l'astérisque par le nom de noeud vous donnerait de meilleurs résultats

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

au lieu de

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

Si vous effectuez une mise à niveau vers XPath 2.0, notez qu'il fournit la fonction index-of , il résout le problème de cette façon:

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

Où:

  • Le premier paramètre est la séquence de recherche
  • 2ème est ce qu'il faut rechercher
3
CroWell

Contrairement à ce qui a été dit précédemment, "précédent-frère" est vraiment l'axe à utiliser, et non "précédent" qui fait quelque chose de complètement différent, il sélectionne tout ce qui se trouve dans le document avant la balise de début du noeud actuel. (voir http://www.w3schools.com/xpath/xpath_axes.asp )

3
Damien

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

Si vous voulez prendre en compte le fait que le nœud peut ne pas exister et que vous voulez le garder purement XPATH, essayez ce qui suit pour retourner 0 si le nœud n'existe pas.

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

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;
                }
            }
        }
    }
}
0
Andrew Cox

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

Supposons que la valeur que vous recherchez se trouve dans une variable de chaîne, appelée TARGET, alors le XPATH serait:

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

En outre, il a été souligné que, pour économiser quelques caractères d’espace, les éléments suivants fonctionneraient également:

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

J'ai également posté une version plus jolie de ceci chez Cool Solutions de Novell: tilisation de XPATH pour obtenir le nœud de position

0
geoffc