XML c#序列化中的控件元素

时间:2016-06-17 11:15:58

标签: c# .net xml inheritance serialization

民间,

我正在尝试创建一个基类,其中的元素将存在于几种不同的类类型中。我接近解决方案,但我需要更多地控制XML Serializer类的输出。

更新

根据下面的答案,我已经为XMl添加了Serializable接口,并且还有一点了。

下面列出的是我的新测试APP的输出,我预期的前两个XML输出,第三个是关闭但是它缺少根元素的命名空间,我需要SomeNewNameForPData来表现就好像它是PData,即没有PData与上面显示的XML一样明显,并且它也缺少基本请求类中的应用程序。有关预期输出,请参阅最终示例。

<?xml version="1.0" encoding="utf-8"?>
<Payment1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Application="MyApp">
  <Pdata Language="en">
    <TimeStamp>2016-06-17T15:31:37.7767381+01:00</TimeStamp>
  </Pdata>
  <RequestType>Pay1</RequestType>
</Payment1>

<?xml version="1.0" encoding="utf-8"?>
<Payment2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Application="MyApp">
  <Sender>ProgramClass</Sender>
  <RequestType>Pay2</RequestType>
</Payment2>

<?xml version="1.0" encoding="utf-8"?>
<Payment3>
  <SomeNewNameForPData>
    <P_Data Language="en">
      <TimeStamp>2016-06-17T15:31:37.7767381+01:00</TimeStamp>
    </P_Data>
  </SomeNewNameForPData>
</Payment3>

预期产出:

<?xml version="1.0" encoding="utf-8"?>
<Payment3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Application="MyApp">
  <SomeNewNameForPData Language="en">
      <TimeStamp>2016-06-17T15:31:37.7767381+01:00</TimeStamp>
  </SomeNewNameForPData>
</Payment3>

更新代码:

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.IO;
using System.ComponentModel;
using System.Xml;

namespace ConsoleApplication7
{
    class Program
    {
        static void Main(string[] args)
        {
            Request cp = new Payment1() { Application = "MyApp", DataField = new P_Data() { Language = "en" } };

            Request cp2 = new Payment2() { Application = "MyApp", Sender = "ProgramClass" };

            Request cp3 = new Payment3() { Application = "MyApp", DataField = new P_Data() { Language = "en" } };

            string s1 = cp.MessageAsString();

            string s2 = cp2.MessageAsString();

            string s3 = cp3.MessageAsString();

            Console.WriteLine(s1);
            Console.WriteLine("");
            Console.WriteLine(s2);
            Console.WriteLine("");
            Console.WriteLine(s3);

            Console.ReadKey();
        }
    }

    public class Helpers : StringWriter
    {
        public override Encoding Encoding
        {
            get { return Encoding.UTF8; }
        }
    }

    public abstract class Request
    {
        [XmlAttribute()]
        public string Application { get; set; }

        public virtual string MessageAsString()
        {
            return CreateMessage();
        }

        private string CreateMessage()
        {
            return SerializeObject<Request>(this, null);
        }

        public static string SerializeObject<X>(X toSerialize, XmlSerializerNamespaces xmlNameSpace)
        {
            XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());
            StringWriter textWriter = new StringWriter();

            string utf8 = ""; ;
            using (StringWriter writer = new Helpers())
            {
                xmlSerializer.Serialize(writer, toSerialize, xmlNameSpace);
                utf8 = writer.ToString();
            }

            return utf8;
        }

    }

    public abstract class RequestType1 : Request
    {
        public RequestType1()
        {
        }

        [XmlIgnore()]
        public abstract string RequestType { get; set; }

        [XmlElement("Pdata")]
        public virtual P_Data DataField { get; set; }
    }

    public abstract class RequestType2 : Request
    {
        public RequestType2()
        {
        }

        [XmlIgnore()]
        public abstract string RequestType { get; set; }

        public string Sender { get; set; }
    }

    [Serializable]
    public abstract class RequestType3 : RequestType1, IXmlSerializable
    {
        public RequestType3()
        {
        }

        [XmlElement("SomeNewNameForPData")]
        public override P_Data DataField { get; set; }

        public System.Xml.Schema.XmlSchema GetSchema()
        {
            throw new NotImplementedException();
        }

        public void ReadXml(XmlReader reader)
        {
            throw new NotImplementedException();
        }

        public void WriteXml(XmlWriter writer)
        {
            writer.WriteStartElement("SomeNewNameForPData");

            var ns = new XmlSerializerNamespaces();
            ns.Add("", "");
            new XmlSerializer(typeof(P_Data)).Serialize(writer, this.DataField, ns);

            writer.WriteEndElement();
        }
    }

    public class Payment1 : RequestType1
    {
        public Payment1()
        {
        }

        public override string RequestType
        {
            get
            {
                return "Pay1";
            }
            set { }

        }
    }

    public class Payment2 : RequestType2
    {
        public Payment2()
        {
        }

        public override string RequestType
        {
            get
            {
                return "Pay2";
            }
            set { }

        }
    }

    public class Payment3 : RequestType3
    {
        public Payment3()
        {
        }

        public override string RequestType
        {
            get
            {
                return "Pay3";
            }
            set { }

        }
    }

    public class P_Data
    {
        public P_Data()
        {
            //We need to format the datetime field
            TimeStamp = DateTime.Now;
        }

        [XmlAttribute, DefaultValue("")]
        public string Language { get; set; }

        public DateTime TimeStamp { get; set; }
    }
}

