Unable do deserialize XDocument

Viewed 286

I am trying to deserialize XDocument to a class that contains an array/list. The problem is this code fails to do so, I always get a Response class without any Inventory items (not null, but count = 0)

Here is my test method:

public void GetObj()
{
    var xe = new XElement("Inventory");
    var xe2 = new XElement("Id", "23");
    xe.Add(xe2);

    var list = new List<XElement>();
    list.Add(xe);
    list.Add(xe);

    var doc = new XDocument(new XElement("Response", list));

    var obj = doc.Deserialize<Response>();
}

And here are my extension methods and models:

public static class XDocumentExtensions
{
    public static T Deserialize<T>(this XDocument doc)
    {
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));

        using (var reader = doc.Root.CreateReader())
        {
            return (T)xmlSerializer.Deserialize(reader);
        }
    }

    public static XDocument Serialize<T>(this T value)
    {
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));

        XDocument doc = new XDocument();
        using (var writer = doc.CreateWriter())
        {
            xmlSerializer.Serialize(writer, value);
        }

        return doc;
    }
}

public class Response
{
    public List<Inventory> Inventory { get; set; }
}

public class Inventory
{
    public int Id { get; set; }
}
1 Answers

The easiest way to diagnose a problem with XML deserialization is to construct an instance of your model in memory and serialize it, then compare the output XML with the desired input. Thus, if I do:

Console.WriteLine(new Response { Inventory = new List<Inventory> { new Inventory { Id = 23 } } }.Serialize() );

The output XML is:

<Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Inventory>
    <Inventory>
      <Id>23</Id>
    </Inventory>
  </Inventory>
</Response>

As you can see, there's an extra level of nesting of <Inventory> elements. It is there because, by default, XmlSerializer serializes collections with an outer container element element named after the serialized member (here Inventory) as well as an element for each item, named (by default) after the item type (here also Inventory). Demo fiddle #1 here.

If you don't want this, you need to add [XmlElement] to public List<Inventory> like so:

public class Response
{
    [XmlElement]
    public List<Inventory> Inventory { get; set; }
}

Now Inventory will be serialized without the outer container element, and so your deserialization code will succeed. Demo fiddle #2 here.

(Alternatively, you could construct your XDocument with the requisite extra level of nesting.)

Related