Ash
Ash

Reputation: 582

Deserializing XML to objects which has list of objects in C#

I have following xml which I want to Deserialize to an object.

<result>
    <reporttype>2</reporttype>
    <items>
        <item>
            <sku>0B0005</sku>
            <style>0B0005.DAK.GREY</style>
            <reason>Barcode cannot be moved to different SKUs</reason>
        </item>
        <item>
            <sku>0B0006</sku>
            <style>0B0006.DAK.GREY</style>
            <reason>Barcode cannot be moved to different SKUs</reason>
        </item>
    </items>
</result>

But following code does not populate the item list, Can someone point me out what I am doing wrong here

string inputString = @"<result><reporttype>2</reporttype><items><item><sku>0B0005</sku><style>0B0005.DAK.GREY</style><reason>Barcode cannot be moved to different SKUs</reason></item><item><sku>0B0005</sku><style>0B0005.DAK.GREY</style><reason>Barcode cannot be moved to different SKUs</reason></item></items></result>";

XmlDocument doc = new XmlDocument();
doc.LoadXml(inputString);

XmlSerializer serializer = new XmlSerializer(typeof(Result));
StringReader rdr = new StringReader(doc.InnerXml);
Result resultingMessage = (Result)serializer.Deserialize(rdr);

public enum ReportType {
    [XmlEnum("0")]
    InternalErrorReport,
    [XmlEnum("1")]
    ErrorReport,
    [XmlEnum("2")]
    InternalSuccessReport
}

[XmlRoot(ElementName = "result")]
public class Result {
    [XmlElement(ElementName = "reporttype")]
    public ReportType reportType { get; set; }
    [XmlElement(ElementName = "items")]
    public List<Item> items = new List<Item>();

    public string error { get; set; }

    public class Item {
        [XmlElement(ElementName = "sku")]
        string sku { get; set; }
        [XmlElement(ElementName = "style")]
        string style { get; set; }
        [XmlElement(ElementName = "reason")]
        string reason { get; set; }
    }
}

Or is there a better way to do this?

Upvotes: 0

Views: 13620

Answers (4)

Fabio
Fabio

Reputation: 32445

You can add two attributes for items property - to satisfy serialization

[XmlRoot(ElementName = "result")]
public class Result 
{
    [XmlArray("items")]
    [XmlArrayItem("item")]
    public List<Item> items = new List<Item>();
}

Or just set type attribute(XmlType) for Item class.
Then will be enough to use only XmlArray attribute for Result.items property. Or not using any attribute at all because name of the property match with name of the element in xml.

[XmlType("item")]
public class Item 
{
    [XmlElement(ElementName = "sku")]
    public string sku { get; set; }
    [XmlElement(ElementName = "style")]
    public string style { get; set; }
    [XmlElement(ElementName = "reason")]
    public string reason { get; set; }
}

And of course make properties public

Upvotes: 4

gio
gio

Reputation: 91

As explained here you need to mark the list as XmlArray specifing also the XmlArrayItem: Deserializing nested lists with XmlSerializer

So the code becomes:

        string inputString = @"<result><error>error test</error><reporttype>2</reporttype><items><item><sku>0B0005</sku><style>0B0005.DAK.GREY</style><reason>Barcode cannot be moved to different SKUs</reason></item><item><sku>0B0005</sku><style>0B0005.DAK.GREY</style><reason>Barcode cannot be moved to different SKUs</reason></item></items></result>";

        XmlDocument doc = new XmlDocument();
        doc.LoadXml(inputString);

        XmlSerializer serializer = new XmlSerializer(typeof(Result));
        object resultingMessage = null;
        using (StringReader rdr = new StringReader(doc.InnerXml)) {
            resultingMessage = (Result)serializer.Deserialize(rdr);
        }

and the classes:

public enum ReportType {
    [XmlEnum("0")]
    InternalErrorReport,
    [XmlEnum("1")]
    ErrorReport,
    [XmlEnum("2")]
    InternalSuccessReport
}

[XmlRoot(ElementName = "result")]
public class Result {
    [XmlElement(ElementName = "reporttype")]
    public ReportType reporttype { get; set; }
    [XmlArray("items")]
    [XmlArrayItem("item")]
    public List<Item> items { get; set; }
    [XmlElement(ElementName = "error")]
    public string error { get; set; }

    [XmlRoot(ElementName = "items\\item")]
    public class Item {
        [XmlElement(ElementName = "sku")]
        public string sku { get; set; }
        [XmlElement(ElementName = "style")]
        public string style { get; set; }
        [XmlElement(ElementName = "reason")]
        public string reason { get; set; }
    }

}

Please, note also that I encapsulated the string reader in a using block, in order to dispose the object once the read ends.

Upvotes: 1

jdweng
jdweng

Reputation: 34421

Variable need to be public.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            string xml = File.ReadAllText(FILENAME);

            XmlSerializer serializer = new XmlSerializer(typeof(Result));
            StringReader rdr = new StringReader(xml);
            Result resultingMessage = (Result)serializer.Deserialize(rdr);


        }
    }
    public enum ReportType
    {
        [XmlEnum("0")]
        InternalErrorReport,
        [XmlEnum("1")]
        ErrorReport,
        [XmlEnum("2")]
        InternalSuccessReport
    }

    [XmlRoot(ElementName = "result")]
    public class Result
    {
        [XmlElement(ElementName = "reporttype")]
        public ReportType reportType { get; set; }
        public Items items { get; set; }
        public string error { get; set; }


    }
    [XmlRoot("items")]
    public class Items
    {
        [XmlElement(ElementName = "item")]
        public List<Item> items = new List<Item>();
    }
    [XmlRoot("item")]
    public class Item
    {
        [XmlElement(ElementName = "sku")]
        public string sku { get; set; }
        [XmlElement(ElementName = "style")]
        public string style { get; set; }
        [XmlElement(ElementName = "reason")]
        public string reason { get; set; }
    }
}

Upvotes: 2

Abinash
Abinash

Reputation: 481

items should be Xmlroot element and it contain XmlElement item,you have to tell when it Deserialize to object. try this :

public class Item
{
    [XmlElement(ElementName = "sku")]
    public string Sku { get; set; }
    [XmlElement(ElementName = "style")]
    public string Style { get; set; }
    [XmlElement(ElementName = "reason")]
    public string Reason { get; set; }
}

[XmlRoot(ElementName = "items")]
public class Items
{
    [XmlElement(ElementName = "item")]
    public List<Item> Item { get; set; }
}

[XmlRoot(ElementName = "result")]
public class Result
{
    [XmlElement(ElementName = "reporttype")]
    public string Reporttype { get; set; }
    [XmlElement(ElementName = "items")]
    public Items Items { get; set; }
}

Upvotes: 0

Related Questions