所以我的问题是:

  1. 如何在使用自定义WriteXml方法时在Payment3的根元素处添加或保留命名空间,是否还需要提供编写基类项目的方法,或者我不能通过事实上,我根据类型使用XmlSerializer序列化类?

  2. 我需要SomeNewNameForPData来表现就好像它是PData,即没有明显的PData

  3. 从基本请求类中添加回应用程序。

  4. TIA

2 个答案:

答案 0 :(得分:1)

如果在类上实现ISerializable接口,则可以控制序列化的发生方式。 https://msdn.microsoft.com/en-us/library/system.runtime.serialization.iserializable(v=vs.110).aspx

答案 1 :(得分:1)

最接近的是:

<MyRequestName Sender="MyAppName" IP="123.456.7.0">
  <NodeWhatever>
    <BaseElement type="SomeData" LanguageCode="en" />
    <BaseElement type="SomeOtherData" Amount="1000" />
  </NodeWhatever>
</MyRequestName>

为什么呢?因为如果你有多个节点就没有办法重新创建原始对象,因为没有办法找出哪个基本元素属于哪个节点!

public abstract class Root
{

    public string Sender { get; set; }


    public string IP { get; set; }

    [Persist("", ChildName = "NodeWhatever")]
    public List<Node> Nodes { get; set; }
}

[PersistInclude(typeof(SomeData),typeof(SomeOtherData))]
public class Node
{
    [Persist("")]
    public List<BaseElement> Elements { get; set; }
}

XmlArchive serial = new XmlArchive(R.GetType());
Archive.ClassKwd = "type";

string utf8 = ""; ;

using (var mm = new MemoryStream())
{
    serial.Write(mm,R,"MyRequestName");
    mm.Position = 0;

    using (var reader = new StreamReader(mm))
    {
        utf8 = reader.ReadToEnd();
    }   
}

Console.WriteLine(utf8);    

根据您更新的问题,我可以获取此xml,不确定这是否是您想要的:

<Payment1 RequestType="Pay1" Application="MyApp">
  <DataField Language="en" TimeStamp="06/17/2016 10:38:39" />
</Payment1>

<Payment2 RequestType="Pay2" Sender="ProgramClass" Application="MyApp" />

<Payment3 RequestType="Pay3" Application="MyApp">
  <MyNameWhatever Language="en" TimeStamp="06/17/2016 10:38:39" />
</Payment3>

代码:

public abstract class Request
{
    public string Application { get; set; }

    public virtual string MessageAsString()
    {
        return CreateMessage();
    }

    private string CreateMessage()
    {
        return SerializeObject<Request>(this);
    }

    public static string SerializeObject<X>(X toSerialize)
    {
        var xmlSerializer = new XmlArchive(toSerialize.GetType());
        Archive.Provider = CultureInfo.InvariantCulture;

        string utf8 = ""; ;
        using (var  writer = new MemoryStream())
        {
            xmlSerializer.Write(writer, toSerialize);
            writer.Position = 0;

            var reader = new StreamReader(writer);
            utf8 = reader.ReadToEnd();
        }

        return utf8;
    }

}

public abstract class RequestType1 : Request
{
    public abstract string RequestType { get; set; }   
    public virtual P_Data DataField { get; set; }
}

public abstract class RequestType2 : Request
{        
    public abstract string RequestType { get; set; }
    public string Sender { get; set; }
}


public abstract class RequestType3 : RequestType1
{
    [Persist("MyNameWhatever")]
    public override P_Data DataField { get; set; }

}

public class Payment1 : RequestType1
{
    public override string RequestType
    {
        get { return "Pay1"; }
        set { }
    }
}

public class Payment2 : RequestType2
{
    public override string RequestType
    {
        get { return "Pay2"; }
        set { }
    }
}

public class Payment3 : RequestType3
{
    public override string RequestType
    {
        get { return "Pay3"; }
        set { }
    }
}

public class P_Data
{
    public P_Data() { TimeStamp = DateTime.Now; }
    public string Language { get; set; }
    public DateTime TimeStamp { get; set; }
}