Reputation: 1983
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.
Upvotes: 2
Views: 3682
Reputation: 117293
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();
Upvotes: 3
Reputation: 1384
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();
Upvotes: 0