I want to process certain elements of an XML string into an object based on the properties in the object matching up to the names of elements in the XML.
An example structure of the XML is as follows:
<Bar>
<Body>
<Header>
<A>Value</A>
<B>true</B>
</Header>
<Data>
<D>Value</D>
</Data>
<Data>
<D>Value2</D>
<Data>
</Body>
</Bar>
There can be MANY <Data> elements in the XML, however <Header> only exists once. The class I have set up is as so:
public class Foo
{
public string A { get; set; }
public bool B { get; set; }
public List<FooData> { get; set; }
public void ProcessXml(string xml)
{
XDocument xDoc = XDocument.Load(new StringReader(xml));
var propVals = (from ele in xDoc.Descendants()
join prop in this.GetType().GetProperties() on ele.Name.LocalName equals prop.Name
select new
{
prop = prop,
val = new Func<object>(() =>
{
object objValue = null;
prop.PropertyType.TryParse(ele.Value, ref objValue);
return objValue;
}).Invoke()
});
propVals.ToList().ForEach(x => x.prop.SetValue(this, x.val, null));
}
}
public class FooData
{
public string D { get; set; }
}
I came up with the method ProcessXml which starts to set things up, however at the minute I am only ever setting Header values (A, B), any ideas on how I can add many FooData items into the List from within the same method easily?
public static class TypeExtensions
{
public static void TryParse(this Type t, object valIn, ref object valOut)
{
//Do some parsing logic
try{
out = TypeDescriptor.GetConverter(t).ConvertFromInvariantString(valIn);
return true;
} catch(Exception) { return false; }
}
}
I went along a similar line as what I did with the header stuff as there isn't an easy way to combine this into one line.
var dataElements = (from dataDescendants in (from ele2 in xDoc.Descendants()
Where ele2.Name.LocalName == "Data"
select ele2.Descendants())
from dataDescendant in dataDescendants
join prop in typeof(FooItem).GetProperties() on prop.Name equals dataDescendant.Name.LocalName
select Element = dataDescendant, Property = prop, dataDescendants
group by dataDescendants into g = group
select g).ToList();
dataElements.ForEach(dataElement =>
{
FooItem fi = new FooItem();
dataElement.ToList.ForEach(x =>
{
object objVal = null;
x.Property.PropertyType.TryParse(x.Element.Value, objVal);
x.Property.SetValue(fi, objVal, null);
}
DataItems.Add(fi);
}
If your XML is really that simple, you can use Serialization to get this dynamic/self loading behavior, by decorating your model classes with the appropriate XML Serialization attributes though you will need at least 1 class for each level of indentation in the document:
void Main()
{
var xml = #"<Bar>
<Body>
<Header>
<A>Value</A>
<B>true</B>
</Header>
<Data>
<D>Value</D>
</Data>
<Data>
<D>Value2</D>
</Data>
</Body>
</Bar>";
var serializer = new XmlSerializer(typeof(Bar));
serializer.Deserialize( new MemoryStream( Encoding.ASCII.GetBytes( xml ) ) ).Dump();
}
public class Bar
{
public Body Body { get; set; }
}
public class Body
{
public Header Header { get; set; }
[XmlElement]
public Data[] Data { get; set; }
}
public class Header
{
public string A { get; set; }
public string B { get; set; }
}
public class Data
{
public string D { get; set; }
}
(Edited: I missed that there's only 1 Header element)
Related
I want final xml as follows...
<Programs>
<Program><id>4</id><isRead>true</isRead><isWrite>false</isWrite></Program>
<Program><id>8</id><isRead>true</isRead><isWrite>true</isWrite></Program>
</programs>
now following is the code written
XmlDocument xmlDoc = new XmlDocument();
XmlNode rootNode = xmlDoc.CreateNode(XmlNodeType.Element,"programs",null);
xmlDoc.AppendChild(rootNode);
foreach (dynamic item in access)
{
XmlNode myXmlNode = JsonConvert.DeserializeXmlNode(item.ToString(), "program");
rootNode.AppendChild(myXmlNode); //error
}
where in myXmlNode.InnerXml, I am already getting following
<Program><id>4</id><isRead>true</isRead><isWrite>false</isWrite></Program>
And so, running the loop for all children to add in which is parent. But I am getting error for line //error as marked above. Error is:
The specified node cannot be inserted as the valid child of this node,
because the specified node is the wrong type.
You are trying to insert different type of xml node. You could use ImportNode to apply it.
foreach (dynamic item in access)
{
XmlNode myXmlNode = JsonConvert.DeserializeXmlNode(item.ToString(), "program");
rootNode.AppendChild(rootNode.OwnerDocument.ImportNode(myXmlNode.FirstChild,true));
}
I would recommend you create a model for what you are looking to create in XML, then serialize a list of the model to XML.
The reason being that you will end up with something far more maintainable.
Your model would be something like this:
public class Program
{
public int Id { get; set; }
public bool IsRead { get; set; }
public bool IsWrite { get; set; }
}
And you can serialize it by following this article:
https://support.microsoft.com/en-gb/help/815813/how-to-serialize-an-object-to-xml-by-using-visual-c
I've used the XmlSerializer library myself a few times.
public class Program
{
public int Id { get; set; }
public bool IsRead { get; set; }
public bool IsWrite { get; set; }
}
public class XmlTemplate
{
public List<Program> Programs { get; set; }
}
class MainProgram
{
static void Main(string[] args)
{
var xmlTemplate = new XmlTemplate();
xmlTemplate.Programs = new List<Program>();
xmlTemplate.Programs.Add(new Program() { Id = 123, IsRead = true, IsWrite = false });
xmlTemplate.Programs.Add(new Program() { Id = 456, IsRead = false, IsWrite = true });
var serializer = new XmlSerializer(typeof(XmlTemplate));
var stream = new StringWriter();
serializer.Serialize(stream, xmlTemplate);
Console.WriteLine(stream.ToString());
Console.ReadKey();
}
}
This outputs the XML in the following format:
<XmlTemplate xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Programs>
<Program>
<Id>123</Id>
<IsRead>true</IsRead>
<IsWrite>false</IsWrite>
</Program>
<Program>
<Id>456</Id>
<IsRead>false</IsRead>
<IsWrite>true</IsWrite>
</Program>
</Programs>
</XmlTemplate>
I'm facing an issue with the .Net XmlSerializer, basically I need one or more elements with same name to be serialized (and deserialized) dynamically between other elements of fixed schema.
Example:
<?xml version="1.0" encoding="utf-8"?>
<A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<asd>asd</asd>
<nnn>q</nnn>
<nnn>w</nnn>
<nnn>e</nnn>
<aaa>aaa</aaa>
</A>
My real <nnn> tag is a little bit more complicated, with dynamic tags inside (not only conditionals), but I'm currently threating this right.
I really need to use the "Order" parameter of XmlElement to control some rules.
I can't change the XML layout.
The example serializable class:
[XmlRoot]
[Serializable]
public class A
{
[XmlElement("asd", Order=1)]
public string asd { get; set; }
[XmlIgnore]
public string[] qwe { get; set; }
[XmlAnyElement("nnn", Order=2)]
public XmlNode[] nnn
{
get
{
if (qwe == null) return null;
var xml = new XmlDocument();
var nodes = new List<XmlNode>(qwe.Length);
foreach (var q in qwe)
{
var nnnTag = xml.CreateNode(XmlNodeType.Element, "nnn", null);
nnnTag.InnerText = q;
nodes.Add(nnnTag);
}
return nodes.ToArray();
}
set
{
if (value == null) return;
qwe = value.Select(tag => tag.InnerText).ToArray();
}
}
[XmlElement("aaa", Order=3)]
public string aaa { get; set; }
The problem is, when not using the "Order" parameter the serialization goes fine, but with the parameter the elements after the XmlAnyElement are understood as part of the array of nodes and so are not deserialized right.
My main program for the example is a Console Application with the following main:
static void Main(string[] args)
{
var a = new A
{
aaa = "aaa",
asd = "asd",
qwe = new[] {"q", "w", "e"}
};
var s = Serialize(a);
var ss = Deserialize<A>(s);
var s2 = Serialize(ss);
Console.WriteLine(s);
Console.WriteLine(s2);
Console.WriteLine("Equals: {0};", s == s2);
Console.ReadKey();
}
The wrong output is:
<?xml version="1.0" encoding="utf-8"?>
<A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<asd>asd</asd>
<nnn>q</nnn>
<nnn>w</nnn>
<nnn>e</nnn>
<aaa>aaa</aaa>
</A>
<?xml version="1.0" encoding="utf-8"?>
<A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<asd>asd</asd>
<nnn>q</nnn>
<nnn>w</nnn>
<nnn>e</nnn>
<nnn>aaa</nnn>
</A>
Equals: False;
For testing, here is the Serialization/Deserialization snippets I'm using:
public static string Serialize<T>(T a)
{
var s = new XmlSerializer(typeof(T));
using (var ms = new MemoryStream())
{
using (TextWriter sw = new StreamWriter(ms))
{
s.Serialize(sw, a);
ms.Seek(0, 0);
using (var sr = new StreamReader(ms))
{
return sr.ReadToEnd();
}
}
}
}
public static T Deserialize<T>(string a)
{
var s = new XmlSerializer(typeof(T));
var bytes = Encoding.ASCII.GetBytes(a);
using (var ms = new MemoryStream(bytes))
{
return (T) s.Deserialize(ms);
}
}
The full source code:
https://gist.github.com/inventti-gabriel/81054269f2e0a32d7e8d1dd44f30a97f
Thanks in advance.
I agree with #CharlesMager that this does appear to be a bug in XmlSerializer.
That being said, you can work around the bug by introducing an intermediate wrapper class or struct to contain the arbitrary nodes, then modifying your surrogate nnn property to return an array of these structs after marking the property with [XmlElement("nnn", Order = 2)]:
[XmlRoot]
[Serializable]
public class A
{
[XmlElement("asd", Order = 1)]
public string asd { get; set; }
[XmlIgnore]
public string[] qwe { get; set; }
[XmlElement("nnn", Order = 2)]
public XmlNodeWrapper [] nnn
{
get
{
if (qwe == null)
return null;
var xml = new XmlDocument();
var nodes = new List<XmlNode>(qwe.Length);
foreach (var q in qwe)
{
var nnnTag = xml.CreateNode(XmlNodeType.Element, "nnn", null);
nnnTag.InnerText = q;
nodes.Add(nnnTag);
}
return nodes.Select(n => (XmlNodeWrapper)n.ChildNodes).ToArray();
}
set
{
if (value == null)
return;
qwe = value.Select(tag => tag.InnerText()).ToArray();
}
}
[XmlElement("aaa", Order = 3)]
public string aaa { get; set; }
}
[XmlType(AnonymousType = true)]
public struct XmlNodeWrapper
{
public static implicit operator XmlNodeWrapper(XmlNodeList nodes)
{
return new XmlNodeWrapper { Nodes = nodes == null ? null : nodes.Cast<XmlNode>().ToArray() };
}
public static implicit operator XmlNode[](XmlNodeWrapper wrapper)
{
return wrapper.Nodes;
}
// Marking the Nodes property with both [XmlAnyElement] and [XmlText] indicates that the node array
// may contain mixed content (I.e. both XmlElement and XmlText objects).
// Hat tip: https://stackoverflow.com/questions/25995609/xmlserializer-node-containing-text-xml-text
[XmlAnyElement]
[XmlText]
public XmlNode[] Nodes { get; set; }
public string InnerText()
{
if (Nodes == null)
return null;
return String.Concat(Nodes.Select(n => n.InnerText));
}
}
Note that the Nodes property in XmlNodeWrapper is marked with both [XmlAnyElement] and [XmlText]. The requirement to do this is explained here.
Sample fiddle.
Try using XmlArrayAttribute in place of XmlAnyElement as the nodes are array
I am implementing a windows service and i need to consume a WebService with REST, I want to parse this to List but i dont know how.
My problem is that the names of the fields are separated from the data.
The structure I get is this:
<?xml version="1.0" encoding="utf-8" ?>
<xml>
<result>OK</result>
<headers>
<header>lastname</header>
<header>firstname</header>
<header>Age</header>
</headers>
<data>
<datum>
<item>Kelly</item>
<item>Grace</item>
<item>33</item>
</datum>
</data>
</xml>
You can use XmlSerializer to deserialize that XML into c# classes that reflect its structure. For instance:
[XmlRoot("xml")] // Indicates that the root element is named "xml"
public class XmlResponse
{
[XmlElement("result")] // Indicates that this element is named "result"
public string Result { get; set; }
[XmlArray("headers")] // Indicates two-level list with outer element named "headers" and inner elements named "header"
[XmlArrayItem("header")]
public List<string> Headers { get; set; }
[XmlArray("data")] // Indicates two-level list with outer element named "data" and inner elements named "datum"
[XmlArrayItem("datum")]
public List<XmlResponseDatum> Data { get; set; }
}
public class XmlResponseDatum
{
[XmlElement("item")] // Indicates a one-level list with repeated elements named "item".
public List<string> Items { get; set; }
}
Which you could deserialize like:
public static T LoadFromXML<T>(string xmlString)
{
using (StringReader reader = new StringReader(xmlString))
{
object result = new XmlSerializer(typeof(T)).Deserialize(reader);
if (result is T)
{
return (T)result;
}
}
return default(T);
}
public static string GetXml<T>(T obj)
{
using (var textWriter = new StringWriter())
{
var settings = new XmlWriterSettings() { Indent = true, IndentChars = " " }; // For cosmetic purposes.
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
new XmlSerializer(obj.GetType()).Serialize(xmlWriter, obj);
return textWriter.ToString();
}
}
public static void Test()
{
string xml = #"<?xml version=""1.0"" encoding=""utf-8"" ?>
<xml>
<result>OK</result>
<headers>
<header>lastname</header>
<header>firstname</header>
<header>Age</header>
</headers>
<data>
<datum>
<item>Kelly</item>
<item>Grace</item>
<item>33</item>
</datum>
</data>
</xml>";
var response = LoadFromXML<XmlResponse>(xml);
Debug.WriteLine(GetXml(response));
As an alternative, here is some XDocument and using objects that do not need to be Xml decorated.
I advocate this approach because it is easier to tweak the XDocument/Xpath statements in case the structure of the Xml changes.....as opposed to the XmlAttributes.
This also allows the same objects to be used, even if there are different xml streams hydrating it. You just write a different XDocument "shredder" for each Xml Input.
[DebuggerDisplay("MyNotUsedStringKey = {MyNotUsedStringKey}")]
public class ImportParent
{
public ImportParent()
{
this.MyNotUsedStringKey = Guid.NewGuid().ToString("N");
this.ImportChildren = new ImportChildCollection();
}
public ImportChildCollection ImportChildren { get; set; }
public string MyNotUsedStringKey { get; set; }
}
public class ImportChildCollection : List<ImportChild>
{
public ImportChildCollection() { }
public ImportChildCollection(IEnumerable<ImportChild> src)
{
if (null != src)
{
foreach (ImportChild item in src)
{
item.Ordinal = this.Count + 1;
base.Add(item);
}
}
//AddRange(src);
}
}
[DebuggerDisplay("MyStringKey = {MyStringKey}, MyStringValue='{MyStringValue}', Ordinal='{Ordinal}'")]
public class ImportChild
{
public ImportChild()
{
}
public int Ordinal { get; set; }
public string MyStringKey { get; set; }
public string MyStringValue { get; set; }
}
string xmlString = #"<?xml version=""1.0"" encoding=""utf-8"" ?>
<xml>
<result>OK</result>
<headers>
<header>lastname</header>
<header>firstname</header>
<header>Age</header>
</headers>
<data>
<datum>
<item>Kelly</item>
<item>Grace</item>
<item>33</item>
</datum>
</data>
</xml> ";
XDocument xDoc = XDocument.Parse(xmlString);
//XNamespace ns = XNamespace.Get("http://schemas.microsoft.com/developer/msbuild/2003");
string ns = string.Empty;
List<ImportParent> parentKeys = new List<ImportParent>
(
from list in xDoc.Descendants(ns + "xml")
from item1 in list.Elements(ns + "headers")
where item1 != null
select new ImportParent
{
//note that the cast is simpler to write than the null check in your code
//http://msdn.microsoft.com/en-us/library/bb387049.aspx
ImportChildren = new ImportChildCollection
(
from detail in item1.Descendants("header")
select new ImportChild
{
MyStringKey = detail == null ? string.Empty : detail.Value
}
)
}
);
List<ImportParent> parentValues = new List<ImportParent>
(
from list in xDoc.Descendants(ns + "xml")
from item1 in list.Elements(ns + "data")
from item2 in item1.Elements(ns + "datum")
where item1 != null && item2 != null
select new ImportParent
{
//note that the cast is simpler to write than the null check in your code
//http://msdn.microsoft.com/en-us/library/bb387049.aspx
ImportChildren = new ImportChildCollection
(
from detail in item1.Descendants("item")
select new ImportChild
{
MyStringValue = detail == null ? string.Empty : detail.Value
}
)
}
);
/*Match up the Keys to the Values using "Ordinal" matches*/
foreach (ImportParent parent in parentKeys)
{
foreach (ImportChild child in parent.ImportChildren)
{
ImportChild foundMatch = parentValues.SelectMany(x => x.ImportChildren).Where(c => c.Ordinal == child.Ordinal).FirstOrDefault();
if (null != foundMatch)
{
child.MyStringValue = foundMatch.MyStringValue;
}
}
}
foreach (ImportParent parent in parentKeys)
{
foreach (ImportChild child in parent.ImportChildren)
{
Console.WriteLine("Key={0}, Value={1}", child.MyStringKey, child.MyStringValue);
}
}
I am having trouble deserializing a list of objects. I can get just one object to serialize into an object but cannot get the list. I get no error it just returns an empty List. This is the XML that gets returned:
<locations>
<location locationtype="building" locationtypeid="1">
<id>1</id>
<name>Building Name</name>
<description>Description of Building</description>
</location>
</locations>
This is the class I have and I am deserializing in the GetAll method:
[Serializable()]
[XmlRoot("location")]
public class Building
{
private string method;
[XmlElement("id")]
public int LocationID { get; set; }
[XmlElement("name")]
public string Name { get; set; }
[XmlElement("description")]
public string Description { get; set; }
[XmlElement("mubuildingid")]
public string MUBuildingID { get; set; }
public List<Building> GetAll()
{
var listBuildings = new List<Building>();
var building = new Building();
var request = WebRequest.Create(method) as HttpWebRequest;
var response = request.GetResponse() as HttpWebResponse;
var streamReader = new StreamReader(response.GetResponseStream());
TextReader reader = streamReader;
var serializer = new XmlSerializer(typeof(List<Building>),
new XmlRootAttribute() { ElementName = "locations" });
listBuildings = (List<Building>)serializer.Deserialize(reader);
return listBuildings;
}
}
Try this:
[XmlRoot("locations")]
public class BuildingList
{
public BuildingList() {Items = new List<Building>();}
[XmlElement("location")]
public List<Building> Items {get;set;}
}
Then deserialize the whole BuildingList object.
var xmlSerializer = new XmlSerializer(typeof(BuildingList));
var list = (BuildingList)xmlSerializer.Deserialize(xml);
I know this is an old(er) question, but I struggled with this today, and found an answer that doesn't require encapsulation.
Assumption 1: You have control over the source Xml and how it is constructed.
Assumption 2: You are trying to serialise the Xml directly into a List<T> object
You must name the Root element in the Xml as ArrayOfxxx where xxx is the name of your class (or the name specified in XmlType (see 2.))
If you wish your xml Elements to have a different name to the class, you should use XmlType on the class.
NB: If your Type name (or class name) starts with a lowercase letter, you should convert the first character to uppercase.
Example 1 - Without XmlType
class Program
{
static void Main(string[] args)
{
//String containing the xml array of items.
string xml =
#"<ArrayOfItem>
<Item>
<Name>John Doe</Name>
</Item>
<Item>
<Name>Martha Stewart</Name>
</Item>
</ArrayOfItem>";
List<Item> items = null;
using (var mem = new MemoryStream(Encoding.Default.GetBytes(xml)))
using (var stream = new StreamReader(mem))
{
var ser = new XmlSerializer(typeof(List<Item>)); //Deserialising to List<Item>
items = (List<Item>)ser.Deserialize(stream);
}
if (items != null)
{
items.ForEach(I => Console.WriteLine(I.Name));
}
else
Console.WriteLine("No Items Deserialised");
}
}
public class Item
{
public string Name { get; set; }
}
Example 2 - With XmlType
class Program
{
static void Main(string[] args)
{
//String containing the xml array of items.
//Note the Array Name, and the Title case on stq.
string xml =
#"<ArrayOfStq>
<stq>
<Name>John Doe</Name>
</stq>
<stq>
<Name>Martha Stewart</Name>
</stq>
</ArrayOfStq>";
List<Item> items = null;
using (var mem = new MemoryStream(Encoding.Default.GetBytes(xml)))
using (var stream = new StreamReader(mem))
{
var ser = new XmlSerializer(typeof(List<Item>)); //Deserialising to List<Item>
items = (List<Item>)ser.Deserialize(stream);
}
if (items != null)
{
items.ForEach(I => Console.WriteLine(I.Name));
}
else
Console.WriteLine("No Items Deserialised");
}
}
[XmlType("stq")]
public class Item
{
public string Name { get; set; }
}
Not sure how Building corresponds with the location you have in your xml, but to me it makes more sense if they're named equivalently. Instead of using a List use a LocationList, and it becomes:
[Serializable()]
[XmlRoot("locations")]
public class LocationCollection{
[XmlElement("location")]
public Location[] Locations {get;set;}
}
[Serializable()]
[XmlRoot("location")]
public class Location
{
[XmlElement("id")]
public int LocationID { get; set; }
[XmlAttribute("locationtype")]
public string LocationType {get;set;}
[XmlElement("name")]
public string Name { get; set; }
[XmlElement("description")]
public string Description { get; set; }
[XmlElement("mubuildingid")]
public string MUBuildingID { get; set; }
}
You can then deserialize as follows:
var request = WebRequest.Create(method) as HttpWebRequest;
var response = request.GetResponse() as HttpWebResponse;
var streamReader = new StreamReader(response.GetResponseStream());
TextReader reader = streamReader;
var serializer = new XmlSerializer(typeof(LocationCollection),
new XmlRootAttribute() { ElementName = "locations" });
var listBuildings = (LocationCollection)serializer.Deserialize(reader);
return listBuildings;
I know, old question, but came across it when faced by a similar issue.
Building on #ricovox's answer and in context of the OP's question, this is the model I would use to serialize his xml:
[Serializable, XmlRoot("locations")]
public class BuildingList
{
[XmlArrayItem("location", typeof(Building))]
public List<Building> locations { get; set; }
}
[Serializable]
public class Building
{
public int LocationID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string MUBuildingID { get; set; }
public List<Building> GetAll()
{
...
}
}
The OP's mistake was to create the list item as the root
Use [XMLArray] for collection properties.
What is the best way to parse XML children nodes into a specific list? This is a small example of the XML.
<Area Name="Grey Bathroom" IntegrationID="3" OccupancyGroupAssignedToID="141">
<Outputs>
<Output Name="Light/Exhaust Fan" IntegrationID="46" OutputType="NON_DIM" Wattage="0" />
</Outputs>
</Area>
I want to create a list or something that will be called the Area Name and hold the information of the Output Name and IntegrationID. So I can call the list and pull out the Output Name and IntegrationID.
I can create a list of all Area Names and then a list of Outputs but cannot figure out how to create a list that will be called "Grey Bathroom" and hold the output "Light/Exhaust Fan" with an ID of 46.
XDocument doc = XDocument.Load(#"E:\a\b.xml");
List<Area> result = new List<Area>();
foreach (var item in doc.Elements("Area"))
{
var tmp = new Area();
tmp.Name = item.Attribute("Name").Value;
tmp.IntegrationID = int.Parse(item.Attribute("IntegrationID").Value);
tmp.OccupancyGroupAssignedToID = int.Parse(item.Attribute("OccupancyGroupAssignedToID").Value);
foreach (var bitem in item.Elements("Outputs"))
{
foreach (var citem in bitem.Elements("Output"))
{
tmp.Outputs.Add(new Output
{
IntegrationID = int.Parse(citem.Attribute("IntegrationID").Value),
Name = citem.Attribute("Name").Value,
OutputType = citem.Attribute("OutputType").Value,
Wattage = int.Parse(citem.Attribute("Wattage").Value)
});
}
}
result.Add(tmp);
}
public class Area
{
public String Name { get; set; }
public int IntegrationID { get; set; }
public int OccupancyGroupAssignedToID { get; set; }
public List<Output> Outputs = new List<Output>();
}
public class Output
{
public String Name { get; set; }
public int IntegrationID { get; set; }
public String OutputType { get; set; }
public int Wattage { get; set; }
}
The example uses an anonymous type. You could (and I warmly advice you to) use your own.
var doc = XDocument.Parse(xml);
var areaLists = doc.Elements("Area").
Select(e => e.Descendants("Output").
Select(d => new
{
Name = (string) d.Attribute("Name"),
Id = (int) d.Attribute("IntegrationID")
}).
ToArray()).
ToList();