tags:

views:

121

answers:

2

I have a list of String

      List<String> lst=new List<String>{"A","B","C"}

And an xml file like

<Root>
<ChildList>
   <Childs>
      <Child Name="a1" Val="A"/>
      <Child Name="a2" val="A"/>
      <Child Name="b1" val="B"/>
   </Childs>
 </ChildList>
 </Root>

i need to read contets of the xml file and add to a dictionary

    Dictionary<String,List<String>> dict

where the dictionary key is the items in the "lst" and value is the attribute value of "Name" from the file

So the result will be like

   Key(String)            Value(List<String>)

   "A"                          "a1","a2"
   "B"                           "b1"
   "C"                           null

now i'm using nested for loop for this

Is there any wau to do this using LINQ to XML

Thanks in advance

+1  A: 
var xml = @"<Root>
<ChildList>
   <Childs>
      <Child Name=""a1"" Val=""A""/>
      <Child Name=""a2"" Val=""A""/>
      <Child Name=""b1"" Val=""B""/>
   </Childs>
 </ChildList>
 </Root>";

var lst= new List<String> { "A", "B", "C" };
var doc = XDocument.Parse(xml);

var dict = (from item in lst
            select new
            {
                Key = item,
                Value = (from elem in doc.Root.Element("ChildList").Element("Childs").Elements("Child")
                         where (string)elem.Attribute("Val") == item
                         select (string)elem.Attribute("Name")).ToList()
            }).ToDictionary(i => i.Key, i => i.Value);

This can be made more efficient. I iterate over the elements once for every item in lst. I'll properly come up with another solution later if others don't come up with one.

lasseespeholt
@ lasseespeholt : Thank you
Pramodh
+2  A: 

I think this will do it:

XDocument doc = XDocument.Load("foo.xml");
ILookup<string, string> lookup = doc.Descendants("Childs")
                                    .First()
                                    .Elements("Child")
                                    .ToLookup(x => (string) x.Attribute("Val"),
                                              x => (string) x.Attribute("Name"));

var dictionary = lst.ToDictionary(x => x,
                         x => lookup[x].ToList().NullIfEmpty());

Using a helper method:

public static List<T> NullIfEmpty<T>(this List<T> list)
{
    return list.Count == 0 ? null : list;
}

If you don't mind having an empty list instead of null for items which aren't in the XML file, the second statement can be simplified, with no need for the helper method:

var dictionary = lst.ToDictionary(x => x, x => lookup[x].ToList());

Note that I've structured this so that it only needs to go through the XML file once, instead of searching through the file once for each element in the list.

Jon Skeet
+1 Nice solution...
lasseespeholt
@ Jon Skeet: Thank you
Pramodh
@Jon Skeet, I think the ToDictionary should be `var dictionary = lookup.ToDictionary(x => x.Key, x => lookup[x.Key].ToList());`.
Chris Taylor
@ Jon Skeet: Can you please explain the uses of ILookup
Pramodh
@Chris: No, because then you won't see entries in `lst` which aren't in the lookup. Also, in that case you'd just do `... = lookup.ToDictionary(x => x.Key, x => x.Value.ToList());` without looking the key up again.
Jon Skeet
@Pramodh: Basically it's like a dictionary, but where each key is associated with multiple values. Note that unlike a normal dictionary, if you ask for a key which doesn't exist in the lookup, it returns an empty sequence.
Jon Skeet
@Jon, ah sorry I missed that `lst` was from the code in the question.
Chris Taylor
@ Jon Skeet: Thank you.... :-)
Pramodh