簡體   English   中英

如何創建序列化對象的集合C#

[英]How to create sets of the serialized objects C#

有多種類型,在特殊情況下可以用不同的方式進行配置。 如何序列化它們?

[Serializable]
[XmlRoot("RootXml", Namespace = "")]
public class RootXml
{
    object _schemaVersion;

    [XmlElement("SchemaVersion")]
    public object SchemaVersion
    {
        get { return _schemaVersion; }
        set { _schemaVersion = value; }
    }

    List<object> _test;

    [XmlElement("Test")]
    public List<object> Test
    {
        get { return _test; }
        set { _test = value; }
    }

    public RootXml()
    {

    }
}

即root可以包含不同的對象,並且必須將它們序列化...

我的XML格式大致如下:

<?xml version="1.0" encoding="windows-1251"?>
<RootXml>
  <SchemaVersion Number="" />
  <Report Code="">
    <Period Code="" Date="">
      <Source ClassCode="" Code="">
        <Form Code="">
          <Column Num="1" Name="" />
          <Column Num="2" Name="" />
          <Column Num="3" Name="" />         
          <Document>
            <Data code="11" />          
            <Data code="12">
              <Px Num="1" Value="1" />
              <Px Num="2" Value="1" />
              <Px Num="4" Value="2" />
              <Px Num="5" Value="2" />
            </Data>
            <Data code="13" />
          </Document>
        </Form>
      </Source>
    </Period>
  </Report>
</RootXml>

其中有些元素可能會稍有變化(文檔,帶標簽的文檔,帶狀態的文檔等),並包含在其他元素中(例如,計划中的報告在內)……並且不知道將來如何更改。

我想構造一組“格式”,其中還將包含各種組件,以供替換...也許為此,您不應該使用序列化,定義屬性集以及對處理對象和形式的反映xml(大約與XmlSerializer一樣)???

