I have an object that I am trying to convert to XML. Inside this object there is a list of a general type (abstract class). Each element in this list may be a different class, but everyone inherits from an abstract base class:
public abstract class animal { public string type { get; set; } } public class cat:animal { public string size { get; set; } public string furColor { get; set; } } public class fish:animal { public string size { get; set; } public string scaleColor { get; set; } }
When I serialize the list, I want it to look like this:
<animal type="cat"> <size>medium</size> <furColor>black</furColor> </animal> <animal type="fish"> <size>small</size> <scaleColor>silver</scaleColor> </animal>
I tried a simple solution:
[XmlElement("Animal")] public List<animal> Animals { get; set; }
But it throws an error because it does not expect the object type to be "cat". Adding the [XmlInclude] tag to a base class, a derived class, or an entire contained class (let it be called) does not help.
I can use typeof notation for one class:
[XmlElement("Animal", typeof(cat))] public List<animal> Animals { get; set; }
and it works correctly as I want, as long as I only use cats. Again, the moment I add the fish to the mix, it explodes with the same error (not expecting the fish).
I can add some typeof attributes:
[XmlElement("Animal")] [XmlElementAttribute(typeof(cat))] [XmlElementAttribute(typeof(fish))] public List<animal> Animals { get; set; }
and this compiles, but ignores the element name and serializes the objects as <cat> </cat> and <fish> </fish> , respectively, which is unacceptable.
I even tried to add some [XmlElement] tags:
[XmlElement("Animal", typeof(cat))] [XmlElement("Animal", typeof(fish))] public List<animal> Animals { get; set; }
In this case, another exception occurs, this time the objects "cat" and "fish" use the type "Animal" in the same area.
Can anyone think of this?
UPDATE After a bit more digging, I found This SO post , which suggests adding a namespace to the base class:
[XmlRoot(Namespace="myNamespace")] [XmlInclude(typeof(cat))] [XmlInclude(typeof(fish))] public abstract class animal
Serializing this gives the following:
<animal xsi:type="cat" type="cat"> ... </animal> <animal xsi:type="fish" type="fish"> ... </animal>
Where xsi: type = "cat" refers to the class name, and type = "cat" refers to the type attribute created in the base class (see the truest example). This is so close to what I need, and I'm afraid that I'm just suffering from inexperience here, but is there any way to get rid of the xsi: type attribute list?