Ilya
Ilya

Reputation: 1223

How can I dynamically add to a list using linq for nested nodes?

Let's say I have a struct called Woah. Woah has one field to store the value of SomeChild below but also contains a List<Woah> to contain other Woah structs. The XML I am reading has the structure of:

<WoahWrapper>
  <Woahs>
    <WoahNode>
      <SomeChild />
      <SubWoahs>
         <WoahNode />
      </SubWoahs>
     </WoahNode>
   </Woahs>
</WoahWrapper>

So here I can assign SomeChild to to a struct I create in "select new" in my linq, but is there a way I can easily initialize that list in my struct and add to it all the WoahNodes that exist in SubWoahs?

    var list = (from c in mapData.Root.Element("Woahs").Elements("WoahNode")
                    select new Woah()
                    {
                        somechild = Convert.ToInt32(c.Element("SomeChild").Value),
                        //If there are Woahs in SubWoahs, initialize list in struct and add each Woah SubWoahs to that list
                    });

Upvotes: 0

Views: 301

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1063338

Firstly, DTOs make lousy structs; structs should be values (not entities), immutable, and small. Your Woah is none of these. It should be a class.

One approach here might be a recursive function, which for small bits of logic you can (if you choose) re-write as an anonymous method:

var mapData = XDocument.Parse(xml);

Func<XElement, Woah> builder = null;
builder = c => {
    var woah = new Woah { SomeChild = (int)c.Element("SomeChild") };
    foreach(var sub in c.Elements("SubWoahs").Elements("WoahNode"))
        woah.Children.Add(builder(sub));
    return woah;
};
var list = (from c in mapData.Root.Element("Woahs").Elements("WoahNode")
            select builder(c)).ToList();

However, personally I think XmlSerializer would be simpler here...

XmlSerializer ser = new XmlSerializer(typeof(WoahWrapper));
var list = ((WoahWrapper)ser.Deserialize(new StringReader(xml))).Woahs;

with types:

public class WoahWrapper
{
    private List<Woah> woahs = new List<Woah>();
    [XmlArray("Woahs"), XmlArrayItem("WoahNode")]
    public List<Woah> Woahs { get { return woahs; } }
}
public class Woah
{
    public int SomeChild { get; set; }
    private List<Woah> children;
    [XmlArray("SubWoahs"), XmlArrayItem("WoahNode")]
    public List<Woah> Children { get { return children ?? (
        children = new List<Woah>()); } }
}

Upvotes: 1

Related Questions