Si j'ai un Par exemple, si le XML est: p> ... puis le chemin du chat persan pourrait être exprimé en tant que Je peux énumérer les ancêtres du nœud en question avec devrais-je évaluer un xpath en utilisant la position xpathnavigator code> 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?
/ data / classe [2] / élément [1] code> p>
sélecteur () code> (ou je pouvais gravir itérativement la relation parent avec
selectparent () code>), mais Cela ne me reçoit pas les informations de position. p>
() code> pour chaque ancêtre ou y a-t-il un meilleur moyen de le faire? p> p>
4 Réponses :
non testé; Fonctionne uniquement avec des objets XPathnavigator créés à partir d'objets XMLDOCUMUMUMENT:
XPathNavigator navigator = /* ... */; string path = navigator.GetPath();
+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 code> retourner
null code> 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 code> depuis hier parce que j'avais besoin de
Supprimer Code> Alors c'est une victoire win i>. Merci :) +1
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 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 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 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.
de XPath () CODE>, mais elle n'a pas fonctionné comme prévu et a été rejetée. P>
Classe STATIQUE XMLELEMENTExtension .
Préviosité version h2>
version itérative h2>
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());
});
}
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.
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; }
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]
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.
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.