2008-10-28 4 views
5

Dernièrement, j'ai utilisé XPathDocument et XNavigator pour analyser un fichier XML pour un XPath et un attribut donné. Cela fonctionne très bien, quand je sais à l'avance ce qu'est le XPath. Cependant, XPath sera l'une des nombreuses valeurs XPath possibles, et j'aimerais pouvoir tester si un XPath existe ou non.Meilleur moyen de tester l'existence de XPath dans un fichier XML?

Dans le cas où je reçois la nomenclature mal, voici ce que j'appelle un XPath - donné cette blob XML:

<foo> 
    <bar baz="This is the value of the attribute named baz"> 
</foo> 

je pourrais être à la recherche de ce que je vous appelle un XPath «// foo/bar "puis en lisant l'attribut" baz "pour obtenir la valeur.

Exemple de code que j'utiliser pour ce faire:

XPathDocument document = new XPathDocument(filename); 
XPathNavigator navigator = document.CreateNavigator(); 
XPathNavigator node = navigator.SelectSingleNode("//foo/bar"); 
if(node.HasAttributes) 
{ 
    Console.WriteLine(node.GetAttribute("baz", string.Empty)); 
} 

Maintenant, si l'appel à navigator.SelectSingleNode échoue, il retournera un NullReferenceException ou un XPathException. Je peux attraper ces deux et refactor le ci-dessus dans un test pour voir si un XPath donné renvoie une exception, mais je me demandais s'il y avait une meilleure façon?

Je n'ai rien vu d'évident dans l'Intellisense. XPathNavigator a .HasAttributes et .HasChildren mais à court d'itération à travers le chemin un nœud à la fois, je ne vois rien de plus agréable à utiliser.

+0

Qu'est-ce que cela a à voir avec LINQ? XPathNavigator et XPathDocument ne font pas partie de LINQ to XML. –

Répondre

10

Si vous avez donné XPath valide, mais il ne correspond pas à quoi que ce soit, ne sera pas SelectSingleNodejeter unNullReferenceException - elle retournera nulle.

Si vous passez SelectSingleNode à un XPath syntaxiquement invalide, c'est-à-dire qu'il lancera un XPathException.

Donc, normalement, il suffit de tester si la valeur retournée est nulle ou non.

+0

C'est ce que je cherchais, merci. –

0

De mémoire, peut contenir des erreurs.

XDocument doc = XDocument.Load("foo.xml"); 

var att = from a in doc.Descendants("bar") 
      select a.Attribute("baz") 

foreach (var item in att) { 
    if (item != null) { ... } 
} 
+0

Puisque le titre de la question mentionne Linq, voici comment je le ferais. –

+0

Utilisation.FirstOrDefault sur la requête si vous voulez juste un –

0

Si node == null puis node.HasAttributes lancera une NullReferenceException. Cette situation se produit lorsque //foo/bar ne correspond à aucun élément dans le document XML.

0
var node = XDocument.Load(filename) 
        .Descendants("bar") 
        .SingleOrDefault(e=>e.Attribute("baz") != null); 

if (node != null) Console.WriteLine(node.Attribute("baz").Value); 
1
var baz = navigator.SelectSingleNode("//foo/bar/@baz"); 
if (baz != null) Console.WriteLine(baz); 
0

je serais probablement plus précis dans mon XPath.

 var doc = XDocument.Load(fileName); 

     var results = from r in doc.XPathSelectElements("/foo/bar[count(@baz) > 0]") 
         select r.Attribute("baz"); 

     foreach (String s in results) 
      Console.WriteLine(s); 
1

Je pense qu'il n'est pas bon de créer un objet XMLNode en exécutant navigator.SelectSingleNode (...).

Vous devez utiliser navigator.Evaluate() à la place:

if (Convert.ToBoolean(navigator.Evaluate(@"boolean(//foo/bar)"))) {...} 
+0

J'ai fait une comparaison de vitesse de cette méthode par rapport à SelectSingleNode, pour 500 000 itérations chacun (avec l'expression XPath sous forme de chaîne, non compilé). La méthode SelectSingleNode était 16-18% plus rapide que la méthode booléenne. J'ai répété le test plusieurs fois et les résultats sont cohérents. –

Questions connexes