Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XmlSerializer replace xsi:type to node name

Currently XmlSerializer produces the following structure:

<config>
  <BaseType xsi:type="DerivedType1" />
  <BaseType xsi:type="DerivedType2" />
</config>

Is there any way to make it put type name into node:

<config>
  <DerivedType1 />
  <DerivedType2 />
</config>

?

like image 950
SiberianGuy Avatar asked Feb 20 '12 10:02

SiberianGuy


2 Answers

Use the XmlElementAttribute constructor overload (string elementName, Type type). It allows you to replace the element name given the actual type found in the member. Stack several of these together if you have multiple derived types.

If you are trying to serialize a generic collection like List<Base> that might contain instances of Derived then use the XmlArrayItem in the same way.

Defining in this way also implicitly makes the derived type known, So an XmlInclude attribute is not required

Sample definition:

[XmlRoot]
public class Data
{
    [XmlElement("Derived1", typeof(Derived1))]
    [XmlElement("Derived2", typeof(Derived2))]
    public Base foo { get; set; }
    [XmlArrayItem("Derived1", typeof(Derived1))]
    [XmlArrayItem("Derived2", typeof(Derived2))]
    public List<Base> fooList { get; set; }
}

public class Base { ... }
public class Derived1 : Base { ... }
public class Derived2 : Base { ... }
like image 168
Tamir Daniely Avatar answered Nov 15 '22 23:11

Tamir Daniely


Why do people keep saying "you'll never be able to deserialize." That is definitionally FALSE.

public class BaseClass {
  public string Name {get;set;}
}
[XmlRoot("BaseClass")]
public class ChildClass : BaseClass {
  public int Value {get;set;}
}
[XmlRoot("BaseClass")]
public class FlatClass
{
  public string Name {get;set;}
  public int Value {get;set;}
}

XmlSerializer ser1 = new XmlSerializer(typeof(BaseClass));
XmlSerializer ser2 = new XmlSerializer(typeof(ChildClass));
XmlSerializer ser3 = new XmlSerializer(typeof(FlatClass));
ser1.Serialize(File.Open("ser1.xml", FileMode.Create), new BaseClass(){Name="Base"});
ser2.Serialize(File.Open("ser2.xml", FileMode.Create), new ChildClass(){Name="Child",Value = 1});

ser1.Deserialize(File.OpenRead("ser2.xml"));
ser2.Deserialize(File.OpenRead("ser1.xml"));
ser3.Deserialize(File.OpenRead("ser2.xml"));

Boom. Works just FINE!!!!! Serialization goes all three both ways perfectly. the resulting objects may not be 100% on either side, but it DOES deserialize. Ser1 IGNORES the Value element when deserializing ser2.xml Ser2 SKIPS the Value propertuy when deserializing ser1.xml

The only thing that breaks this model is:

ser1.Serailize(File.Open("ser3.xml", FileMode.Create), new ChildClass(){Name = "Child2", Value = 2});
XmlSerialize ser3 = new XmlSerializer(typeof(FlatClass));
ser3.Deserialize(File.OpenRead("ser3.xml"));

This last breaks, becuase the the Serializer for the BaseClass follows the schema standard (albeit a valuable and 99% of the time desired standard) of including the xsi:type="ChildClass" attribute on the element. Ser3 cannot process that type because it is not realated to that type, especially if FlatClass exists in another assembly across WAN or LAN lines. Just like the Honey-badger the XmlSerailizer DON'T CARE about the elements or values as long as it can find them and nothing in the schema breaks the process. The XSI:TYPE attribute breaks the schema.

Like, for instance, when using WCF or other XML communication based systems if the Service has a class called FlatClass, it WILL NOT DESERIALIZE a ChildClass that contains the xsi:type="" attribute. However, if you don't use the serializer for the BaseClass, it WILL deserialize the exact same XML without that xsi:type attribute.

Q.E.D. It is often times beneficial, necessary, and DESIRABLE, to NOT include the xsi:type attribute.

So with that being said is there a way to have an XmlSerializer created for the BaseClass type and tell it NOT to include the xsi:type attribute when serializing a child type?

Thanks Jaeden "Sifo Dyas" al'Raec Ruiner

like image 25
JaedenRuiner Avatar answered Nov 15 '22 21:11

JaedenRuiner