XmlSerializer将xsi:type替换为节点名称

时间:2012-02-20 10:55:52

标签: .net serialization xml-serialization

目前XmlSerializer产生以下结构:

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

有没有办法让它将类型名称放入节点:

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

3 个答案:

答案 0 :(得分:26)

使用XmlElementAttribute构造函数重载(string elementName, Type type)。 它允许您替换在成员中找到的实际类型的元素名称。 如果您有多个派生类型,请将其中的几个堆叠在一起。

如果您尝试序列化可能包含Derived实例的List<Base>等通用集合,请以相同方式使用XmlArrayItem

以这种方式定义也隐式地使派生类型已知,因此不需要XmlInclude属性

样本定义:

[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 { ... }

答案 1 :(得分:1)

为什么人们一直说“你永远无法反序列化”。 这在定义上是假的。

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"));

动臂。工作得很精致!!!!! 序列化完全符合这两种方式。生成的对象可能不是100%,但它反序列化。 Ser1在反序列化ser2.xml时忽略Value元素 Ser2 SKIPS在反序列化ser1.xml时的价值属性

打破这个模型的唯一因素是:

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"));

这最后一次打破,因为BaseClass的Serializer遵循在元素上包含xsi:type =“ChildClass”属性的架构标准(尽管是有价值且99%的所需时间标准)。 Ser3无法处理该类型,因为它不依赖于该类型,特别是如果FlatClass存在于WAN或LAN线路的另一个程序集中。 就像Honey-badger一样,XmlSerailizer不关心元素或值,只要它能找到它们并且模式中的任何内容都不会破​​坏过程。 XSI:TYPE属性会破坏架构。

例如,当使用WCF或其他基于XML通信的系统时,如果Service有一个名为FlatClass的类,它就不会DESREIALIZE包含xsi:type =“”属性的ChildClass。但是,如果不对BaseClass使用序列化程序,它将反序列化完全相同的XML而不使用xsi:type属性。

Q.E.D。 NOT 包含xsi:type属性通常是有益的,必要的和可取的。

所以说有没有办法为BaseClass类型创建一个XmlSerializer,并告诉它在序列化子类型时不要包含xsi:type属性?

由于 Jaeden“Sifo Dyas”al'Raec Ruiner

答案 2 :(得分:0)

你可以用XmlElement Attrribute覆盖元素名称,例如

[XmlElement("DerivedType1")]
public BaseType : DerivedType1 {get;set;}

如果仍然会将xsi:type放入,并产生更大的混淆......

你的班级是什么样的?