WillC
WillC

Reputation: 2125

Deserializing Generic List<T> From XML Without XmlAttributes

I am trying to deserialize an xml list to a generic List in C#. I do not want to use XmlAttributes as the solution needs to be generic. I must be getting close as I am getting 3 Item objects but they are all populated with default values, ie: null or 0.

This is not a duplicate of how to deserialize an xml node with a value and an attribute using asp.net serialization which uses XmlAttributes and is not an option. This is clearly stated in the question.

There are a number of SO answers out there whicha I have tried and are similar to what I need, including the other list of SO responses in the [Duplicate]. The code below is modified from one of those answers but does not quite work.

<?xml version="1.0" encoding="utf-8"?>
<root>
---snip---
    <Items>
    <Item ItemId="1" ItemName="TestName1" Number="100" Created=""></Item>
    <Item ItemId="2" ItemName="TestName2" Number="200" Created=""></Item>
    <Item ItemId="3" ItemName="TestName3" Number="300" Created=""></Item>
    </Items>
</root>

========================================================

var sourceData = XDocument.Parse(xml); 

public List<T> GetObjectList<T>(string identifier) where T : class, new()
{
    if (sourceData != null && !identifier.isNullOrEmpty())
    {
        var list = sourceData.Descendants(identifier)
            .Select(p => DeserializeObject<T>(p.ToString()))
            .ToList();

        return list;
    }
    return new List<T>();
}

public static T DeserializeObject<T>(string xml)  where T : class, new()
{
    if (string.IsNullOrEmpty(xml))
    {
        return default(T);
    }
    try
    {
        using (var stringReader = new StringReader(xml))
        {
            var serializer = new XmlSerializer(typeof(T));
            return (T) serializer.Deserialize(stringReader);
        }
    }
    catch 
    {
        return default(T);
    }
}

public class Item
{
    public int ItemId { get; set; }
    public string ItemName { get; set; }
    public int? Number { get; set;}
    public DateTime? Created { get; set; }
}

// RESULT
// Item ItemId="0" ItemName="null" Number="null" Created="null" 
// Item ItemId="0" ItemName="null" Number="null" Created="null"
// Item ItemId="0" ItemName="null" Number="null" Created="null"

Upvotes: 0

Views: 728

Answers (2)

phi1010
phi1010

Reputation: 677

Check out the XmlSerialzer constructor, you can specify attribute overrides there, if you do not want to modify the class -- you'll need some data defining what you serialize at some point; the XmlSerializer was never written to work without these Attributes, or types that are known to be serializable (numbers, strings, ...).

If you want to be generic, you'll have to write your own serializer, which uses reflection to decide what to serialize, how, and in which order, and what to ignore. You can use the XmlSerializer in it when serializing types that have the necessary attributes. Search for tutorials explaining how to implement IXmlSerializable, they will show you how to use XmlWriter / XmlReader to avoid handling the XML syntax yourself.

A guess why it is like this: Circular references make (de-)serialization really hard, and a generic solution would probably try to serialize this without coming to an end, causing weird bugs with the call hanging forever, when some developer changes one of those classes without being able to see (due to no attribute being there) that they have to write the class in a way avoiding serialization problems.

Upvotes: 1

WillC
WillC

Reputation: 2125

I asked another similar question (A Better XElement to Object Without XMLAttributes in C#) when this one got marked as a duplicate (for a while) and ended up creating a simple custom de-serializer that met my needs. See the answers there for the code if interested.

Upvotes: 0

Related Questions