1

I have an XML file for settings. Here is an example with a few elements:

<Settings>
    <Templates>
        <Item name="Home" value="{B0BDB6B6-CB6E-464A-A170-6F88E2B3B10F}" />
        <Item name="DevelopmentLanding" value="{3F66C5BA-BE16-4E29-A9D8-0FFBCEA4C791}" />
        <Item name="EventsLanding" value="{A1D51F12-D449-4933-8C0E-B236F291D050}" />
    </Templates>
    <Application>
        <Item name="MemberDomain" value="extranet" />
        <Item name="SearchCacheHours" value="0" />
        <Item name="SearchCacheMinutes" value="10" />
    </Application>
</Settings>

I also have two classes:

public class Setting
{
    public string Type { get; set; }
    public IEnumerable<SettingItem> SettingItems { get; set; }
}

and

public class SettingItem
{
    public string Name { get; set; }
    public string Value { get; set; }
}

I want to take the XML file and strongly type it using my two classes, so then I'd end up with a List<Setting>.

This is the code I have so far to do this:

var xml = XDocument.Load(HttpContext.Current.Server.MapPath(AppConfig.SettingsFileLocation));
var root = xml.Root;

var toplevel = root.Elements().AsEnumerable()
                   .Select(item => new Setting
                        {
                            Type = item.Name.ToString(),
                            SettingItems = item.Elements(item.Name.ToString()).AsEnumerable()
                                                        .Select(x => new SettingItem
                                                            {
                                                                Name = x.Attribute("name").ToString(),
                                                                value = x.Attribute("value").ToString()
                                                            }
                                                ).ToList()
                                });

However, when I run this, I don't have anything in Setting.SettingItems.

Where am I going wrong?

Piers Karsenbarg
  • 3,105
  • 5
  • 31
  • 67
  • Blech... IMHO, you went wrong with using LINQ to XML for a query of any significant complexity, but I admit that's a personal prejudice... this is difficult to read, though. – Jeremy Holovacs Apr 09 '13 at 16:37
  • How would you suggest doing it instead? – Piers Karsenbarg Apr 09 '13 at 16:40
  • when passing in the name to the `Elements(...)` method, what does it do? It looks to me like that's where the issue is. I see at the top you select elements with default parameters only, but on the inside you use the item.name as a parameter... – Nevyn Apr 09 '13 at 16:42
  • From msdn: http://msdn.microsoft.com/en-us/library/bb348975.aspx – Piers Karsenbarg Apr 09 '13 at 16:47

3 Answers3

1

I'm not sure why your code isn't working, but something like this should work:

            var toplevel = doc.Root.Elements().Select(settingElement => new Setting
                {
                    Type = settingElement.Name.LocalName,
                    SettingItems = settingElement.Elements("Item").Select(itemElement => new SettingItem
                        {
                            Name = itemElement.Attribute("name").Value,
                            Value = itemElement.Attribute("value").Value,
                        })
                }).ToList();
gerrard00
  • 1,628
  • 14
  • 17
1

Have you considered another approach to LINQ? For example, you could generate strongly typed classes using xsd.exe, as described in this answer. Loading the data from the XML could be done via deserialization, example in this answer.

Side note: the XML is badly formed XML (the last line should be </Settings>).

Community
  • 1
  • 1
Geoff
  • 8,551
  • 1
  • 43
  • 50
  • Yeah, that's not the actual settings file, it's a cut down version of it. There are lots of settings. Also, I want XMl file to be read in on the fly, not via a .exe but thanks. – Piers Karsenbarg Apr 10 '13 at 09:42
  • 1
    As long as you know the *schema* you should be able to generate the classes in advance; the xsd tool first generates a schema (which you can edit), then generates the code from that. – Geoff Apr 10 '13 at 17:33
0

Your problem is the line:

SettingItems = item.Elements(item.Name.ToString()).AsEnumerable()

it should read:

SettingItems = item.Elements()

You want all the child elements of item (the "Templates" or "Application" node), not the ones also named "Templates" or "Application". The AsEnumerable is just unnecessary, since Elements() returns an IEnumerable already.

Jon
  • 3,065
  • 1
  • 19
  • 29