2016-06-17 8 views
0

Folks,Элементы управления в XML C# сериализации

Я пытаюсь создать базовый класс с элементами, которые будут существовать в нескольких различных типов классов. Я близок к решению, но мне нужно немного больше контролировать вывод из класса XML Serializer.

UPDATE


Ok на основе ответа ниже я добавил Serializable интерфейс для Xml и получили немного дальше.

Ниже представлен выход из моего нового тестового 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. Как добавить или сохранить пространство имен в корневом элементе для Payment3 при использовании custo m WriteXml, мне также нужно предоставить средства для записи элементов базового класса или не получить их в силу того факта, что я сериализую класс с помощью XmlSerializer на основе его типа?

  2. мне нужно SomeNewNameForPData действовать, как если бы оно было PDATA, т.е. не PDATA наглядного

  3. Добавить обратно в Заявлении от базового класса Request.

ТИА

+0

Можете ли вы объяснить, почему вы не хотите для отображения узла ''? –

+0

Я использую Nodes в качестве плачхолдера для различных кланов, которые могут существовать в Request или RequestType2, поэтому этот список NODE добавляется с разными классами в зависимости от того, что требуется третьей стороне. В классе Nodes я указываю все элементы, которые могут существовать, это всего лишь подмножество из них для демонстрационных целей, чтобы объяснить проблему. –

ответ

1

, если вы реализуете интерфейс ISerializable на вашем классе вы можете контролировать, как сериализация происходит. https://msdn.microsoft.com/en-us/library/system.runtime.serialization.iserializable(v=vs.110).aspx

+0

Спасибо, Пол, я реализовал интерфейс IXMLSerializable, у меня есть все еще, но все еще остаются проблемы. Я обновил свой оригинальный пост, какие-либо дальнейшие предложения? TIA –

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; } 
} 
+0

Спасибо elios, у меня с тех пор прошло по-другому, основываясь на похожих комментариях, которые я читал в другом месте, я обновил исходное сообщение новым кодом. –

Смежные вопросы