一、XML序列化基本要点
在本节最先之前,起首来看一个最简朴的示例:
namespace 进修测试 { class Program { static void Main(string[] args) { Person p = new Person(1, "刘备", 176); string xmlString = ""; //xml序列化最先 using (MemoryStream ms = new MemoryStream()) { Type t = p.GetType(); XmlSerializer xml = new XmlSerializer(t); xml.Serialize(ms, p); byte[] arr = ms.ToArray(); xmlString = Encoding.UTF8.GetString(arr, 0, arr.Length); ms.Close(); } Console.WriteLine(xmlString); Console.ReadKey(); } } public class Person { //必需定义一个无参数组织函数,不然没法序列化(固然完全不写组织函数也是可以序列化的,因为有个默许的无参组织函数) public Person() { } public Person(int id, string name, int age) { Id = id; Name = name; //Age = age; } public int Id { get; set; } public string Name { get; set; } //私有字段 private int Age { get; set; } //只读属性 private int height; public int Height { get { return height; } } } }
该代码输出以下:
从以上输出,我们可以得出结论,必需请求无参组织函数,默许的也可以。但注重当默许的无参组织函数比掩盖时,要补上一个无参组织函数。别的,私有属性,只读属性是不能被序列化的。
更多的注重事项:
要序列化的类必需有默许的组织的组织函数,才运用XmlSerializer序列化;
要领不能被序列化;
索引器、私有字段或只读属性(只读鸠合属性除外)不能被序列化;
须要序列化的类都必需有一个无参的组织函数
罗列变量可序列化为字符串,无需用[XmlInclude]
导出非基本范例对象,都必需用[XmlInclude]事前声明。该划定规矩递归作用到子元素
Attribute中的IsNullable参数若即是false,示意若元素为null则不显现该元素。(针对值范例有效)
某些类就是没法XML序列化的(纵然运用了[XmlInclude])
IDictionary(如HashTable)
父类对象给予子类对象值的状况
对象间轮回援用
9.关于没法XML序列化的对象,可斟酌
运用自定义xml序列化(完成IXmlSerializable接口)
完成IDictionary的类,可斟酌(1)用别的鸠合类替换;(2)用类封装之,并供应Add和this函数
某些范例须要先经由转换,然后才序列化为 XML。如XML序列化System.Drawing.Color,可先用ToArgb()将其转换为整数
过于庞杂的对象用xml序列化不方便的话,可斟酌用二进制序列化。
不想序列化时:
当不想序列化一个属性时,运用[System.Xml.Serialization.XmlIgnore]标记,能用于属性;
[NonSerializable]应用于属性无效,能用于类,构造体等
默许组织函数是必需的,因为反序列化本质上运用的是反射,须要默许组织函数来实例化类,假如去掉个中的默许组织函数,则编译没有题目,但运转就会报错。
只管不要将比较大的属性放在默许组织函数初始化,那会致使在反序列化时对列表初始化两次:默许组织函数中实行一次,反序列化时从XML文档读取再实行一次。
二、转变XML序列化的默许值
平常,在XML序列化的历程当中,有许多东西是自动生成的,比方XML命名空间,编码等等。
1、去除默许的命名空间与前缀:
XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("", ""); //第一个参数是前缀,第二个参数是命名空间 //然后在序列化的时刻,指定自定义命名空间 xml.Serialize(ms, p, ns);
输出对照:
固然,这个要领也可以用于生成你想要的自定义命名空间。
2、去除XML声明:顶部的 <?xml version="1.0" encoding="utf-8"?>
public static string ObjectToXmlSerializer(Object Obj) { XmlWriterSettings settings = new XmlWriterSettings(); //去除xml声明 settings.OmitXmlDeclaration = true; settings.Encoding = Encoding.Default; System.IO.MemoryStream mem = new MemoryStream(); using (XmlWriter writer = XmlWriter.Create(mem, settings)) { //去除默许命名空间xmlns:xsd和xmlns:xsi XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("", ""); XmlSerializer formatter = new XmlSerializer(Obj.GetType()); formatter.Serialize(writer, Obj, ns); } return Encoding.Default.GetString(mem.ToArray()); }
输出:
3、换行缩进
settings.Indent = true;
当XmlWriterSettings云云设置后,输出的XML为:
4、指定缩进字符
settings.IndentChars = "--";
输出以下:
XmlWriterSettings更多设置属性以下:
成员 | 申明 |
CloseOutput | 猎取或设置一个值,该值指导在挪用 Close 要领时,XmlWriter 是不是还应该封闭基本流或 TextWriter。 |
Encoding | 猎取或设置要运用的文本编码的范例。 |
Indent | 猎取或设置一个值,该值指导是不是缩进元素。 |
IndentChars | 猎取或设置缩进时要运用的字符串。 |
NamespaceHandling | 猎取或设置一个值,该值指导在编写 XML 内容时,XmlWriter 是不是应移除反复的命名空间声明。 的默许是输出顺序中涌现的一切命名空间声明。 |
NewLineChars | 猎取或设置要用于分行符的字符串 |
NewLineHandling | 猎取或设置一个值,该值指导是不是将输出中的分行符正常化。 |
NewLineOnAttributes | 猎取或设置一个值,该值指导是不是将属性写入新行。 |
OmitXmlDeclaration | 猎取或设置一个值指导省略 XML 声明。 |
Encoding | 猎取或设置要运用的文本编码的范例。 |
Reset要领 | 重置以上属性 |
http://msdn.microsoft.com/zh-cn/library/system.xml.xmlwritersettings(v=vs.110).aspx
三、完成序列化接口IXmlSerializable
完成IXmlSerializable接口以后,我们可以自定义类序列化的体式格局。
该接口包括3个要领:
XmlSchema GetSchema(); void ReadXml(XmlReader reader); void WriteXml(XmlWriter writer);
简朴示例:
namespace 自定义序列化 { class Program { static void Main(string[] args) { Person p = new Person(); p.Id = 1; p.Name = "刘备"; string str = ObjectToXmlSerializer(p); Console.WriteLine(str); Person p1 = ObjectToXmlDESerializer<Person>(str); Console.WriteLine("我的名字是:" + p1.Name); Console.ReadKey(); } //序列化Xml public static string ObjectToXmlSerializer(Object Obj) { string XmlString = ""; XmlWriterSettings settings = new XmlWriterSettings(); //去除xml声明 //settings.OmitXmlDeclaration = true; settings.Indent = true; settings.Encoding = Encoding.Default; using (System.IO.MemoryStream mem = new MemoryStream()) { using (XmlWriter writer = XmlWriter.Create(mem, settings)) { //去除默许命名空间xmlns:xsd和xmlns:xsi XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("", ""); XmlSerializer formatter = new XmlSerializer(Obj.GetType()); formatter.Serialize(writer, Obj, ns); } XmlString = Encoding.Default.GetString(mem.ToArray()); } return XmlString; } //反序列化 public static T ObjectToXmlDESerializer<T>(string str)where T : class { object obj; using (System.IO.MemoryStream mem = new MemoryStream(Encoding.Default.GetBytes(str))) { using (XmlReader reader = XmlReader.Create(mem)) { XmlSerializer formatter = new XmlSerializer(typeof(T)); obj = formatter.Deserialize(reader); } } return obj as T; } } public class Person { public int Id { get; set; } public string Name { get; set; } } public class PersonSerializer : IXmlSerializable { private Person p; public int Id { get; set; } public string Name { get; set; } #region IXmlSerializable 成员 System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() { throw new NotImplementedException(); } //假如这个要领默许则报:XML 文档(2, 2)中有毛病。 void IXmlSerializable.ReadXml(XmlReader reader) { reader.ReadElementString("Person"); } void IXmlSerializable.WriteXml(XmlWriter writer) { writer.WriteElementString("Id", Id.ToString()); writer.WriteElementString("Name", Name); } #endregion } }
输出以下:
我们都晓得,接口是不支持序列化的。下面来做个有效的示例,完成IList<T>的序列化与反序列化:
namespace IList<T>的序列化与反序列化 { class Program { static void Main(string[] args) { Woman w1 = new Woman() { Id = 1, Name = "貂蝉" }; Woman w2 = new Woman() { Id = 2, Name = "西施" }; List<Woman> ListWoman = new List<Woman>(); ListWoman.Add(w1); ListWoman.Add(w2); Person p = new Person(); p.Id = 1; p.Name = "刘备"; p.ListWoman = ListWoman; string str = ObjectToXmlSerializer(p); Console.WriteLine(str); Person p1 = ObjectToXmlDESerializer<Person>(str); Console.WriteLine("我的名字是:" + p1.Name + "我的妻子有:"); foreach (Woman w in p1.ListWoman) { Console.WriteLine(w.Name); } Console.ReadKey(); } //序列化Xml public static string ObjectToXmlSerializer(Object Obj) { string XmlString = ""; XmlWriterSettings settings = new XmlWriterSettings(); //去除xml声明 //settings.OmitXmlDeclaration = true; settings.Indent = true; settings.Encoding = Encoding.Default; using (System.IO.MemoryStream mem = new MemoryStream()) { using (XmlWriter writer = XmlWriter.Create(mem, settings)) { //去除默许命名空间xmlns:xsd和xmlns:xsi XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("", ""); XmlSerializer formatter = new XmlSerializer(Obj.GetType()); formatter.Serialize(writer, Obj, ns); } XmlString = Encoding.Default.GetString(mem.ToArray()); } return XmlString; } //反序列化 public static T ObjectToXmlDESerializer<T>(string str) where T : class { object obj; using (System.IO.MemoryStream mem = new MemoryStream(Encoding.Default.GetBytes(str))) { using (XmlReader reader = XmlReader.Create(mem)) { XmlSerializer formatter = new XmlSerializer(typeof(T)); obj = formatter.Deserialize(reader); } } return obj as T; } } public class Person : IXmlSerializable { public int Id { get; set; } public string Name { get; set; } public IList<Woman> ListWoman { get; set; } #region IXmlSerializable 成员 System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() { throw new NotImplementedException(); } void IXmlSerializable.ReadXml(XmlReader reader) { //一定要迥殊注重配对题目,不然很轻易反序列化鸠合涌现只可以读取第一个的状况 reader.ReadStartElement("Person"); Id = Convert.ToInt32(reader.ReadElementString("Id")); Name = reader.ReadElementString("Name"); //我也不晓得为何,庞杂范例只可以别的定义一个,取得值以后再给本来的赋值 List<Woman> ListWoman2 = new List<Woman>(); reader.ReadStartElement("ListWoman"); while (reader.IsStartElement("Woman")) { Woman w = new Woman(); reader.ReadStartElement("Woman"); w.Id = Convert.ToInt32(reader.ReadElementString("Id")); w.Name = reader.ReadElementString("Name"); reader.ReadEndElement(); reader.MoveToContent(); ListWoman2.Add(w); } ListWoman = ListWoman2; reader.ReadEndElement(); reader.ReadEndElement(); } void IXmlSerializable.WriteXml(XmlWriter writer) { //这里是不须要WriteStart/End Person的 writer.WriteElementString("Id", Id.ToString()); writer.WriteElementString("Name", Name); //有重载,想设置命名空间,只需在参数加上 writer.WriteStartElement("ListWoman"); foreach (Woman item in ListWoman) { PropertyInfo[] ProArr = item.GetType().GetProperties(); writer.WriteStartElement("Woman"); foreach (PropertyInfo p in ProArr) { writer.WriteElementString(p.Name, p.GetValue(item, null).ToString()); } writer.WriteEndElement(); } writer.WriteEndElement(); } #endregion } public class Woman { public int Id { get; set; } public string Name { get; set; } } }
输出以下:
以上代码是可以直接用于序列化数组的,也就是IList<Person>的,下面在贴上两个序列化与反序列化IList<T>的要领:
//序列化Xml public static string ListToXmlSerializer<T>(IList<T> ListT) { XmlSerializer ser = new XmlSerializer(ListT.GetType()); System.IO.MemoryStream mem = new MemoryStream(); XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; settings.OmitXmlDeclaration = false; settings.Encoding = Encoding.UTF8; XmlWriter writer = XmlWriter.Create(mem, settings); ser.Serialize(writer, ListT); writer.Close(); string strtmp = Encoding.UTF8.GetString(mem.ToArray()); return strtmp; } //反序列化Xml public static List<T> XmlToListSerializer<T>(Stream stream) { string XmlPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + @"\OutLine\" + typeof(T).Name + ".xml"; using (StreamReader sr = new StreamReader(stream, System.Text.Encoding.UTF8)) { XmlSerializer ser = new XmlSerializer(typeof(List<T>)); var listsch = ser.Deserialize(sr); List<T> reses = listsch as List<T>; return reses; } }
下面给出一个序列化与反序列化经由过程反射的庞杂对象的示例:
using System.Linq.Expressions;namespace 掌握台___进修测试 { class Program { static void Main(string[] args) { Woman w1 = new Woman() { Id = 1, Name = "貂蝉" }; Woman w2 = new Woman() { Id = 2, Name = "西施" }; List<Woman> ListWoman1 = new List<Woman>(); ListWoman1.Add(w1); ListWoman1.Add(w2); List<Person> ListPerson = new List<Person>(); Person p1 = new Person() { Id = 1, Name = "刘备", ListWoman = ListWoman1 }; Person p2 = new Person() { Id = 2, Name = "关羽", ListWoman = ListWoman1 }; Person p3 = new Person() { Id = 3, Name = "张飞", ListWoman = ListWoman1 }; ListPerson.Add(p1); ListPerson.Add(p2); ListPerson.Add(p3); string xml = ListToXmlSerializer(ListPerson); Console.WriteLine(xml); MemoryStream mem = new MemoryStream(Encoding.UTF8.GetBytes(xml)); List<Person> ListPerson2 = XmlToListSerializer<Person>(mem); Console.WriteLine(ListPerson2.Count); Console.WriteLine(ListPerson2[2].ListWoman[1].Name); Console.ReadKey(); } //序列化Xml public static string ListToXmlSerializer<T>(IList<T> ListT) { XmlSerializer ser = new XmlSerializer(ListT.GetType()); System.IO.MemoryStream mem = new MemoryStream(); XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; settings.OmitXmlDeclaration = true; settings.Encoding = Encoding.UTF8; XmlWriter writer = XmlWriter.Create(mem, settings); ser.Serialize(writer, ListT); writer.Close(); string strtmp = Encoding.UTF8.GetString(mem.ToArray()); File.WriteAllText(@"D:\222.xml", strtmp); return strtmp; } //反序列化Xml public static List<T> XmlToListSerializer<T>(Stream stream) { using (StreamReader sr = new StreamReader(stream, System.Text.Encoding.UTF8)) { XmlSerializer ser = new XmlSerializer(typeof(List<T>)); var listsch = ser.Deserialize(sr); List<T> reses = listsch as List<T>; return reses; } } } public class Person : IXmlSerializable { public int Id { get; set; } public string Name { get; set; } public IList<Woman> ListWoman { get; set; } #region IXmlSerializable 成员 System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() { throw new NotImplementedException(); } void IXmlSerializable.ReadXml(XmlReader reader) { //while (reader.Name == "Person") //{ reader.ReadStartElement("Person"); Id = Convert.ToInt32(reader.ReadElementString("Id")); Name = reader.ReadElementString("Name"); List<Woman> newWomans = new List<Woman>(); PropertyInfo[] ProArr = typeof(Woman).GetProperties(); reader.ReadStartElement("ListWoman"); while (reader.IsStartElement("Woman")) { Woman Item2 = new Woman(); reader.ReadStartElement("Woman"); foreach (PropertyInfo p in ProArr) { string str = reader.ReadElementString(p.Name); p.SetValue(Item2, Convert.ChangeType(str, p.PropertyType), null); } reader.ReadEndElement(); reader.MoveToContent(); newWomans.Add(Item2); } ListWoman = newWomans; reader.ReadEndElement(); reader.ReadEndElement(); } void IXmlSerializable.WriteXml(XmlWriter writer) { writer.WriteElementString("Id", Id.ToString()); writer.WriteElementString("Name", Name); writer.WriteStartElement("ListWoman"); foreach (Woman item in ListWoman) { PropertyInfo[] ProArr = item.GetType().GetProperties(); writer.WriteStartElement("Woman"); foreach (PropertyInfo p in ProArr) { if (p.GetValue(item, null) != null) { writer.WriteElementString(p.Name, p.GetValue(item, null).ToString()); } else { writer.WriteElementString(p.Name, ""); } } writer.WriteEndElement(); } writer.WriteEndElement(); } #endregion } public class Woman { public int Id { get; set; } public string Name { get; set; } } }
以上代码输出:
迥殊提醒,一定要迥殊迥殊注重,ReadStartElement与ReadEndElement的题目,不然很轻易涌现反序列化鸠应时只可以读取第一个的状况。而关于序列化,假如WriteStartElement与WriteEndElement不婚配,涌现的只是XML标签对不婚配的题目,没Read的时刻那末坑。
四、XML特征
偶然,我们在序列化时想要自定义XML的构造,这时刻就要用到我们的属性类了。属性类供应了许多特征供我们运用,以完成自定义序列化功用。
称号 | 形貌 |
XmlAttribute | 示意一个特征对象的鸠合,这些对象掌握XmlSerializer怎样序列化和反序列化对象 |
XmlArrayAttribute | 指定XmlSerializer应将特定的类成员序列化为XML元素数组 |
XmlArrayItemAttribute | 指定XmlSerializer可以安排在序列化数组中的派生范例 |
XmlArrayItemAttributes | 示意XmlArrayItemAttribute对象的鸠合 |
XmlAttributeAttribute | 指定XmlSerializer应将类成员作为XML特征序列化 |
XmlChoiceIdentifierAttribute | 指定可以经由过程运用罗列来进一步消弭成员的歧义 |
XmlElementAttribute | 在XmlSerializer序列化或反序列化包括对象时,指导大众字段或属性示意XML元素 |
XmlElementAttributes | 示意XmlElementAttribute的鸠合,XmlSerializer将其用于它重写序列化类的默许体式格局 |
XmlEnumAttribute | 掌握XmlSerializer怎样序列化罗列成员 |
XmlIgnoreAttribute | 指导XmlSerializer要领不序列化大众字段或大众读/写属性值 |
XmlIncludeAttribute | 许可XmlSerializer在它序列化或反序列化对象时辨认范例 |
XmlRootAttribute | 掌握视为XML根元素的属性目的的XML序列化 |
XmlTextAttribute | 当序列化或反序列化时,想XmlSerializer指导应将此成员作为XML文本处理 |
XmlTypeAttribute | 掌握当属性目的由XmlSerializer序列化时生成的XML构造 |
XmlAnyAttributeAttribute | 指定成员(返回XmlAttribute对象的数组的字段)可以包括XML属性 |
XmlAnyElementAttribute | 指定成员可以包括对象,该对象示意在序列化或反序列化的对象中没有响应成员的一切XML元素 |
XmlAnyElementAttributes | 示意XmlAnyElementAttribute对象的鸠合 |
XmlAttributeEventArgs | 为UnKnowAttribute供应数据 |
XmlAttributeOverrides | 许可你在运用XmlSerializer序列化或反序列化时重写属性、字段和类特征 |
XmlElementEventArgs | 为UnknownElement事宜供应数据 |
XmlNamespaceDeclarationsAttribute | 指定目的属性、参数、返回值或类成员包括与XML文档中所用命名空间关联的前缀 |
XmlNodeEventArgs | 为UnknownNode时候供应数据 |
XmlSerializer | 将对象序列化到XML文档中和从XML文档中反序列化对象,XmlSerializer使你得以掌握怎样将对象编码到XML中 |
XmlSerializerNamespaces | 包括XmlSerializer用于在XML文档实例中生成限命名的XML命名空间和前缀 |
XmlTypeMapping | 包括从一种范例到另一种范例的映照 |
下面仅仅给出两个简朴示例:
namespace 进修测试 { [Serializable] public class Person { public Person() { } public int Id { get; set; } public string Name { get; set; } [XmlAttribute(DataType = "string")] public string Content { get; set; } [XmlIgnore] public int Age { get; set; } [XmlArray] [XmlArrayItem("Int32", typeof(Int32))] public IList ListInt { get; set; } } class Program { static void Main(string[] args) { IList list = new ArrayList(); list.Add(1); list.Add(2); list.Add(3); Person p = new Person(); p.Id = 1; p.Name = "刘备"; p.Age = 23; p.Content = "这是一个牛人"; p.ListInt = list; string strXml = ObjectToXmlSerializer(p); Console.WriteLine(strXml); //反序列化IList另有题目 //Person p2 = ObjectToXmlDESerializer<Person>(strXml); //Console.WriteLine(p2.Name); Console.ReadKey(); } //序列化 public static string ObjectToXmlSerializer(Object Obj) { string XmlString = ""; XmlWriterSettings settings = new XmlWriterSettings(); //去除xml声明 //settings.OmitXmlDeclaration = true; settings.Indent = true; settings.Encoding = Encoding.Default; using (System.IO.MemoryStream mem = new MemoryStream()) { using (XmlWriter writer = XmlWriter.Create(mem, settings)) { //去除默许命名空间xmlns:xsd和xmlns:xsi XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("", ""); XmlSerializer formatter = new XmlSerializer(Obj.GetType()); formatter.Serialize(writer, Obj, ns); } XmlString = Encoding.Default.GetString(mem.ToArray()); } return XmlString; } //反序列化Xml public static T ObjectToXmlDESerializer<T>(string str) where T : class { object obj; using (System.IO.MemoryStream mem = new MemoryStream(Encoding.Default.GetBytes(str))) { using (XmlReader reader = XmlReader.Create(mem)) { XmlSerializer formatter = new XmlSerializer(typeof(T)); obj = formatter.Deserialize(reader); } } return obj as T; } } }
2013/12/27 常遇毛病纪录:
反序列化毛病提醒:
1、XML 文档(2, 2)中有毛病:
报这个毛病平常是因为序列化与反序列化的范例不一致:
XmlSerialize.Serialize(@"C:\Person.xml",person); //person 是 Person类的对象var test = XmlSerialize.DeSerialize(typeof(Person), @"C:\Person.xml");
2014/08/12
2、XmlIgnore与NonSerialized的区分。
1、XmlIgnore能作用于属性,NonSerialized只作用于字段。
2、XmlIgnore对序列化与反序列化均有效,而NonSerialized只影响序列化,反序列化不论。(非百分百肯定)
以上就是Xml序列化的图文代码详解的细致内容,更多请关注ki4网别的相干文章!