Linq à Xml: sélection d'éléments si une valeur d'attribut est égale à une valeur de noeud dans un IEnumerable <XElement>


8

je crée un objet IEnumerable qui ne contient que les nœuds que je veux partir d'un fichier xml:

IEnumerable<XElement> rosters = XDocument.Load("roster.xml") 
             .Elements("rosterlist") 
             .Elements("roster") 
             .Where(w => w.Element("division") 
                 .Value 
                 .Equals("SUPER AWESOME DIVISION")); 

Il est donc une collection de ceux-ci:

<rosterlist> 
    <roster> 
     <userid>1</userid> 
     <name></name> 
     <etc></etc> 
    </roster> 
    <roster> 
     <userid>2</userid> 
     <name></name> 
     <etc></etc> 
    </roster> 
</rosterlist> 

Je veux saisir uniquement les utilisateurs dont l'attribut userid est également un nœud userid dans la collection rosters.

IEnumerable<XElement> users = XDocument.Load("user.xml") 
             .Elements("userlist") 
             .Elements("user") 
             .Where(w => rosters.Elements("userid") 
                  .Contains(w.Attribute("userid").Value)); 

Mais il me donne une erreur:

Les arguments de type pour la méthode 'System.Linq.Enumerable.Contains (System.Collections.Generic.IEnumerable, Tsource)' ne peut pas être déduite de la usage. Essayez de spécifier explicitement les arguments de type.

Quel est le problème avec mon approche?

6

Un problème que je vois est que dans le dernier extrait de code, ...Elements("userid") renvoie une liste d'objets XElement qui ne peuvent pas contenir de chaîne renvoyée par la propriété Value. Cela devrait fonctionner ...

IEnumerable<XElement> rosters = obRoot.Elements("rosterlist").Elements("roster"); 
var rosterUserIds = (rosters.Elements("userid").Select(r => r.Value)); 
IEnumerable<XElement> users = obRoot.Elements("userlist").Elements("user") 
       .Where(u => rosterUserIds.Contains(u.Attribute("userid").Value)); 

Cependant, je ferais cela en utilisant une requête de jointure .. Sélectionner un utilisateur se joindre sur les listes userid
Ce serait quelque chose comme ça

string sXml = @" 
<root> 
<rosterlist> 
    <roster> 
     <userid>1</userid> 
     <name>R1</name> 
     <etc></etc> 
    </roster> 
    <roster> 
     <userid>2</userid> 
     <name>R2</name> 
     <etc></etc> 
    </roster> 
</rosterlist> 
<userlist> 
    <user userid='1'> 
     <name>User on roster</name> 
    </user> 
    <user userid='5'> 
     <name>User not on roster</name> 
    </user> 
</userlist> 
</root> 

"; 

XElement obRoot = XElement.Parse(sXml); 
var results = from user in obRoot.Elements("userlist").Elements("user") 
    join roster in obRoot.Elements("rosterlist").Elements("roster") 
    on user.Attribute("userid").Value equals roster.Element("userid").Value 
    select new {Name=user.Element("name").Value, RosterName=roster.Element("name").Value} ; 

foreach (var v in results) 
{ 
    Console.WriteLine("{0, -20} on Roster {1, -20}", v.Name, v.RosterName); 
} 

Sorties:

User on roster  on Roster R1