user746461
user746461

Reputation:

Serialize a polymorphic List BUT unable to change type definitions

I'm using another party's DLL, which defines animals, cat, fish classes.

//Begin another party's DLL
public class animals
{
}

public class cat : animals
{
    public string size { get; set; }
    public string furColor { get; set; }
}

public class fish : animals
{
    public string size { get; set; }
    public string scaleColor { get; set; }
}
//End another party's DLL

static void Main(string[] args)
{

    using (var xmlWriter = XmlWriter.Create("a.xml", new XmlWriterSettings { Indent = true }))
    {
        var eventArgsList = new List<animals>();
        eventArgsList.Add(new cat { size = "10", furColor = "red" });
        eventArgsList.Add(new fish { size = "20", scaleColor = "blue" });

        new XmlSerializer(eventArgsList.GetType(),new[] { typeof(cat), typeof(fish) }).Serialize(xmlWriter, eventArgsList);
    }
}

The above code correctly outputs

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfAnimals xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <animals xsi:type="cat">
    <size>10</size>
    <furColor>red</furColor>
  </animals>
  <animals xsi:type="fish">
    <size>20</size>
    <scaleColor>blue</scaleColor>
  </animals>
</ArrayOfAnimals>

However, I want it to look like

<?xml version="1.0" encoding="utf-8"?>
<Animals xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <cat>
    <size>10</size>
    <furColor>red</furColor>
  </cat>
  <fish>
    <size>20</size>
    <scaleColor>blue</scaleColor>
  </fish>
</Animals>

Adimttedly it's similar to Serialize a polymorphic List with the same type name, but I cannot change the type definition. I guess I have to use XmlAttributeOverrides, can anyone tell me how to do?

Upvotes: 0

Views: 45

Answers (2)

user746461
user746461

Reputation:

Inspired by CodingYoshi's innovative way, I find the following helper class works shorter by 100 lines.

[XmlRoot("Animals")]
public class AnimalsHelper
{
    [XmlElement("Cat", typeof(cat))]
    [XmlElement("Fish", typeof(fish))]
    public List<animals> Animals { get; set; } = new List<animals>();
}

static void Main(string[] args)
{

    using (var xmlWriter = XmlWriter.Create("a.xml", new XmlWriterSettings { Indent = true }))
    {
        var animalsHelper= new AnimalsHelper();
        animalsHelper.Animals.Add(new cat { size = "10", furColor = "red" });
        animalsHelper.Animals.Add(new fish { size = "20", scaleColor = "blue" });

        new XmlSerializer(animalsHelper.GetType(),new[] { typeof(cat), typeof(fish) }).Serialize(xmlWriter, animalsHelper);
    }

    using (var xmlReader = XmlReader.Create("a.xml", new XmlReaderSettings { IgnoreWhitespace = true }))
    {
        var obj = (AnimalsHelper)new XmlSerializer(animalsHelper.GetType(), new[] { typeof(cat), typeof(fish) }).Deserialize(xmlReader);

    }
}

I'm stilling longing for a solution without using helper classes.

Upvotes: 0

CodingYoshi
CodingYoshi

Reputation: 27039

In order to have that structure in XML without writing a custom serializer, you need to have the same structure in your C# classes. But this is easy because Visual Studio will do this for you.

Copy your desired XML and create classes for that XML structure. It will create the following classes. You need to make one tweak and set AnonymousType = false as I have done below.

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = false)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class Animals
{

    private AnimalsCat[] catField;

    private AnimalsFish[] fishField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("cat")]
    public AnimalsCat[] cat
    {
        get
        {
            return this.catField;
        }
        set
        {
            this.catField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("fish")]
    public AnimalsFish[] fish
    {
        get
        {
            return this.fishField;
        }
        set
        {
            this.fishField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = false)]
public partial class AnimalsCat
{

    private byte sizeField;

    private string furColorField;

    /// <remarks/>
    public byte size
    {
        get
        {
            return this.sizeField;
        }
        set
        {
            this.sizeField = value;
        }
    }

    /// <remarks/>
    public string furColor
    {
        get
        {
            return this.furColorField;
        }
        set
        {
            this.furColorField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = false)]
public partial class AnimalsFish
{

    private byte sizeField;

    private string scaleColorField;

    /// <remarks/>
    public byte size
    {
        get
        {
            return this.sizeField;
        }
        set
        {
            this.sizeField = value;
        }
    }

    /// <remarks/>
    public string scaleColor
    {
        get
        {
            return this.scaleColorField;
        }
        set
        {
            this.scaleColorField = value;
        }
    }
}

Usage

using (var xmlWriter = XmlWriter.Create("a.xml", new XmlWriterSettings { Indent = true }))
{
    var eventArgsList = new Animals();
    eventArgsList.cat = new AnimalsCat[1]; // set this based on the number 
    eventArgsList.fish = new AnimalsFish[2]; // set this based on the number 

    // Do this using a loop but I just hard coded it
    eventArgsList.cat[0] = new AnimalsCat { size = 10, furColor = "red" };
    eventArgsList.fish[0] = new AnimalsFish { size = 20, scaleColor = "blue" };
    eventArgsList.fish[1] = new AnimalsFish { size = 30, scaleColor = "orange" };

    new XmlSerializer(eventArgsList.GetType(), new[] { typeof(AnimalsCat), typeof(AnimalsFish) }).Serialize(xmlWriter, eventArgsList);
}

Output

<?xml version="1.0" encoding="utf-8"?>
<Animals xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <cat>
    <size>10</size>
    <furColor>red</furColor>
  </cat>
  <fish>
    <size>20</size>
    <scaleColor>blue</scaleColor>
  </fish>
  <fish>
    <size>30</size>
    <scaleColor>orange</scaleColor>
  </fish>
</Animals>

Upvotes: 0

Related Questions