2009-12-04 3 views
3

Cela peut être une solution simple (eh bien, c'est probablement le cas), mais pour une raison quelconque, je ne peux pas le comprendre.LINQ to XML: gestion des noeuds qui n'existent pas?

Alors, j'ai quelques xml qui ressemble à ceci:

XElement xml = XElement.Parse (
@"<Alphabet> 
    <a name="A" /> 
    <b name="B" /> 
    <d name="D" /> 
    <e name="E" /> 
</Alphabet>"); 

donc plus tard dans mon code, je référence un noeud qui peut ou peut ne pas exister là-dedans comme ceci:

var name = (from b in xml.Descendants("c") 
      select b.Attribute("name")).FirstOrDefault().Value; 

Mais quand il n'existe pas, au lieu de retourner null ou "", il lance une référence NullReferenceException: Object non définie sur une instance d'un objet.

Quelle est la meilleure façon de vérifier et de voir si un nœud existe réellement dans ma requête linq? Ou dois-je vérifier s'il existe d'une autre manière?

+0

On dirait qu'il était mon utilisation de FirstOrDefault() qui a été déconner cela. Merci pour les réponses si - Tout est très utile! – onekidney

+0

pouvez-vous s'il vous plaît la solution pour cela je suis dans la même situation et en utilisant FirstOrDefault() quelle est l'alternative – trx

+0

@trx - Le problème que j'avais lors de la publication de ce problème appelait Value sur ma requête 'FirstOrDefault()'. Étant donné que la requête retournait null, l'appel de Value sur elle a provoqué l'erreur. Donc, pour tester si le noeud est là, j'aurais dû écrire: 'var nom = (à partir de b dans xml.Descendants (" c ") sélectionnez b.Attribute (" nom ")). FirstOrDefault();' et vérifié 'name' pour voir si elle était nulle ou non. – onekidney

Répondre

5

Eh bien, vous sélectionnez l'attribut - donc il suffit d'utiliser:

var nameAttribute = xml.Descendants("c").Select(b => b.Attribute("name")) 
             .FirstOrDefault(); 
if (nameAttribute != null) 
{ 
    string name = nameAttribute.Value; 
} 
else 
{ 
    // Whatever... 
} 

(je l'ai changé à partir d'une expression de requête à la notation par points parce que la requête était trivial - la syntaxe d'expression de requête n'a pas été fait vous achetez quelque chose.)

Un problème avec cette solution: elle ne fait pas la différence entre un élément "c" mais un attribut "name", et il n'y a pas d'élément "c" dans le premier endroit. Avez-vous besoin de pouvoir faire la différence?

+0

Merci pour la réponse - Non, je n'ai pas besoin de faire la différence pour que ça fonctionne bien. Je m'intéresse à ce que vous disiez que «la syntaxe d'expression de requête ne vous achetait rien» - J'ai toujours supposé que choisir une syntaxe plutôt qu'une autre était basée sur la préférence - y a-t-il une raison de performance? Ou peut-être que c'est un sujet complètement différent. Google ici je viens! – onekidney

+0

@Skeet - Ayende a également parlé de Linq. Vous voulez expliquer pourquoi c'est bénéfique? – mhenrixon

+0

Aucune raison de performance du tout - juste que le "de x en y" est juste plus superflu dans ce cas. Voir http://msmvps.com/blogs/jon_skeet/archive/2009/01/07/you-don-t-have-to-use-query-expressions-to-use-linq.aspx –

4

J'ai créé des méthodes d'extension pour le faire pour moi.

public static string GetAttributeValue(this XElement element, string attributeName) 
{ 
    XAttribute attribute = element.Attribute(attributeName); 
    return attribute != null ? attribute.Value : string.Empty; 
} 

public static string GetElementValue(this XElement element) 
{ 
    return element != null ? element.Value : string.Empty; 
} 

public static string GetElementValue(this XElement element, string elementName) 
{ 
    XElement child = element.Element(elementName); 
    return child != null ? child.Value : string.Empty; 
} 
+0

Salut, bien. Je vais les utiliser. Pourquoi n'y ai-je pas pensé? –

+0

N'hésitez pas à les utiliser :) – mhenrixon

0

Vous pouvez faire quelque chose comme ceci:

var name = (from b in xml.Descendants("c") 
      select b.Attribute("name").Value).FirstOrDefault(); 

ou si vous avez vraiment besoin de l'élément:

var name = (from b in xml.Descendants("c") 
      select b.Attribute("name")).FirstOrDefault(); 

if (name != null) 
{ 
    // your logic ... 
} 
1

FirstOrDefault retours null ou un XAttribute que vous pouvez jeter un string à obtenez la valeur:

var name = (string)((from b in xml.Descendants("c") 
        select b.Attribute("name")).FirstOrDefault()); 

ou

var name = (string)xml.Descendants("c") 
         .Select(b => b.Attribute("name")) 
         .FirstOrDefault();