转载

[.net 面向对象程序设计进阶] (10) 序列化(Serialization)(二) 通过序列化博客园文章学习XML的序列化

[.net 面向对象程序设计进阶] (10) 序列化(Serialization)(二) 通过序列化博客园文章学习XML的序列化

本节导读:

上节我们介绍了二进制流的序列化,本节继续上节内容介绍XML序列化和反序列化。XML作为W3C标准数据传输格式,将XML对象化处理,认识和使用XML序列化类XmlSerializer,是.NET面向对象程序设计必须要掌握的知识。

读前必备:

A. 修饰符         [.net 面向对象编程基础 ]  (8) 基础中的基础 —— 修饰符  

B. 类和类的实例  [.net 面向对象编程基础 ]  (9) 类和类的实例

C. 类的成员        [.net 面向对象编程基础 ] (10) 类的成员(字段、属性、方法)

D. 数组与集合 [.net 面向对象编程基础] (17)  数组与 集合

E. 泛型           [.net 面向对象编程基础] (18) 泛型

F.LINQ 使用   [.net 面向对象编程基础 ] (20) LINQ 使用

1. 关于XML

XML 指可扩展标记语言(EXtensible Markup   Language)

XML 是一种标记语言,很类似 HTML

XML 的设计宗旨是传输数据,而非显示数据

XML 标签没有被预定义。您需要自行定义标签。

XML 被设计为具有自我描述性。

XML 是 W3C 的推荐标准

关于XML相关的基础知识,这里不作为重点赘述,下面入正题。

2. XML序列化

XML序列化的命名空间是:System.Xml.Serialization

类:XmlSerializer

主要方法:Serialize和Deserialize

下面先来一个简单有意思的XML序列化,为了让小伙伴们有兴趣看完,我来实现动态获取博客园实时数据(这个不是重点,本节重在在于序列化和反序列化),进行序列化。

首先获取获博客园文章,创建文章实体类,如下:

