2010-11-07 7 views
1

permet de supposer un fichier xml nommé data.xml avec le contenu suivant:C# LINQ to requête xml aide

<root> 
<record> 
<id>1</id> 
<name>test 1</name> 
<resume>this is the resume</resume> 
<specs>these are the specs</specs> 
</record> 
<record> 
<id>2</id> 
<name>test 2</name> 
<resume>this is the resume 2</resume> 
</record> 
<record> 
<id>3</id> 
<name>test 3</name> 
<specs>these are the specs 3</specs> 
</record> 
</root> 

J'ai besoin de chercher tous les dossiers où l'un de ces champs (id, nom, curriculum vitae ou spécifications) contient une valeur donnée. J'ai créé ce code

XDocument DOC = XDocument.Load("data.xml"); 
IEnumerable<ProductRecord> results = from obj in DOC.Descendants("record") 
    where 
obj.Element("id").Value.Contains(valueToSearch) || 
obj.Element("name").Value.Contains(valueToSearch) || 
obj.Element("resume").Value.Contains(valueToSearch) || 
obj.Element("specs").Value.Contains(valueToSearch) 
    select new ProductRecord { 
ID = obj.Element("id").Value, 
Name = obj.Element("name").Value, 
Resume = obj.Element("resume").Value, 
Specs = obj.Element("specs").Value 
    }; 

Ce code génère une erreur de NullReference car tous les enregistrements ne possèdent pas tous les champs. Comment puis-je tester si l'enregistrement en cours a un élément donné avant de définir une condition à appliquer? Ex. L'enregistrement [@ ID = 3] n'a pas de résumé.

Merci à l'avance

Répondre

0

Vous pouvez écrire une méthode d'extension qui est comme ci-dessous:

public static class XMLExtension 
{ 
    public static string GetValue(this XElement input) 
    { 
     if (input != null) 
      return input.Value; 
     return null; 
    } 

    public static bool XMLContains(this string input, string value) 
    { 
     if (string.IsNullOrEmpty(input)) 
      return false; 
     return input.Contains(value); 
    } 
} 

et l'utiliser comme ci-dessous:

IEnumerable<ProductRecord> results = from obj in DOC.Descendants("record") 
               where 
              obj.Element("id").GetValue().XMLContains(valueToSearch) || ... 
+0

Merci beaucoup! – adaoss

0

Vous obtenez un NullReferenceException parce que vous essayez d'accéder à la valeur de certains nœuds qui n'existent pas pour chaque record comme specs. Vous devez vérifier si obj.Element("specs") != null avant d'appeler .Value à ce sujet.

Comme alternative, vous pouvez utiliser XPath:

var doc = XDocument.Load("test.xml"); 
var records = doc.XPathSelectElements("//record[contains(id, '2') or contains(name, 'test') or contains(resume, 'res') or contains(specs, 'spe')]"); 
0

D'abord, je suis étonné que ça ne plante pas parce que vous n'utilisez pas l'espace de noms. Peut-être que C# 4.0 a contourné cela?

essayer Quoi qu'il en soit

obj.Descendants("id").Any() ? root.Element("id").Value : null 

C'est:

select new ProductRecord { 
    ID = obj.Descendants("id").Any() ? root.Element("id").Value : null, 
    Name = obj.Descendants("name").Any() ? root.Element("name").Value : null, 
    Resume = obj.Descendants("resume").Any() ? root.Element("resume").Value : null 
    Specs = obj.Descendants("specs").Any() ? root.Element("specs").Value : null 
}; 
+0

le problème n'est pas dans select, je l'ai bypassé avec ce code Specs = (string) obj.Element ("Specs") ?? "n/a". Le problème principal est dans la clause where ... – adaoss

+0

Essayez d'utiliser la même logique? (chaîne de caractères) obj.Element ("Specs") ?? vrai. Comme si l'objet n'existait pas, vous souhaitez le considérer comme une véritable option pour cet enregistrement. – Kamal