简体   繁体   中英

Parsing XML with LINQ in C#

I am trying to do a mapping between C# and XML with LINQ. Currently, I have a class defined in C# that looks like this:

Item.cs

public class Item
{
  public string DepartmentName { get; set; }
  public Dictionary<string, string> DepartmentNames { get; set; }

  public string Name { get; set; }
  public Dictionary<string, string> Names { get; set; }
}

My XML file looks like this:

departments.xml

<Departments>
  <Department Name="Sports" Title="Sports Department" Path="/sports" en-us="Sports" de-de="Sport">
    <Item Name="Football" en-us="Football" de-de="Fußball" es-mx="" />
    <Item Name="TennisBall" en-us="Tennis Ball" de-de="Tennisball" />
  </Department>

  <Department Name="Automotive" Title="Automotive Department" Path="/autos" en-us="Automotive" de-de="kraftfahrtechnisch">
    <Item Name="Oil" en-us="Oil" de-de="Öl" />
    <Item Name="Tires" en-us="Tires" de-de="Bereifung" es-mx="Ruedas" />
  </Department>
</Departments>

Basically, I have some values I want to load into a definite properties. Then, I have a list of attributes I know ("en-us", "de-de", "es-mx") that I want to load into Dictionaries. Currently, I have the following:

var items = XDocument.Parse(File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\Items.xml")))
  .Element("Departments")
  .Elements("Department")
  .Elements("Item")
  .Select(e => new Item
  {
    DepartmentName = ?,
    DepartmentNames = ?,
    Name = e.Attribute("Name").Value,
    Names = ?
  }).ToList();

I'm not sure how to load the properties from a) The parent elements b) Load the Dictionary object. Is this even possible with LINQ? Essentially, I'm trying to flatten out my data structure in-memory.

In cases like this, where you need to access properties of outer elements in nested loops, I find the Linq from / select syntax to be more comfortable. Thus:

        var doc = XDocument.Load(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "InputData.xml"));
        var query = from department in doc.Element("Departments").Elements("Department")
                    from item in department.Elements("Item")
                    select new Item
                    {
                        DepartmentName = department.Attribute("Name").Value,
                        DepartmentNames = department.Attributes().Where(a => a.Name != "Name").ToDictionary(a => a.Name.LocalName, a => a.Value),
                        Name = item.Attribute("Name").Value,
                        Names = item.Attributes().Where(a => a.Name != "Name").ToDictionary(a => a.Name.LocalName, a => a.Value),
                    };
        var items = query.ToList();

Here I am assuming you want every attribute placed in the dictionary other than the Name attribute, which has its own property.

Update

If you have a known list of attributes to put in the dictionary, you can do:

        var attributes = new HashSet<string>(new[] { "en-us", "de-de", "es-mx" }); // Possibly initialized in a static constructor.

        var query = from department in doc.Element("Departments").Elements("Department")
                    from item in department.Elements("Item")
                    select new Item
                    {
                        DepartmentName = department.Attribute("Name").Value,
                        DepartmentNames = department.Attributes().Where(a => attributes.Contains(a.Name.LocalName)).ToDictionary(a => a.Name.LocalName, a => a.Value),
                        Name = item.Attribute("Name").Value,
                        Names = item.Attributes().Where(a => attributes.Contains(a.Name.LocalName)).ToDictionary(a => a.Name.LocalName, a => a.Value),
                    };
        var items = query.ToList();

I think that the code below is what you want. I tested here and it worked, but I'm not sure if this is what you intent. I'm just filling the dictionaries with all values of languages.

            var items = XDocument.Parse(
            File.ReadAllText(
            Path.Combine(
                Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), 
                "InputData.xml")))
                      .Element("Departments")
                      .Elements("Department")
                      .Select(
                      d => d.Elements("Item").Select(e => new Item
                      {
                        DepartmentName = d.Attribute("Name").Value,
                        DepartmentNames = new Dictionary<string,string>()
                        {
                            { "en-us", d.Attribute("en-us").Value },
                            { "de-de", d.Attribute("de-de").Value}
                        },
                        Name = e.Attribute("Name").Value,
                        Names = new Dictionary<string,string>()
                        {
                            { "en-us", e.Attribute("en-us").Value},
                            { "de-de", e.Attribute("de-de").Value}
                        }
                      })).ToList();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM