Search code examples
serializationxml-serializationdatacontractxmlserializer

XML Serialization - Is it possible to serialize a model in this way?


I have the following model:

public class ABaseObject
{
    private Guid id = Guid.NewGuid();

    public ABaseObject()
    {
    }

    public Guid ID { get { return id; } }
}

public class ADerivedObject : ABaseObject
{
    public ADerivedObject()
    {
    }

    public string Name { get; set; }
}

public class AObjectCollection<T>
{
    private List<T> items = new List<T>();

    public AObjectCollection()
    {
    }

    public IEnumerable<T> Items { get { return items; } }
    public void Add(T item)
    {
        items.Add(item);
    }

    public void Save(string filePath)
    {
        FileStream writer = new FileStream(filePath, FileMode.Create);
        DataContractSerializer s = new DataContractSerializer(typeof(T));
        s.WriteObject(writer, this);
        writer.Close();
    }

    public void Load(string filePath)
    {
        FileStream fs = new FileStream(filePath, FileMode.Open);
        XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
        DataContractSerializer ser = new DataContractSerializer(typeof(T));

        // Deserialize the data and read it from the instance.
        T deserializedObj = (T)ser.ReadObject(reader, true);
        reader.Close();
        fs.Close();
    }
}

So basically I want to be able to do the following:

var der = new ADerivedObject();
der.Name = "Test";
var col = new AObjectCollection<ADerivedObject>();
col.Add(der);
col.Save("C:\MyCollection.xml");
...
var col2 = new AObjectCollection<ADerivedObject>();
col2.Load("C:\MyCollection.xml");

When serialized it should look something like:

<Collection>
    <Item>
        <ID></ID>
        <Name></Name>
    </Item>
</Collection>

I have played around with DataContracts and XmlSerializer but I can't quite seem to find a way to do it.


Solution

  • This code:

    public class ABaseObject
    {
        public ABaseObject() { }
        public Guid ID { get; set;}
    }
    
    [XmlType("Item")]
    public class ADerivedObject : ABaseObject
    {
        public ADerivedObject() {}
        public string Name { get; set; }
    }
    
    [XmlType("Collection")]
    public class AObjectCollection<T>
    {
        private System.Xml.Serialization.XmlSerializerNamespaces ns;
        private System.Xml.Serialization.XmlSerializer s;
    
        public AObjectCollection()
        {
            ns= new System.Xml.Serialization.XmlSerializerNamespaces();
            ns.Add( "", "");
            s= new System.Xml.Serialization.XmlSerializer(this.GetType());
            Items = new List<T>();
        }
    
        public List<T> Items { get; set; }
        public DateTime LastSaved { get;set; }
    
        public void Add(T item)
        {
            Items.Add(item);
        }
    
        public void Save(string filePath)
        {
            LastSaved= System.DateTime.Now;
            var xmlws = new System.Xml.XmlWriterSettings { OmitXmlDeclaration = true, Indent= true };
    
            using ( var writer = System.Xml.XmlWriter.Create(filePath, xmlws))
            {
                s.Serialize(writer, this, ns);
            }
        }
    
        public static AObjectCollection<T2> Load<T2>(string filepath)
        {
            AObjectCollection<T2> obj;
            try
            {
                var s= new System.Xml.Serialization.XmlSerializer(typeof(AObjectCollection<T2>));
                using(System.IO.StreamReader reader= System.IO.File.OpenText(filepath))
                {
                    obj= (AObjectCollection<T2>) s.Deserialize(reader);
                }
            }
            catch
            {
                obj= new AObjectCollection<T2>();
            }
    
            return obj;
        }
    }
    

    produces this output:

    <Collection>
      <Items>
        <Item>
          <ID>00000000-0000-0000-0000-000000000000</ID>
          <Name>Test</Name>
        </Item>
      </Items>
      <LastSaved>2010-02-04T07:32:05.812-05:00</LastSaved>
    </Collection>
    

    There are ways to tweak the XML to remove the Collection/Items layer. Search SO for other Collection / Serialization questions.