YouneL
YouneL

Reputation: 8351

Get XElements List of XElements List from XML document using linq to xml

I create a list of node object:

public class Node
{
    public string Key { get; set; }
    public string Value { get; set; }
}

public class ListNode : List<Node> {  }

And i have an xml document :

<details>
<detail>
  <node>
    <key>xxx</key>
    <value>111</value>
  </node>
  <node>
    <key>yyy</key>
    <value>222</value>
  </node>
</detail>
<detail>
  <node>
    <key>zzz</key>
    <value>333</value>
  </node>
  <node>
    <key>aaa</key>
    <value>444</value>
  </node>
</detail>
</details>

what i want to do is to put these xml elements to a List of ListNode objects using linq to xml:

<node> => Node Object
<detail> => ListNode
<details> => List<ListNode>

this is my linq to xml request:

List<ListNode> listNodeDetails = xElement
    .Element("details")
    .Elements("detail")
    .Elements("node")
    .Select(n => new Node() 
        { Key = n.Element("key").Value, 
          Value = n.Element("node").Element("value").Value 
        })
    .ToList();

Upvotes: 1

Views: 3198

Answers (2)

juharr
juharr

Reputation: 32266

First you don't really need the Node or ListNode classes. You should be able to get the same results using KeyValuePair<string,string> (or Tuple<string,string>) and List<KeyValuePari<string,string>> (or List<Tuple<string,string>>). Here's how you can get your desired results as a List<List<KeyValuePair>>

var results =
    element.Elements("detail")
            .Select(
                x =>
                    x.Elements("node")
                    .Select(n => new KeyValuePair<string, string>(
                        n.Element("key").Value, 
                        n.Element("value").Value))
                    .ToList())
            .ToList();

The trick here is that you have an inner linq statement that builds up the List<KeyValuePair<string,string>> while the outer linq statement builds that up into the List<List<KeyValuePair>>. Also you have to use Elements instead of Element to get a colleciton of all the desired elements.

It's trivial to substitute in your Node class (or Tuple<string,string>). But it's a little more difficult, and unnecessary, to substitute in your ListNode class.

However here is how you can get a List<ListNode> as you currently have the ListNode class defined.

List<ListNode> list = new List<ListNode>();
foreach (var detail in element.Elements("detail"))
{
    var nodeList = new ListNode();
    nodeList.AddRange(
        detail.Elements("node")
            .Select(
                n => new Node
                {
                    Key = n.Element("key").Value,
                    Value = n.Element("value").Value
                }));
    list.Add(nodeList);
}

Here you have to create a ListNode before adding the nodes versus using the ToList extension method. You could make that foreach into a linq expression, but I typically avoid lambdas that have multiple statements whenever possible.

Upvotes: 3

Martin Dunsmore
Martin Dunsmore

Reputation: 86

You've not really said where you're stuck... Anyway, this should do the trick.

var xdoc = XDocument.Load("Test.xml");

var listNodeDetails = xdoc.Root
    .Elements("detail")
    .Elements("node").Select(
        n => new Node
        {
            Key = n.Element("key").Value,
            Value = n.Element("value").Value
        }).ToList();

Upvotes: 1

Related Questions