public class MyBlogs {  /// <summary>  /// 获取我的博客园中文章  /// </summary>  /// <returns></returns>  public  static List<MyArticle> GetMyArticle(int count)  {   var document = XDocument.Load(    "http://wcf.open.cnblogs.com/blog/u/yubinfeng/posts/1/" + count    );   List<MyArticle> myArticleList = new List<MyArticle>();   var elements = document.Root.Elements();   //在进行这个工作之前,我们先获取我博客中的文章列表   var result = elements.Where(m => m.Name.LocalName == "entry").Select(myArticle => new MyArticle   {    id = Convert.ToInt32(myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "id").Value),    title = myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "title").Value,    published = Convert.ToDateTime(myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "published").Value),    updated = Convert.ToDateTime(myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "updated").Value),    diggs = Convert.ToInt32(myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "diggs").Value),    views = Convert.ToInt32(myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "views").Value),    comments = Convert.ToInt32(myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "comments").Value),    summary = myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "summary").Value,    link = myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "link").Attribute("href").Value,    author = myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "author").Elements().SingleOrDefault(x => x.Name.LocalName == "name").Value   }).OrderByDescending(m=>m.published);   myArticleList.AddRange(result);   return myArticleList;  } } /// <summary /// 我的博客文章实体类 /// </summary> public class MyArticle {  /// <summary>  /// 文章编号  /// </summary>  public int id { get; set; }  /// <summary>  /// 文章标题  /// </summary>  public string title { get; set; }  /// <summary>  /// 文章摘要  /// </summary>  public string summary { get; set; }  /// <summary>  /// 发布时间  /// </summary>  public DateTime published { get; set; }  /// <summary>  /// 最后更新时间  /// </summary>  public DateTime updated { get; set; }  /// <summary>  /// URL地址  /// </summary>  public string link { get; set; }  /// <summary>  /// 推荐数  /// </summary>  public int diggs { get; set; }  /// <summary>  /// 浏览量  /// </summary>  public int views { get; set; }  /// <summary>  /// 评论数  /// </summary>  public int comments { get; set; }  /// <summary>  /// 作者  /// </summary>  public string author { get; set; } } 

下面实现myArticleList对象序列化XML并输出到控制台  

//XML序列化命名空间:System.Xml.Serialization; //类:XmlSerializer //主要方法:Serialize和Deserialize //博客数据的对象化(反序列化)及序列化 //(1)获取我博客园中最后10篇文章 (实际上这个过程也是反序列化) List<MyArticle> myArticleList = MyBlogs.GetMyArticle(10);     //(2)将上面的对象myArticleList序列化XML,并输出到控制台 string xmlString = String.Empty; using (MemoryStream ms = new MemoryStream()) {     XmlSerializer xml = new XmlSerializer(typeof(List<MyArticle>));     xml.Serialize(ms, myArticleList);     byte[] arr = ms.ToArray();     xmlString = Encoding.UTF8.GetString(arr, 0, arr.Length);     ms.Close(); } Console.WriteLine(xmlString); 

运行结果如下:

[.net 面向对象程序设计进阶] (10) 序列化(Serialization)(二) 通过序列化博客园文章学习XML的序列化

上面的示例,实现了一个最基本的从对象到XML的序列化。接下来完成上面示例序列化的xmlString文本对象化为List<MyArticle>

3. XML反序列化

Xml反序列化,即将Xml文本转化为对象的过程。

我们将上面序列化的文本xmlString反序列化为List<MyArticle>对象  

//下面我们刚才输出的xmlString文本对象化(反序列化)为一个文章List对象 using (StringReader sr = new StringReader(xmlString)) {  XmlSerializer xml=new XmlSerializer(typeof(List<MyArticle>));      ;  List<MyArticle> myNewArticleList= xml.Deserialize(sr) as List<MyArticle>;  //遍历输出反序化的新对象myNewArticleList  myNewArticleList.ForEach(m =>   Console.WriteLine("文章编号:" + m.id + "/n文章标题:" + m.title)         );  sr.Close(); } 

运行结果如下:

[.net 面向对象程序设计进阶] (10) 序列化(Serialization)(二) 通过序列化博客园文章学习XML的序列化  

上面的示例实现了从XML文本反序列化为List<MyArticle> 对象的过程。

学会了上面的两个示例,就掌握了XML序列化和反序列化的基本知识,下面介绍更进一步介绍在序列化过程中的一些细节。

4. XML序列化一些注意事项

(1)要序列化的类必须有默认的构造的构造函数,才能使用XmlSerializer序列化,需要序列化的类都必须有一个无参的构造函数(通过对基础中类和类的实例学习,我们必须知道类不定义构造函数的情况下,会默认生成一个无参数的构造函数);

(2)索引器、私有字段或只读属性(只读集合属性除外)不能被序列化;

(3)不想序列化时:当不想序列化一个属性时,使用[System.Xml.Serialization.XmlIgnore]标记,能用于属性;[NonSerializable]应用于属性无效,能用于类,结构体等;

(4)方法不能被序列化(虽然是废话,但是还是列举出来);

(5)枚举变量可序列化为字符串,无需用[XmlInclude]

(6)导出非基本类型对象,都必须用[XmlInclude]事先声明。该规则递归作用到子元素

(7)Attribute中的IsNullable参数若等于false,表示若元素为null则不显示该元素。(针对值类型有效)

(8)某些类就是无法XML序列化的(即使使用了[XmlInclude])

比如:

IDictionary(如HashTable);

父类对象赋予子类对象值的情况;

对象间循环引用;

(9)对于无法XML序列化的对象,可考虑:

使用自定义xml序列化(实现IXmlSerializable接口);

实现IDictionary的类,可考虑(1)用其它集合类替代;(2)用类封装之,并提供Add和this函数;

某些类型需要先经过转换,然后才能序列化为 XML。如XML序列化System.Drawing.Color,可先用ToArgb()将其转换为整数;

过于复杂的对象用xml序列化不便的话,可考虑用二进制序列化;

(10)默认构造函数是必须的,因为反序列化本质上使用的是反射,需要默认构造函数来实例化类,如果去掉其中的默认构造函数,则编译没有问题,但运行就会报错。

尽量不要将比较大的属性放在默认构造函数初始化,那会导致在反序列化时对列表初始化两次:默认构造函数中执行一次,反序列化时从XML文档读取再执行一次。

以上十点注意,其中前三点,也就是加黑的这几点,是重点要知道的。

5. 改变XML序列化的默认值

5.1 更改或删除XML默认命名空间

使用 XmlSerializerNamespaces类(System.Xml.Serialization.XmlSerializerNamespaces)。来完成

我们对上面最重得到的对象List<MyArticle>进行XML序列化,并更改XML默认的命名空间,示例如下:

//更新默认命名空间 //使用XmlSerializerNamespaces类来完成(System.Xml.Serialization.XmlSerializerNamespaces) System.Xml.Serialization.XmlSerializerNamespaces XmlSN = new XmlSerializerNamespaces();      //获取文章列表对象 List<MyArticle> newArticleList = MyBlogs.GetMyArticle(10); //更改命名空间,并输出 string newXmlString = String.Empty; XmlSN.Add("MyBlogURL", @"http://www.cnblogs.com/yubinfeng"); using (MemoryStream ms = new MemoryStream()) {  XmlSerializer xml = new XmlSerializer(typeof(List<MyArticle>));  xml.Serialize(ms, newArticleList,XmlSN);  byte[] arr = ms.ToArray();  newXmlString = Encoding.UTF8.GetString(arr, 0, arr.Length);  ms.Close(); } Console.WriteLine(newXmlString); 

我们可以和前面默认的输出结果比较,如下图:

[.net 面向对象程序设计进阶] (10) 序列化(Serialization)(二) 通过序列化博客园文章学习XML的序列化

也是可以删除命名空间的

System.Xml.Serialization.XmlSerializerNamespaces XmlSN = new XmlSerializerNamespaces();     XmlSN.Add("","");

当加入一个空的命名空间时,就可以删除默认的XML命名空间。

5.2  更改XML序列化的其他元素

我们先列出XmlWriterSettings可以更改的属性。

XmlWriterSettings 更多设置属性如下:

成员

说明

CloseOutput

获取或设置一个值,该值指示在调用  Close  方法时, XmlWriter  是否还应该关闭基础流或  TextWriter 。

Encoding

获取或设置要使用的文本编码的类型。

Indent

获取或设置一个值,该值指示是否缩进元素。

IndentChars

获取或设置缩进时要使用的字符串。

NamespaceHandling

获取或设置一个值,该值指示在编写  XML  内容时, XmlWriter  是否应移除重复的命名空间声明。 的默认是输出程序中出现的所有命名空间声明。

NewLineChars

获取或设置要用于分行符的字符串

NewLineHandling

获取或设置一个值,该值指示是否将输出中的分行符正常化。

NewLineOnAttributes

获取或设置一个值,该值指示是否将属性写入新行。

OmitXmlDeclaration

获取或设置一个值指示省略  XML  声明。

Encoding

获取或设置要使用的文本编码的类型。

Reset 方法

重置以上属性

API 官方地址: http://msdn.microsoft.com/zh-cn/library/system.xml.xmlwritersettings(v=vs.110).aspx

下面我们通过示例。来设置三个属性:去掉XML 声明,换行缩进,指定字符缩进,示例如下:

先定义一个方法

/// <summary> /// 设置三个属性:去掉XML声明,指定字符缩进 /// </summary> /// <param name="Obj"></param> /// <returns></returns> public static string ObjectToXmlSerializer(Object Obj) {     System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings();     settings.OmitXmlDeclaration = true;//去除xml声明     settings.Encoding = Encoding.Default;//使用默认编码     settings.IndentChars = "--"; //使用指定字符缩进     settings.Indent = true; //换行缩进     System.IO.MemoryStream mem = new MemoryStream();     using (System.Xml.XmlWriter writer = System.Xml.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()); } 

调用如下:

//使用 设置 XmlWriterSettings 类的属性,来更改序列化的XML其他元素 //所在命名空间:System.Xml.XmlWriterSettings //设置三个属性:去掉XML声明,指定字符缩进 Console.WriteLine(ObjectToXmlSerializer(myArticleList));

输出结果和之前进行对比,如下图:

[.net 面向对象程序设计进阶] (10) 序列化(Serialization)(二) 通过序列化博客园文章学习XML的序列化

6. 本节要点:

(1)了解 XML 的序列化,将对象转为 XML 数据格式

(2)了解 XML 的反序列化,将 XML 文本转换为对象

(3)了解 XML 序更化的注意事项 , 主要有以下几点:

  • 默认类和无参数构造函数类才可以序列化;
  • 索引器、私有字段或只读属性 ( 只读集合属性除外 ) 不能被序列化
  • 有一些序列化的标记当不想序列化一个属性时,使用 [System.Xml.Serialization.XmlIgnore] 标记,能用于属性 ;
  • [NonSerializable] 应用于属性无效,能用于类,结构体等。

(4)改变XML序列化的默认值:

使用 XmlSerializerNamespaces类(System.Xml.Serialization.XmlSerializerNamespaces),更改或删除XML的命名空间;

使用 XmlWriterSettings类(System.Xml.XmlWriterSettings)的属性,来更改 XML 的明名、缩进等元素。  

下节我们将对通过实现序列化接口 IXmlSerializable 来介绍 XML 序列化以及介绍 XML 的其他特性,并举例说明 XML 序列化的高级应用。

正文到此结束
Loading...