Search code examples
c#xmldatacontractserializer

Preserve element name in collection when using DataContractSerializer


I wonder if it's possible to define the element names when serializing my custom collection of a certain base type. Consider the following example (I'm using the fruit example here :)):

[DataContract(Name = "Bowl")]
public class Bowl
{
    [DataMember]
    public List<Fruit> Fruits { get; set; }
}
[DataContract(Name = "Fruit")]
public abstract class Fruit
{
}
[DataContract(Name = "Apple", Namespace = "")]
public class Apple : Fruit
{
}
[DataContract(Name = "Banana", Namespace = "")]
public class Banana : Fruit
{
}

When serializing:

var bowl = new Bowl() { Fruits = new List<Fruit> { new Apple(), new Banana() } };
var serializer = new DataContractSerializer(typeof(Bowl), new[] { typeof(Apple), typeof(Banana) });
using (var ms = new MemoryStream())
{
    serializer.WriteObject(ms, bowl);
    ms.Position = 0;
    Console.WriteLine(System.Text.Encoding.UTF8.GetString(ms.ToArray()));
}

Would give me an output of:

<Bowl xmlns="http://schemas.datacontract.org/2004/07/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Fruits>
    <Fruit i:type="Apple" xmlns="" />
    <Fruit i:type="Banana" xmlns="" />
  </Fruits>
</Bowl>

What I really would like is an output where the Fruit elements is replaces with their proper class names. I.e.:

<Bowl xmlns="http://schemas.datacontract.org/2004/07/">
  <Fruits>
    <Apple />
    <Banana />
  </Fruits>
</Bowl>

Is it possible to do with DataContractSerializer or do I have to write my own logic for it with XmlWriter?


Solution

  • If you want lots of control over the xml output, you should be annotating it for XmlSerializer, not DataContractSerializer. For example:

    using System;
    using System.Collections.Generic;
    using System.Xml.Serialization;
    
    public class Bowl {
        [XmlArray("Fruits")]
        [XmlArrayItem("Apple", typeof(Apple))]
        [XmlArrayItem("Banana", typeof(Banana))]
        public List<Fruit> Fruits { get; set; }
    }
    public abstract class Fruit { }
    public class Apple : Fruit { }
    public class Banana : Fruit { }
    
    static class Program {
        static void Main() {
            var ser = new XmlSerializer(typeof(Bowl));
            var obj = new Bowl {
                Fruits = new List<Fruit> {
                    new Apple(), new Banana()
                }
            };
            ser.Serialize(Console.Out, obj);
        }
    }