2

I need to parse XML responses into different class objects. I have classes with many different properties. I know I can create the objects directly using LINQ like the below code:

XElement response = XElement.Parse(xmlValue);
IEnumerable<DTO> result =
    from el in response.Descendants("i")
    select new DTO()
    {
        Object_ID = (int)el.Attribute("Object_ID")
        // Other properties mapped here.
    };

My XML is is the following format and only has attribute values, no element values:

<root>
    <i attribute1="value" attribute2="value"... attributex="value"/>
    <i attribute1="value" attribute2="value"... attributex="value"/>
    <i attribute1="value" attribute2="value"... attributex="value"/>
    <i attribute1="value" attribute2="value"... attributex="value"/>
</root>

The issue is that I have multiple DTO's and I don't want to write different handlers for each case since there are so many different attributes and mapping each attribute would result in redundant ugly code.

I need the data to be stored in an IEnumerable type.

Is this the most efficient way to proceed? Should I create a generic type conversion method that returns objects?

EDIT: I eventually used XmlSerializer to solve this problem, with a few minor adjustments to the accepted answer below. Code follows:

    public static IEnumerable<T> DeserializeXml<T>(XElement response)
    {
        var list = new List<T>();
        foreach (var item in response.Descendants("i"))
        {
            using (var sr = new StringReader(student.ToString()))
            {
                var xRoot = new XmlRootAttribute();
                xRoot.ElementName = "i";
                xRoot.IsNullable = true;
                var serializer = new XmlSerializer(typeof(T), xRoot);
                list.Add((T)serializer.Deserialize(sr));
            }
        }
        return list;
    }
  • 3
    Use the [`XmlSerializer`](https://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer(v=vs.110).aspx) – rene Dec 18 '17 at 23:09
  • 1
    Specifically see [Using XmlSerializer to create an element with attributes and a value but no sub-element](https://stackoverflow.com/q/3524224/3744182) and [Serialize Property as Xml Attribute in Element](https://stackoverflow.com/q/11330643/3744182). – dbc Dec 18 '17 at 23:46

2 Answers2

1

I can do a Dictionary of attributes for each i tag in your Xml, and then return a collection of dictionaries.

IEnumerable<Dictionary<string, string>> result =
    from tag in response.Descendants("i")
    select tag.Attributes().Select(a =>
        new { key = a.Name.LocalName, value = a.Value.ToString() })
        .ToDictionary(k => k.key, v => v.value);
derloopkat
  • 6,232
  • 16
  • 38
  • 45
1

If you want something more strongly typed (than a dictionary of Strings), in terms of declared attribute names and types, you can create a DTO annotated with XmlSerizalizer attributes and use a generic array deserializer.

[XmlType("i")]
public class DtoI
{
    [XmlAttribute("Object_ID")]
    public int Id;
    [XmlAttribute("attribute1")]
    public String Attribute1;
    [XmlAttribute("attribute2")]
    public String Attribute2;
    [XmlAttribute("attributex")]
    public Int32 AttributeX;
}


public static T[] DeserializeArray<T>(String xml)
{
    using (var reader = new StringReader(xml))
    {
        var serializer = new XmlSerializer(typeof(T[]), new XmlRootAttribute("root"));
        return (T[])serializer.Deserialize(reader);
    }
}
Tom Blodget
  • 20,260
  • 3
  • 39
  • 72