How do i get all "properties" from xml via linq to xml
c#, linq, linq-to-xml
Solution
EDIT: updated code with `ToDictionary` approach for clarity and efficiency.
You can try the following sample. If you remove `Record` from the `select new Record` line it will result in an anonymous type and still work. Your `Record` class should have a default parameterless constructor to use the object initializer if you have provided other constructors (it will also work if you have no constructors). Otherwise you can use the available constructors instead of the object initializer.
Note that the use of `Single()` and `Value` assume the XML is well formed without any missing elements.
var xml = XElement.Parse(@"<records>
<record index=""1"">
<property name=""Username"">Sven</property>
<property name=""Domain"">infinity2</property>
<property name=""LastLogon"">12/15/2009</property>
</record>
<record index=""2"">
<property name=""Username"">Josephine</property>
<property name=""Domain"">infinity3</property>
<property name=""LastLogon"">01/02/2010</property>
</record>
<record index=""3"">
<property name=""Username"">Frankie</property>
<property name=""Domain"">wk-infinity9</property>
<property name=""LastLogon"">10/02/2009</property>
</record>
</records>");
var query = from record in xml.Elements("record")
let properties = record.Elements("property")
.ToDictionary(p => p.Attribute("name").Value, p => p.Value)
select new Record
{
Index = record.Attribute("index").Value,
Username = properties["Username"],
Domain = properties["Domain"],
LastLogon = properties["LastLogon"]
};
foreach(var rec in query)
{
Console.WriteLine("ID: {0} User:{1} Domain:{2} LastLogon:{3}", rec.Index, rec.Username, rec.Domain, rec.LastLogon);
}
EDIT: I've updated the code sample above with the `ToDictionary` approach which is cleaner and quicker. Based on my benchmarking efforts the fastest was `ToDictionary`, followed by `Func`, and then the `Where` approach.
Original Query
var query = from record in xml.Elements("record")
let properties = record.Elements("property")
select new Record
{
Index = record.Attribute("index").Value,
Username = properties.Where(p => p.Attribute("name").Value == "Username").Single().Value,
Domain = properties.Where(p => p.Attribute("name").Value == "Domain").Single().Value,
LastLogon = properties.Where(p => p.Attribute("name").Value == "LastLogon").Single().Value
};
Query with Func
Redundancy of the original query can be reduced by using the following code:
Func<XElement, string, string> GetAttribute =
(e, property) => e.Elements("property")
.Where(p => p.Attribute("name").Value == property)
.Single().Value;
var query = from record in xml.Elements("record")
select new Record
{
Index = record.Attribute("index").Value,
Username = GetAttribute(record, "Username"),
Domain = GetAttribute(record, "Domain"),
LastLogon = GetAttribute(record, "LastLogon")
};
Problem
XML sample (original link): ``` <records> <record index="1"> <property name="Username">Sven</property> <property name="Domain">infinity2</property> <property name="LastLogon">12/15/2009</property> </record> <record index="2"> <property name="Username">Josephine</property> <property name="Domain">infinity3</property> <property name="LastLogon">01/02/2010</property> </record> <record index="3"> <property name="Username">Frankie</property> <property name="Domain">wk-infinity9</property> <property name="LastLogon">10/02/2009</property> </record> </records> ``` I'm wanting to get an instance of a class per record in the xml. i found similar examples in here but they only had a root, then one element deep. It works, right up until i put that other element in. i want to be able to do something like ``` foreach(Record rec in myVar) { Console.WriteLine("ID: {0} User:{1} Domain:{2} LastLogon:{3}",rec.Index, rec.Username, rec.Domain, rec.LastLogon); } ```