[.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);
執行結果如下:
上面的示例,實現了一個最基本的從物件到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(); }
執行結果如下:
上面的示例實現了從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);
我們可以和前面預設的輸出結果比較,如下圖:
也是可以刪除名稱空間的
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));
輸出結果和之前進行對比,如下圖:
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操作的通用類。
==============================================================================================
<如果對你有幫助,記得點一下推薦哦,如有有不明白或錯誤之處,請多交流>
<對本系列文章閱讀有困難的朋友,請先看《.net 物件導向程式設計基礎》>
<轉載宣告:技術需要共享精神,歡迎轉載本部落格中的文章,但請註明版權及URL>
==============================================================================================