LINQ to XML: la selección de los elementos si un valor de atributo es igual a un valor de nodo en un IEnumerable <XElement>


8

puedo crear un objeto IEnumerable que solo contiene los nodos que quiero de un archivo xml:

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

Así que es una colección de éstos:

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

Quiero agarrar sólo los usuarios donde el atributo userid es también un nodo userid dentro de la colección rosters.

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

Pero es que me da un error:

Los argumentos de tipo para el método 'System.Linq.Enumerable.Contains (System.Collections.Generic.IEnumerable, TSource)' no puede deducirse de la uso. Intente especificar los argumentos de tipo explícitamente.

¿Qué pasa con mi enfoque?

6

Un problema que veo es que en el último fragmento de código, ...Elements("userid") devuelve una lista de objetos XElement que no pueden contener una cadena devuelta por la propiedad Value. Esto debería funcionar ...

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)); 

Sin embargo me gustaría hacer esto mediante el uso de una consulta de unión .. Seleccionar usuario se una listas de ID de usuario
Sería algo como esto

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); 
} 

Salidas:

User on roster  on Roster R1