2010-04-18 7 views
1

J'ai un fichier XML comme ceci:Une meilleure solution que element.Elements ("Whatever"). First()?

<SiteConfig> 
    <Sites> 
    <Site Identifier="a" /> 
    <Site Identifier="b" /> 
    <Site Identifier="c" /> 
    </Sites> 
</SiteConfig> 

Le fichier est modifiable par l'utilisateur, donc je veux donner un message d'erreur raisonnable au cas où je ne peux pas analyser correctement il. Je pourrais probablement écrire un .xsd pour cela, mais cela semble un peu exagéré pour un simple fichier.

De toute façon, lors de l'interrogation de la liste des <Site> noeuds, il y a deux façons je pouvais le faire:

var doc = XDocument.Load(...); 

var siteNodes = from siteNode in 
        doc.Element("SiteConfig").Element("Sites").Elements("Site") 
       select siteNode; 

Mais le problème est que si l'utilisateur n'a pas inclus le noeud <SiteUrls> (disons) il va juste jeter un NullReferenceException qui ne dit pas grand-chose à l'utilisateur sur ce qui s'est vraiment mal passé.

Une autre possibilité est juste d'utiliser Elements() partout au lieu de Element(), mais cela ne fonctionne pas toujours lorsqu'il est couplé avec des appels à Attribute(), par exemple, dans la situation suivante:

var siteNodes = from siteNode in 
        doc.Elements("SiteConfig") 
        .Elements("Sites") 
        .Elements("Site") 
       where siteNode.Attribute("Identifier").Value == "a" 
       select siteNode; 

(C'est, Y a-t-il quelque chose de intégré au cadre pour gérer un peu mieux cette situation? Ce que je préférerais une version de Element() (et de Attribute() pendant que nous y sommes) qui renvoie une exception descriptive (par exemple, « Looking for élément <xyz> sous <abc> mais aucun élément n'a été trouvé ») au lieu de retourner null .

Je pourrais écrire ma propre version de Element() et Attribute(), mais il me semble comme cela est un tel scénario commun que je dois manquer quelque chose ...

+2

mai souhaitez mettre à jour votre exemple XML ci-dessus - il n'y a pas 'élément SiteURLs' liste. –

+0

@Otaku: D'un autre côté, peut-être qu'il ne devrait pas le changer car il montre exactement le problème qu'il veut résoudre. –

+0

Otaku: Désolé, c'était une erreur cut'n'paste de mon projet :-) –

Répondre

2

Vous pouvez mettre en œuvre votre fonctionnalité désirée comme une méthode d'extension:

public static class XElementExtension 
{ 
    public static XElement ElementOrThrow(this XElement container, XName name) 
    { 
     XElement result = container.Element(name); 
     if (result == null) 
     { 
      throw new InvalidDataException(string.Format(
       "{0} does not contain an element {1}", 
       container.Name, 
       name)); 
     } 
     return result; 
    } 
} 

Vous auriez besoin quelque chose de similaire pour XDocument. Puis l'utiliser comme ceci:

var siteNodes = from siteNode in 
    doc.ElementOrThrow("SiteConfig") 
     .ElementOrThrow("SiteUrls") 
     .Elements("Sites") 
    select siteNode; 

vous obtiendrez une exception comme ceci:

 
SiteConfig does not contain an element SiteUrls 
+0

Ouais, je pense que c'est ce que je vais faire avec. Je pourrais créer un fichier XSD en même temps, car cela donne aussi l'avantage de laisser IntelliSense de Visual Studio :) –

0

Vous pouvez utiliser XPathSelectElements

Une autre chose qui vient à l'esprit est de définir un schéma XSD et de valider votre fichier XML par rapport à ce schéma. Cela générera des messages d'erreur significatifs et si le fichier est valide, vous pouvez l'analyser sans problèmes.

Questions connexes