如何创建序列化对象集 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>
其中一些元素可以稍微改变(文档、带标签的文档、带状态的文档等),
included in others(比如report incl. in scheme)...不知道以后怎么改。
我想构建一组 "formats" ,其中也将包含各种组件,以供替换...
也许出于这个目的你不应该使用序列化,并定义
属性集,以及处理对象和形成 xml(大约与 XmlSerializer 一样)的反射???
您正在尝试使用多态字段序列化和反序列化数据。您在这里有几个选择:
如果您事先知道在多态字段中可能遇到的所有可能类型,则可以对可能遇到的每个派生类型使用 attributes to tell XmlSerializer
how to serialize and deserialize each type. In particular, for a polymorphic field, apply [XmlElement("DerivedElementName", Type = typeof(DerivedElementType))]
。
例如,稍微简化您的 RootXml
class,以下允许序列化两种不同类型的报告:
[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" } };
请注意,您可以对多态 lists 使用相同的技术,在这种情况下,序列化程序将期望具有指定名称的元素序列:
[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; }
}
}
如果 XML 可以是任何东西而你不知道它可能包含什么(因为你必须从未来的版本中反序列化 XML 并在不丢失数据的情况下重新序列化它,例如)您可能需要将 XML 加载到 XDocument
then manually search for data using Linq-to-XML. For information on how to do this, see here: Basic Queries (LINQ to XML).
您可以采用混合方法,将 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();
}
好的,鉴于您使用的是 c# 2.0,您可以将 Xml 加载到 XmlDocument
and use it as described here: Process XML Data Using the DOM Model 中。这是 Linq-to-XML 的前身 API,使用起来有点困难——但仍然可以正常工作。
您也可以采用混合方法并使用 XmlSerializer
反序列化和重新序列化 XmlDocument
的已知块。这里有一些用于此目的的 extension methods -- 但是由于您使用的是 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.
的可能性非常相似
有多种类型,在特殊情况下可以采用不同的方式进行配置。如何序列化它们?
[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>
其中一些元素可以稍微改变(文档、带标签的文档、带状态的文档等), included in others(比如report incl. in scheme)...不知道以后怎么改。
我想构建一组 "formats" ,其中也将包含各种组件,以供替换... 也许出于这个目的你不应该使用序列化,并定义 属性集,以及处理对象和形成 xml(大约与 XmlSerializer 一样)的反射???
您正在尝试使用多态字段序列化和反序列化数据。您在这里有几个选择:
如果您事先知道在多态字段中可能遇到的所有可能类型,则可以对可能遇到的每个派生类型使用 attributes to tell
XmlSerializer
how to serialize and deserialize each type. In particular, for a polymorphic field, apply[XmlElement("DerivedElementName", Type = typeof(DerivedElementType))]
。例如,稍微简化您的
RootXml
class,以下允许序列化两种不同类型的报告:[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" } };
请注意,您可以对多态 lists 使用相同的技术,在这种情况下,序列化程序将期望具有指定名称的元素序列:
[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; } } }
如果 XML 可以是任何东西而你不知道它可能包含什么(因为你必须从未来的版本中反序列化 XML 并在不丢失数据的情况下重新序列化它,例如)您可能需要将 XML 加载到
XDocument
then manually search for data using Linq-to-XML. For information on how to do this, see here: Basic Queries (LINQ to XML).您可以采用混合方法,将 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(); }
好的,鉴于您使用的是 c# 2.0,您可以将 Xml 加载到
XmlDocument
and use it as described here: Process XML Data Using the DOM Model 中。这是 Linq-to-XML 的前身 API,使用起来有点困难——但仍然可以正常工作。您也可以采用混合方法并使用
XmlSerializer
反序列化和重新序列化XmlDocument
的已知块。这里有一些用于此目的的 extension methods -- 但是由于您使用的是 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.
的可能性非常相似