8
votes

Obtenez un chemin complet sur le nœud actuel

Si j'ai un xpathnavigator positionné sur un nœud, comment puis-je obtenir une expression XPath qui représente le chemin d'accès à ce nœud, de la racine?

Par exemple, si le XML est: xxx

... puis le chemin du chat persan pourrait être exprimé en tant que / data / classe [2] / élément [1]

Je peux énumérer les ancêtres du nœud en question avec sélecteur () (ou je pouvais gravir itérativement la relation parent avec selectparent () ), mais Cela ne me reçoit pas les informations de position.

devrais-je évaluer un xpath en utilisant la position () pour chaque ancêtre ou y a-t-il un meilleur moyen de le faire?


2 commentaires

Pourquoi essayez-vous de faire cela? Les objets XPathnavigator sont généralement positionnés sur la racine. Une fois qu'ils sont créés, leurs positions ne peuvent pas changer. Peut-être qu'il y a un moyen de contourner ce problème?


@ZENEXER: Si j'utilise CreateAnavigator (). Sélectionnez (Expr) alors qui renvoie un XPathNodeiterator ... mais le XPathNodeiterator me donne un xpathnavigator pour chaque noeud sélectionné - positionné sur ledit noeud.


4 Réponses :


3
votes

non testé; Fonctionne uniquement avec des objets XPathnavigator créés à partir d'objets XMLDOCUMUMUMENT:

XPathNavigator navigator = /* ... */;
string path = navigator.GetPath();


7 commentaires

+1. Positional XPath est la voie à suivre. Notez que, en fonction de la mise en œuvre des nœuds "Précédent" peut être extrêmement lente (si nécessaire de marcher sur tous les enfants jusqu'à la finale). Pensez à marcher vers l'avant vers le nœud actuel. NOTE 2: Soyez prudent avec les attributs car ils n'ont pas de position -0 juste nom.


@ZenExer: Merci, mais hélas je traite avec un XPathDocument. Si j'ai réalisé que cela fait une différence, j'aurais mentionné cela. Pardon.


@Zenexer: Dans quelles circonstances serait nœud.parentnode.childnodes.count être zéro? Cela semble être une contradiction ...


@Garymcgill Ce ne serait pas. Mais cela pourrait être 1. C'est ce que le test est.


Hmmm ... navigator.underlyLingObject comme xmlnode retourner null pour moi


@Mickyd Ceci fonctionne uniquement avec XMLDocuments, pas XPathDocuments. Utilisez-vous ce dernier?


Ohh!! Oui c'est vrai. Je devais passer à l'aide de xmldocument depuis hier parce que j'avais besoin de Supprimer Alors c'est une victoire win . Merci :) +1



7
votes

En supposant que vous n'êtes intéressé que dans les éléments XPATH d'éléments XML, j'ai implémenté un algorithme de force brute (c'est-à-dire une traversée de la structure XML) comme méthodes d'extension sur xmlelement code>. C'est très similaire à la réponse de @ zenexer, bien que j'avais déjà commencé à ma version lorsqu'il a posté sa propre version lorsqu'il a posté son.

Aussi, intrigué par la pointe d'Alexei sur la performance, j'ai créé une sorte de test de test utilisant un fichier XML quelque peu complexe. ici. Ensuite, j'ai mis en œuvre deux versions du même algorithme; Celui qui dépend des précédents, et d'autres personnes qui tient des nœuds de manière séquentielle. Une troisième version s'appuyait sur la fonction de XPath () CODE>, mais elle n'a pas fonctionné comme prévu et a été rejetée. P>

Pendant que vous devriez vérifier vous-même, dans ma machine les résultats ont montré. Un avantage de performance significatif pour la version itérative forte> - 1.7S contre 21s Scored par la version de frères et sœurs. p>

importateurArt: Ces méthodes d'extension sont déclarées à l'intérieur d'un Classe STATIQUE XMLELEMENTExtension .

Préviosité version h2> xxx pré>

version itérative h2> xxx pré>

le cas de test H2>
    private static void Measure(string functionName, int iterations, Action implementation)
    {
        Stopwatch watch = new Stopwatch();
        watch.Start();

        for (int i = 0; i < iterations; i++)
        {
            implementation();
        }

        watch.Stop();
        Console.WriteLine("{0}: {1}ms", functionName, watch.ElapsedMilliseconds);
    }

    private static void Main(string[] args)
    {
        XmlDocument doc = new XmlDocument();
        doc.Load(@"location of some large and complex XML file");

        string referenceXPath = "/vps/vendorProductSets/vendorProductSet/product[100]/prodName/locName";

        Measure("UsingPreviousSiblings", 10000,
                () =>
                    {
                        XmlElement target = doc.SelectSingleNode(referenceXPath) as XmlElement;
                        Debug.Assert(referenceXPath == target.GetXPath_UsingPreviousSiblings());
                    });

        Measure("SequentialIteration", 10000,
                () =>
                {
                    XmlElement target = doc.SelectSingleNode(referenceXPath) as XmlElement;
                    Debug.Assert(referenceXPath == target.GetXPath_SequentialIteration());
                });
    }


3 commentaires

Merci. Les gens ont passé tellement de temps à ce que je suis presque désolé de poser la question! :-) Notez toutefois que vous avez une erreur Copy-coller dans votre "position" et "itération". Au point de l'appel récursif, tous deux appellent réellement votre version "frères et sœurs". Cela pourrait expliquer pourquoi vous n'avez vu aucune différence de performance? :-)


Gosh! Ma faute. Va mettre à jour bientôt. Eh bien, j'ai effectivement passé plus de temps que je ne me laisserais mais c'était assez amusant et instructif! Bonne question néanmoins.


Corrigé et édité. J'ai également laissé tomber la version de la position XPath () telle qu'elle était incorrecte.



2
votes

Solution simple avec parentnode. Montez simplement jusqu'à atteindre le nœud racine et rappelez-vous chaque nom de noeud que vous passez. Testé!

    // Get the node full path
    static string getPath(XmlNode node)
    {
        string path = node.Name;
        XmlNode search = null;
        // Get up until ROOT
        while ((search = node.ParentNode).NodeType != XmlNodeType.Document)
        {
            path = search.Name + "/" + path; // Add to path
            node = search;
        }
        return "//"+path;
    }


1 commentaires

Je ne pense pas que vous lisez complètement la question. Je devrais connaître la position à chaque étape, par exemple. / foo [3] / bar [2]



0
votes

Voici ma solution pour XPathnavigator créée à partir de XPathDocument. Il comporte jusqu'à la racine lors de la vérification de chaque nœud dans le chemin, il a un frère au-dessus ou non. XXX


0 commentaires