Custom XML serialization with inheritance

[亡魂溺海] 提交于 2020-01-25 00:33:45

问题


I have the following class structure which I want to serialize:

    [XmlRoot("SomeClass")]
public class SomeClass
{
    private BaseClass[] _itemArray;
    public BaseClass[] ItemArray
    {
        get { return _itemArray; }
        set { _itemArray = value; }
    }

    public PPSPStatReportMessage()
        : base()
    {
    }
}

public class SomeOtherClass
{
    private int _property5;
    [XmlAttribute("Property5")]
    public int Property5
    {
        get { return _property5; }
        set { _property5 = value; }
    }

    private string _property6;
    [XmlText()]
    public string Property6
    {
        get { return _property6; }
        set { _property6 = value; }
    }

    public SomeOtherClass()
    {
    }
}

[XmlInclude(typeof(DerivedClass1))]
[XmlInclude(typeof(DerivedClass2))]
[XmlRoot("BaseClass")]
[XmlType("")]
public class BaseClass
{
    private string _property1;
    [XmlAttribute("Property1")]
    public string Property1
    {
        get { return _property1; }
        set { _property1 = value; }
    }

    public SomeClass(string PropertyVal)
    {
        _property1 = PropertyVal;
    }
}

[XmlRoot("BaseClass")]
[XmlTypeAttribute(Namespace = "")]
public class DerivedClass1 : BaseClass
{
    private string _property2;
    [XmlAttribute("Property2")]
    public string Property2
    {
        get { return _property2; }
        set { _property2 = value; }
    }


    private SomeOtherClass _property3;
    [XmlElement("SomeOtherClass")]
    public SomeOtherClass Property3
    {
        get { return _property3; }
        set { _property3 = value; }
    }

    public DerivedClass()
        : base("PropertyVal1")
    {
    }
}

[XmlRoot("BaseClass", Namespace = "")]
[XmlType("")]
public class DerivedClass2 : BaseClass
{
    private Int64 _property4;
    [XmlAttribute("Property4")]
    public Int64 Property4
    {
        get { return _property4; }
        set { _property4 = value; }
    }

    public DerivedClass2()
        : base("PropertyVal2")
    {
    }
}

And this is the method I use to serialize SomeClass:

public static string SerializeXML(object Value, System.Type ObjectType)
    {
        XmlSerializer serializer = new XmlSerializer(ObjectType);
        XmlSerializerNamespaces namespaceSerializer = new XmlSerializerNamespaces();
        namespaceSerializer.Add("", "");
        StringWriter ms = new StringWriter();
        serializer.Serialize(ms, Value, namespaceSerializer);
        return ms.ToString();
    }

This method generates an XML structure that looks like the following:

<?xml version="1.0" encoding="utf-16"?>
<SomeClass>
  <ItemArray>
    <BaseClass d3p1:type="DerivedClass1" Property1="PropertyVal1" Property2="123" xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance">
      <SomeOtherClass Property5="0" >STRING DATA</SomeOtherClass>
    </BaseClass>
    <BaseClass d3p1:type="DerivedClass2" Property="PropertyVal2" Property4="456" xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance" />
  </ItemArray>
</SomeClass>

However, I need to omit the d3p1:type and xmlns:d3p1 attributes and generate an XML structure that looks like this:

<?xml version="1.0" encoding="utf-16"?>
<SomeClass>
  <ItemArray>
    <BaseClass Property1="PropertyVal1" Property2="123">
      <SomeOtherClass Property5="0" >STRING DATA</SomeOtherClass>
    </BaseClass>
    <BaseClass Property="PropertyVal2" Property4="456" />
  </ItemArray>
</SomeClass>

As you can see in the code, I've tried to use XmlType and XmlTypeAttribute, but without success.

Any advice on how can I generate the XML structure as described above (without d3p1:type and xmlns:d3p1 attributes)?


回答1:


Do you need the subclass elements to be called "BaseClass" - or would the name of the derived class do?

I am serializing similar subclass structures, and also wanted to get rid of the "d3p1:type" and "xmlns:d3p1" tags - instead replacing the "BaseClass" tags with derived class tags. So it is possible to generate xml for your example:

<ItemArray>
    <DerivedClass1 Property1="PropertyVal1" Property2="123">
        ....
    </DerivedClass1>

You're using an XmlInclude attribute on your BaseClass to let the serliazer know which derived classes to expect. Instead, you can tell the serializer about the expected subtypes on each element:

public class SomeClass
{
    private BaseClass[] _itemArray;

    [XmlElement(typeof(DerivedClass1))]
    [XmlElement(typeof(DerivedClass2))]
    public BaseClass[] ItemArray
    { 
        get { return _itemArray; }
        set { _itemArray = value; }
}

Eliminating the "type" attributes. Deserialiazation will also work fine.




回答2:


You cannot accomplish what you want directly.

If the type being serialized isn't the exact type contained, .NET has to track what the type really is to allow proper deserialization.

To accomplish what you want - use RegEx.Replace() or other post-processing to replace the namespaces.

(e.g. serializing Object which is really a String will cause this problem).




回答3:


XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
settings.Indent = true;

using (XmlWriter writer = XmlWriter.Create(file, settings))
{
    XmlSerializer serializer = new XmlSerializer(source.GetType());

    XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
    namespaces.Add(string.Empty, string.Empty);
    // ...
}


来源:https://stackoverflow.com/questions/5170300/custom-xml-serialization-with-inheritance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!