您正在嘗試使用多態字段對數據進行序列化和反序列化。 您可以在此處選擇以下幾種方式:

  1. 如果預先知道多態字段中可能遇到的所有可能的類型,則可以使用屬性告訴XmlSerializer如何序列化和反序列化每種類型。 特別是,對於多態字段,對可能遇到的每個派生類型應用[XmlElement("DerivedElementName", Type = typeof(DerivedElementType))]

    例如,為了簡化您的RootXml類,以下允許對兩種不同類型的報告進行序列化:

     [XmlRoot("Report", Namespace = "")] public class Report { [XmlAttribute] public string Code { get; set; } [XmlElement] public decimal TotalCost { get; set; } } [XmlRoot("DifferentReport", Namespace = "fuuuu")] public class DifferentReport { public DifferentReport() { } public DifferentReport(string code, string value) { this.Code = code; this.Value = value; } [XmlAttribute] public string Code { get; set; } [XmlText] public string Value { get; set; } } [XmlRoot("RootXml", Namespace = "")] public class RootXml { public RootXml() { } object _test; [XmlElement("Report", Type=typeof(Report))] [XmlElement("DifferentReport", Type = typeof(DifferentReport))] public object Data { get { return _test; } set { _test = value; } } } 

    然后,可以對以下兩個項進行序列化和反序列化:

      var root1 = new RootXml { Data = new Report { Code = "a code", TotalCost = (decimal)101.01 } }; var root2 = new RootXml { Data = new DifferentReport { Code = "a different code", Value = "This is the value of the report" } }; 

    請注意,您可以對多態列表使用相同的技術,在這種情況下,序列化程序將期望具有指定名稱的元素序列:

     [XmlRoot("RootXml", Namespace = "")] public class RootXml { public RootXml() { } List<object> _test; [XmlElement("Report", Type=typeof(Report))] [XmlElement("DifferentReport", Type = typeof(DifferentReport))] public List<object> Data { get { return _test; } set { _test = value; } } } 
  2. 如果XML可以是任何東西,而您不知道它可能包含什么(例如,因為必須從將來的版本中反序列化XML並重新序列化而不會丟失數據),則可能需要將XML加載到XDocument然后手動搜索使用Linq-to-XML的數據。 有關如何執行此操作的信息,請參見此處: 基本查詢(LINQ to XML)

  3. 您可以采用一種混合方法,將XML加載到XDocument ,然后使用XmlSerializer使用以下擴展方法對熟悉的部分進行反序列化和序列化:

     public static class XObjectExtensions { public static T Deserialize<T>(this XContainer element) { return element.Deserialize<T>(new XmlSerializer(typeof(T))); } public static T Deserialize<T>(this XContainer element, XmlSerializer serializer) { using (var reader = element.CreateReader()) { object result = serializer.Deserialize(reader); if (result is T) return (T)result; } return default(T); } public static XElement Serialize<T>(this T obj, bool omitStandardNamespaces = true) { return obj.Serialize(new XmlSerializer(obj.GetType()), omitStandardNamespaces); } public static XElement Serialize<T>(this T obj, XmlSerializer serializer, bool omitStandardNamespaces = true) { var doc = new XDocument(); using (var writer = doc.CreateWriter()) { XmlSerializerNamespaces ns = null; if (omitStandardNamespaces) (ns = new XmlSerializerNamespaces()).Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines. serializer.Serialize(writer, obj, ns); } return doc.Root; } } 

    然后使用它們來挑選和反序列化XML的已知部分,如下所示:

      var doc = XDocument.Parse(xml); var reportElement = doc.Root.Element("Report"); if (reportElement != null) { var report1 = doc.Root.Element("Report").Deserialize<Report>(); // Do something with the report. // Create a different report var differentReport = new DifferentReport { Code = report1.Code + " some more code", Value = "This is the value of the report" }; var differentElement = differentReport.Serialize(); reportElement.AddAfterSelf(differentElement); reportElement.Remove(); } 
  4. 好的,假設您正在使用c#2.0,則可以將Xml加載到XmlDocument並按如下所述使用它: 使用DOM模型處理XML數據 這是Linq-to-XML的原始API,使用起來有些困難-但仍然可以正常使用。

    您還可以采用混合方法,並使用XmlSerializer來反序列化和重新序列化XmlDocument已知塊。 這是一些用於此目的的擴展方法 - 但由於您使用的是c#2.0,因此必須刪除this關鍵字

     public static class XmlNodeExtensions { public static XmlElement SerializeToXmlElement<T>(this T o, XmlElement parent) { return SerializeToXmlElement(o, parent, new XmlSerializer(o.GetType())); } public static XmlElement SerializeToXmlElement<T>(this T o, XmlElement parent, XmlSerializer serializer) { int oldCount = parent.ChildNodes.Count; XPathNavigator navigator = parent.CreateNavigator(); using (XmlWriter writer = navigator.AppendChild()) { writer.WriteComment(""); // Kludge suggested here: https://social.msdn.microsoft.com/Forums/en-US/9ff20a3c-913d-4c6f-a18a-c10040290862/how-to-xmlserialize-directly-into-xmldocument?forum=asmxandxml serializer.Serialize(writer, o); } XmlElement returnedElement = null; for (int i = parent.ChildNodes.Count - 1; i >= oldCount; i--) { XmlComment comment = parent.ChildNodes[i] as XmlComment; if (comment != null) { parent.RemoveChild(comment); } else { returnedElement = (parent.ChildNodes[i] as XmlElement) ?? returnedElement; } } return returnedElement; } public static XmlDocument SerializeToXmlDocument<T>(this T o) { return SerializeToXmlDocument(o, new XmlSerializer(o.GetType())); } public static XmlDocument SerializeToXmlDocument<T>(this T o, XmlSerializer serializer) { XmlDocument doc = new XmlDocument(); using (XmlWriter writer = doc.CreateNavigator().AppendChild()) serializer.Serialize(writer, o); return doc; } public static T Deserialize<T>(this XmlElement element) { return Deserialize<T>(element, new XmlSerializer(typeof(T))); } public static T Deserialize<T>(this XmlElement element, XmlSerializer serializer) { using (var reader = new XmlNodeReader(element)) return (T)serializer.Deserialize(reader); } } 

    有了這些方法,您可以執行以下操作:

      // Load the document from XML XmlDocument doc = new XmlDocument(); doc.LoadXml(xml); // Find all nodes with name "Report" foreach (XmlElement reportNode in doc.SelectNodes("/RootXml/Report")) { // Deserialize as a Report Report report = XmlNodeExtensions.Deserialize<Report>(reportNode); // Do something with it // Create a new Report, based on the original report. DifferentReport differentReport = new DifferentReport(report.Code + " some more code", "This is the value of the report"); ; // Add the new report to the children of RootXml XmlElement newNode = XmlNodeExtensions.SerializeToXmlElement(differentReport, (XmlElement)reportNode.ParentNode); } 

    如您所見,這與Linq-to-XML可能實現的非常相似。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM