一、 概述
為什麼要序列化一個對象,大概出于兩個目的。
第一儲存對象以便以後再處理,這是出于對象持久化(persist)的要求。這種情況一般需要把對象儲存到可以長久儲存的媒體上,比如磁盤。儲存在磁盤上的資料是一系列連續的位元組組成的,是以就需要把對象轉換成一個連續的位元組串以便把對象寫入到磁盤。把一個對象當時的完整狀态轉換成連續的位元組串的過程就是對象的序列化(serialize)過程。反過來把表示一個對象的連續的位元組串複原成原來的那個對象的過程就是反序列化(deserialize)過程。
第二,自從有了分布式處理技術後,就出現了需要從一個應用傳送一個對象到另一個應用的需求。不同的應用大多數情況是不在同一個機器上的,對象需要在網絡上進行傳輸。跟寫入到磁盤類似,網絡傳輸資料也可以看做是傳輸一個連續的位元組串。這種需求同樣需要把對象先序列化成連續的位元組串,經過網絡傳輸到,到達目标應用,再經過反序列化恢複為對象。
Dotnet framework中針對不同的應用場景提供了幾類不同的序列化器,主要有三大類,分别是針對不同的技術提供的。
下面分别介紹三大類一個5個序列化器,每個序列化器都是用一個簡單的示例說明把一個對象序列化到一個流,然後再從流反序列化為這個對象。
完整的代碼(解決方案中包含了本文的所有示例項目)下載下傳位址:DotnetSerialize.rar
二、 為remoting提供的BinaryFormatter和SoapFormatter
這兩個序列化器都是由System.Runtime.Remoting.Messaging. IRemotingFormatter接口派生。
這兩個序列化器是為remoting準備的,remoting是微軟在dotnet中提供的應用程式間遠端通路的技術,用以替代com+的技術,在通訊通道方面,remoting既支援tcp,也支援http協定,這樣就解決防火牆的限制問題。
Remoting技術考慮進行遠端通路的雙方都是基于dotnet技術的應用,沒有太多的考慮使用更通用的業界标準,是以這兩個序列化器帶有強烈的dotnet的自身特點。
1、 BinaryFormatter和SoapFormatter兩個主要特點
1.1. 序列化資料中包含類型資訊
對象序列化後的資料中包含類型資訊:類的全限定名、版本、區域、KeyToken,是以反序列化時必須制定同一類型,即類的全限定名、版本、區域、KeyToken必須一緻,否則會被認為不是同一類型的對象。
1.2. 具有類型保真(type fidelity)的特性
所有的field都将被序列化(包括私有字段),但是不包括屬性(屬性隻是通路器,本身不儲存資料),除非field被标記[NonSerialized]屬性。
這樣序列化後的資料,再被反序列化回對象,将嚴格的跟原來的對象一模一樣。
2、 SoapFormatter
SoapFormatter序列化器把對象序列化為SOAP形式的xml字元串序列,xml形式便于通過HTTP協定在網絡上傳輸,是以remoting在使用HTTP協定時就采用SoapFormatter序列化器序列化對象。
SoapFormatter所在名稱空間和所在assembly:
Namespace: System.Runtime.Serialization.Formatters.Soap
Assembly: system.runtime.serialization.formatters.soap.dll
SoapFormatter序列化器序列化的對象必須是被标記為[Serializable]屬性的類。
2.1. 準備需要序列化的類
代碼很簡單,不需要多加說明,有幾點需要強調:
l 類必須被[Serializable]屬性标記,否則SoapFormatter序列化器序列化時會抛出異常
l 預設類的所有field,不管是公有還是私用的field都會被序列化,以保證類型保真性。除非把某個field标記[NonSerialized]屬性。
///
/// 需要被序列化的類
///
[Serializable]
public class book
{
//私有field将被序列化
private string name;
//構造方法将把下面兩個address字段将指向同一個對象
private string address1;
private string address2;
//辨別為[NonSerialized]的私有field将被序列化
[NonSerialized]
private string address_invisible = "shenzhen";
//公有field将被序列化
public string author;
//屬性隻是通路器,不被序列化
public string Name
{
get { return name; }
set { name = value; }
}
public book()
{
string address = "shenzhen";
address1 = address;
address2 = address;
}
}
2.2. 準備需要序列化的對象和流
序列化時針對對象而言的,是把一個對象的當時的狀态完整的轉換成連續的位元組串。
序列化的源是一個[Serializable]屬性類的一個執行個體對象。
序列化的目标是一個Stream對象,或者是檔案流,或者是記憶體流等等。
是以這一步将要準備需要被序列化的對象和序列化後的目标,一個記憶體流。
///
/// 聲明一個流對象,用來儲存序列化後的對象
///
private static MemoryStream myMemoryStream;
///
/// 需要序列化的對象
///
private static book mybook;
#region 準備需要序列化的對象
mybook = new book();
mybook.Name = "我的第一本書";
mybook.author = "chnking";
#endregion
//準備儲存序列化後對象的流
myMemoryStream = new MemoryStream();
2.3. 将準備好的對象序列化到準備好的流對象中
使用SoapFormatter對象的Serialize方法進行序列化:
SoapFormatter.Serialize (Stream, Object)
Object 參數是需要被序列化的對象。
Stream是儲存序列化後資料的流對象。
這裡有幾點需要特别強調的:
l SoapFormatter把對象轉換成xml後,從xml到Stream過程預設采用UTF-8編碼,而且好像無法改變這個編碼。是以,要從Stream轉換成字元串需要使用UTF-8進行解碼。
l Serialize方法把對象序列化到Stream對象後,Stream的目前位置在最後,使用 Stream的Read方式讀取流中資料注時意把Stream目前位置複位到起始位置。
///
/// 将準備好的對象序列化到準備好的流對象中
///
static void Serialize()
{
//準備序列化器SoapFormatter
SoapFormatter formatter = new SoapFormatter();
//序列化mybook對象,序列化到myMemoryStream流對象
formatter.Serialize(myMemoryStream, mybook);
#region 将流中的資料轉換為字元串或xmlDocument
byte[] resultByte = myMemoryStream.GetBuffer();
string resultStr = Encoding.UTF8.GetString(resultByte);
//轉成xmlDocument對象友善在斷點調試時檢視結果
XmlDocument myXmlDocument = new XmlDocument();
myXmlDocument.LoadXml(resultStr);
#endregion
}
2.4. 檢視序列化的結果
前面的代碼把對象序列化後儲存資料的MemoryStream中的資料轉換成字元串,然後讀入到一個XmlDocument中以友善檢視,看一下結果
可以看出以下幾點:
l 包含對象的完整的類型資訊,包括類的類名、名稱空間、版本号、區域、KeyToken,甚至還有所在Assembly的名稱,參看上圖中的辨別。
l 隻有field被序列化,不管是私有的還是公有的,除非這個字段被标記[NonSerialized]屬性,本例中address_invisible字段就被标記為[NonSerialized],序列化後的結果能看到,address_invisible沒有被序列化。
l 對象中幾個字段為同一個對象時,在序列化後,隻有一個副本,其它的字段指向這個副本。本例中address1字段和address2字段被賦給了同一個字元串對象,在序列化後,address1字段保留了一個副本,address2字段通過引用address1的id來引用這個副本。
2.5. 将流對象中資料反序列化為對象
使用SoapFormatter對象的Deserialize方法進行反序列化
反序列化比較簡單,把前面步驟生成的儲存序列化後的對象的流直接使用Deserialize方法
///
/// 将Serialize方法序列化到流中的資料反序列化為對象
///
static void Deserialize()
{
myMemoryStream.Position = 0;
SoapFormatter formatter = new SoapFormatter();
mybook = (book)formatter.Deserialize(myMemoryStream);
}
看一下反序列化後得到的對象的狀态:
除了被标記為[NonSerialized]的address_invisible字段,這個字段沒有被序列化,當然反序列化後的這個字段的值就被丢了,别的字段的狀态都被恢複了。
3、 BinaryFormatter
BinaryFormatter序列化器把對象序列化為二進制格式的資料,這樣的資料格式最精簡、效率最高,但也最不具互動性,适合在區域網路内用TCP協定傳輸,是以remoting在使用TCP協定時就采用BinaryFormatter序列化器序列化對象。
BinaryFormatter在功能上跟SoapFormatter想對應,隻是SoapFormatter把對象序列化為Soap形式,BinaryFormatter把對象序列化二進制形式。還有點不同是,SoapFormatter在序列化對象是可以在對象之外增加一些附加資訊放入到soap的head部分。
BinaryFormatter所在名稱空間和所在assembly:
Namespace: System.Runtime.Serialization.Formatters.Binary
Assembly: mscorlib.dll
同樣BinaryFormatter序列化器序列化的對象必須是被标記為[Serializable]屬性的類。
下面的示例還是處理前面SoapFormatter同樣的例子,隻是把SoapFormatter換成BinaryFormatter看看是什麼樣的結果。
準備需要序列化的類和對象,準備序列化的目标流步驟跟前面SoapFormatter的例一摸一樣,參看前面的例子。
3.1. 将準備好的對象序列化到準備好的流對象中
使用BinaryFormatter對象的Serialize方法進行序列化:
BinaryFormatter.Serialize (Stream, Object)
這裡有幾點需要特别強調的:
BinaryFormatter把對象轉換成二進制的序列資料,其中總不免會有字元存在,比如字元串類型的字段,對字元同樣在序列化過程預設采用UTF-8編碼,而且好像無法改變這個編碼。
///
/// 将準備好的對象序列化到準備好的流對象中
///
static void Serialize()
{
//準備序列化器BinaryFormatter
BinaryFormatter formatter = new BinaryFormatter();
//序列化mybook對象,序列化到myMemoryStream流對象
formatter.Serialize(myMemoryStream, mybook);
#region 将流中的資料轉換為字元串
byte[] resultByte = myMemoryStream.GetBuffer();
string resultStr = Encoding.UTF8.GetString(resultByte);
#endregion
}
3.2. 檢視序列化的結果
序列化的流主要是二進制的資料,不過裡面也會夾雜的字元,是以還是使用UTF-8編碼把流轉成字元串檢視。
結果是這樣的:
/0/0/0/0????/0/0/0/0/0/0/0/f[1]/0/0/0FBinaryFormatter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null/0/0/0&Serialize.BinaryFormatterTest.App+book /0/0/0
name/baddress1/baddress2author [1]/0/0/0 /0/0/0 我的第一本書 /0/0/0/bshenzhen/t /0/0/0/0/0/0/achnking/v/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0
裡面亂碼部分是二進制的資料,沒法看。不過裡面的字元還是可以看出些東西來。
“BinaryFormatter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”,這部分是對象的類型的Assembly、版本、區域、KeyToken資訊。
“Serialize.BinaryFormatterTest”,這是類所在的名稱空間。
“book”,是類型名。
還有其他的field名和他們相關的值,标記為[NonSerialized]的address_invisible字段不會被序列化,是以在這個結果裡也沒有出現。
3.3. 将流對象中資料反序列化為對象
使用BinaryFormatter對象的Deserialize方法進行反序列化。
跟SoapFormatter一樣進行反序列化。
///
/// 将Serialize方法序列化到流中的資料反序列化為對象
///
static void Deserialize()
{
myMemoryStream.Position = 0;
BinaryFormatter formatter = new BinaryFormatter();
mybook = (book)formatter.Deserialize(myMemoryStream);
}
反序列化後得到的對象跟SoapFormatter反序列化的結果一樣。
三、 XmlSerializer
XmlSerializer是ASP.NET Web Services使用的序列化器。
Web Services有一系列的業界标準,不隻是微軟自己的标準, web servces可能跟異構的系統互動,是以,Web Services序列化後的資料隻包括對象包含的公有資料,不會包含dotnet的類型資訊。
XmlSerializer隻轉換公共字段和屬性,不轉換方法、索引、私有字段、隻讀屬性(隻讀集合除外),XmlSerializer生成的xml的格式受類成員的屬性控制,這些屬性可以指定類轉換成xml後的根節點名稱,名稱空間,類成員是作為屬性形式還是作為節點形式出現等等。
序列化後的資料不包含類型和assembly的資訊。
是以XmlSerializer化後得到的xml不是保真的序列化,它隻是把對象的一部分公開的資料序列化了,反序列化得到的對象跟原來的對象可能就有些不同了。
建立需要通過XmlSerializer序列化的.net類的兩種方式:
l 把一般的.net的自定義類型通過添加相應控制xml序列化的屬性來建立序列化的類
l 通過工具把現有xml架構生成帶有相關屬性的.net類,這樣的類的對象序列化後将符合這個架構。當希望序列化後的内容遵從某個已知架構時可以使用這種方式建構類。
XmlSerializer所在名稱空間和所在assembly:
Namespace: System.Xml.Serialization
Assembly: system.xml.dll
1、 使用自定義.net類型的序列化
1.1. 定義需要用XmlSerializer序列化的.net類型
自定義個類,這個類要可以通過XmlSerializer序列化器序列化為xml,并且能夠根據實際需要控制序列化後的xml的格式。
首先,這個類不需要[Serializable]屬性。
其次,用一些Attribute來控制類或類成員如何生成xml。
下面是主要的幾個Attribute的作用:
1.1.1. XmlRootAttribute
這個屬性必須放在類的前面用來限定需要序列化的類。
[XmlRootAttribute("BOOK", Namespace="http://www.chnking.com", IsNullable = false)]
public class book
{
//定義類代碼
}
屬性的第一個參數 ElementName = “BOOK” ,表示序列化後的xml的根元素是BOOK,預設的話,根元素名就是類名。
參數Namespace,表示根元素的名稱空間,這個名稱空間是根元素的預設名稱空間,表現為:xmlns=”http://www.chnking.com” 這樣的形式。
參數IsNullable,值為true時表示如果這個對象執行個體為Null,生成的xml在根元素的用屬性xsi:nil="true"表示。
1.1.2. XmlAttribute
此屬性放在類的公有字段和可讀寫屬性前,表示這個字段或屬性在xml中以element的屬性形式出現。
[XmlAttribute("Author", Namespace = "http://www.chnkingAttr.com",DataType = "NMTOKEN")]
public string author;
屬性的第一個參數AttributeName = "Author",表示這個成員被序列化為Attribute的屬性名。
參數Namespace,表示根元素的名稱空間,這個名稱空間隻是這個屬性名稱空間。
參數DataType,表示這個成員轉換為xml的XML Schema類型。一般的,很多XML Schema類型,比如int 、decimal,在.net framework都有相應的資料類型相對應,但也有很多XML Schema類型類型在.net framework中沒有,就可以通過[XmlAttribute]的DataType參數來訓示轉成xml後的XML Schema資料類型。上面的DataType = "NMTOKEN",表示要把.net framework中的string類型轉換到XML Schema中的NMTOKEN資料類型。根據W3C XML Schema 中資料類型的定義,NMTOKEN類型中隻能包含數字、字母、下劃線、冒号,如果不在此範圍内的字元都以十六進制的ASCII碼表示。比如,如果字元串“^chnking”中包含了NMTOKEN類型不允許出現的^字元,是以這個字元串轉成xml後會變成這樣:"_x005E_chnking",x005E是字元^的ASCII碼。
1.1.3. XmlElementAttribute
此屬性放在類的公有字段和可讀寫屬性前,表示這個字段或屬性在xml中以element形式出現。這是XmlSerializer序列化器的預設行為,如果這個公有字段或可讀寫屬性前沒有相關Attribute限制,那這個公有字段或可讀寫屬性在序列化後的xml中就以element形式出現。
但是[XmlElementAttribute]還是可以為控制序列化的xml提供更多的控制。
[XmlElementAttribute(ElementName = "NamePro", Namespace = "http://www.chnkingName.com", DataType = "NMTOKEN",IsNullable = true)]
public string Name
{
get { return name; }
set { name = value; }
}
屬性的第一個參數ElementName = "NamePro",表示這個成員被序列化後element的名稱。
第二和第三個參數Namespace和DataType跟上面[XmlAttribute]含義一樣。
第四個參數IsNullable = true,這個屬性描述相關公有字段或可讀寫屬性的值為null時生成xml的行為。
如果這個屬性的值為true,相應的element依然會在序列化後的xml中出現,隻是沒有值,在element中會有一個xsi:nil="true"屬性,表示此元素為null值,比如:
<NamePro xsi:nil="
true" xmlns="
http://www.chnkingName.com" />
如果這個屬性的值為false,相應的element将不會在序列化後的xml中出現。
下面是準備需要序列化的類,跟前面兩個BinaryFormatter和SoapFormatter中的例子基本上一樣。隻是改成了适合XmlSerializer的樣子:
[XmlRootAttribute(ElementName = "BOOK", Namespace = "http://www.chnking.com", IsNullable = true)]
public class book
{
//私有field将不被序列化
private string name;
//構造方法将把下面兩個address字段将指向同一個對象
public string address1;
public string address2;
//[XmlAttribute]屬性将訓示把類的成員序列化為一個element的屬性
[XmlAttribute(AttributeName = "Author", Namespace = "http://www.chnkingAttr.com", DataType = "NMTOKEN")]
public string author;
[XmlElementAttribute(ElementName = "NamePro", Namespace = "http://www.chnkingName.com", DataType = "NMTOKEN", IsNullable = true)]
public string Name
{
get { return name; }
set { name = value; }
}
public book()
{
string address = "shenzhen";
address1 = address;
address2 = address;
}
}
1.2. 準備需要序列化的對象和流
這部分跟BinaryFormatter和SoapFormatter中的例子一樣。
不過這裡mybook.author屬性的值為"^chnking",裡面的^符号是author屬性被限定為xml的NMTOKEN類型不允許的字元,注意在轉換為xml後如何轉換這個字元的。
///
/// 聲明一個流對象,用來儲存序列化後的對象
///
private static MemoryStream myMemoryStream;
///
/// 需要序列化的對象
///
private static book mybook;
mybook = new book();
mybook.Name = "我的第一本書";
mybook.author = "^chnking";
//準備儲存序列化後對象的流
myMemoryStream = new MemoryStream();
1.3. 将準備好的對象序列化到準備好的流對象中
跟BinaryFormatter和SoapFormatter不一樣,這兩個序列化器都有預設構造函數,XmlSerializer構造函數必須要提供序列化對象的類型參數。
同樣也是使用Serialize方法把需要序列化的對象序列化到一個流中。
跟SoapFormatter類似,XmlSerializer把對象轉換成xml後,從xml到Stream過程預設采用UTF-8編碼,而且好像無法改變這個編碼。是以,要從Stream轉換成字元串需要使用UTF-8進行解碼。
static void Serialize()
{
//準備序列化器XmlSerializer
XmlSerializer formatter = new XmlSerializer(typeof(book));
//序列化mybook對象,序列化到myMemoryStream流對象
formatter.Serialize(myMemoryStream, mybook);
#region 将流中的資料轉換為字元串或xmlDocument
byte[] resultByte = myMemoryStream.GetBuffer();
string resultStr = Encoding.UTF8.GetString(resultByte);
//轉成xmlDocument對象友善在斷點調試時檢視結果
XmlDocument myXmlDocument = new XmlDocument();
myXmlDocument.LoadXml(resultStr);
#endregion
}
1.4. 檢視序列化的結果
前面的代碼把對象序列化後儲存資料的MemoryStream中的資料轉換成字元串,然後讀入到一個XmlDocument中以友善檢視,看一下結果:
這個結果裡面有幾點需要注意:
l 類中Author共有字段辨別了XmlAttribute屬性,,是以它在xml中表現為根元素的一個屬性,同時它的值為"^chnking",是NMTOKEN類型,是以字元^被轉換成^字元十六進制的ACSII碼X005E。
l 公有字段address1和address2是指向同一個對象,跟在BinaryFormatter中address2使用id引用到address1不同,這裡這兩個字段都被賦給了同一個值。這是因為BinaryFormatter是基于對象的,在序列化成xml依然要展現對象的特性,要反映出序列化前的對象引用關系,而XmlSerializer是面向資料的,它隻關心最後形成的資料,是以它不必一定要保留對象直接的引用關系,直接都給他們賦予同一個值。
1.5. 将流對象中資料反序列化為對象
使用XmlSerializer對象的Deserialize方法進行反序列化。
static void Deserialize()
{
myMemoryStream.Position = 0;
XmlSerializer formatter = new XmlSerializer(typeof(book));
mybook = (book)formatter.Deserialize(myMemoryStream);
}
檢視反序列化後的對象:
1.6. 測試在web services中序列化對象是否跟XmlSerializer一緻
前面講過,XmlSerializer是dotnet中用于web services序列化對象的序列化器,是以這裡就來測試一下在web services中使用前面的那個示例中我們自己用XmlSerializer序列化的對象,看看得到的序列化的結果是不是完全一樣。
在解決方案中建立一個web services的項目,引用前面XmlSerializer的項目,為了使用項目中定義的需要序列化的那個book類。
Web services的代碼很簡單:
[WebService(Namespace = "http://chnking.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class BookService : System.Web.Services.WebService
{
[WebMethod]
public book GetBook()
{
book mybook = new book();
mybook.Name = "我的第一本書";
mybook.author = "^chnking";
return mybook;
}
}
在浏覽器中直接浏覽這個web services,測試GetBook方法,得到的結果是:
跟前面XmlSerializer例子得到的序列化的結果比較一下,一模一樣。
2、 使用工具把現有xml架構轉換成.net類
在XmlSerializer這一節的開頭我們談到過,有兩種方法建立需要序列化的類。
上面的例子是第一種方式:通過自己寫代碼定義.net類,然後通過給類成員加上各種Attribute來控制序列化後的xml形式。
還有一種方式是根據給定的xsd 架構檔案生成一個.net類,然後這個類序列化後的xml是符合xsd的架構的。
這種方式适合于,在交換資料的雙方事先約定了一個交換資料的格式,即先定義了一個schema,雙方交換的資料都必須遵從這個schema的情況。
2.1. 準備xsd架構檔案
還是使用上面的自定義.net的例子資料,根據上面例子序列化後的xml,建立這個xml對應的schema,既前面的xml資料遵從這個schema。
由于xml中Author屬性有自己的名稱空間,NamePro元素也有自己的名稱空間,是以這兩個成員需要在單獨的schema中定義,是以這個xml一共需要三個schema來定義:
主xsd的内容,檔案名test2.xsd,這裡面會import Author屬性和NamePro元素對應的兩個xsd檔案,同時把根元素BOOK改成BOOKxsd,生成BOOKxsd的.net類型,跟上個例子的book類型相差別:
xml version="1.0" encoding="utf-16"?>
<xsd:schema xmlns:d1p1="http://www.chnkingAttr.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://www.chnking.com">
<xs:import schemaLocation="./test.xsd" namespace="http://www.chnkingAttr.com" />
<xs:import schemaLocation="./test1.xsd" namespace="http://www.chnkingName.com" />
<xs:element name="BOOKxsd">
<xs:complexType>
<xs:sequence>
<xs:element name="address1" type="xs:string" />
<xs:element name="address2" type="xs:string" />
<xs:element xmlns:q1="http://www.chnkingName.com" ref="q1:NamePro" />
xs:sequence>
<xs:attribute ref="d1p1:Author" use="required" />
xs:complexType>
xs:element>
xsd:schema>
Author屬性的schema,檔案名test1.xsd:
xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns:tns="http://www.chnkingName.com" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://www.chnkingName.com" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="NamePro" type="xs:string" />
xs:schema>
NamePro元素schema,檔案名test.xsd:
xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns:tns="http://www.chnkingAttr.com" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://www.chnkingAttr.com" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:attribute name="Author" type="xs:string" />
xs:schema>
好了,schema檔案都準備好了,使用工具驗證一下這些schema生成的一個xml的執行個體:
<ns0:BOOK ns1:Author="d1p1:Author_0" xmlns:ns1="http://www.chnkingAttr.com" xmlns:ns0="http://www.chnking.com">
<ns0:address1>address1_0 ns0:address1>
<ns0:address2>address2_0 ns0:address2>
<ns2:NamePro xmlns:ns2="http://www.chnkingName.com">NamePro_0 ns2:NamePro>
ns0:BOOK>
跟前面示例的xml的模樣是一緻的,說明這幾個schema建立的沒有問題。
2.2. 根據xsd生成.net類
微軟提供了一個工具xsd.exe,它可以根據xsd架構檔案,生成相應的.net類,而這個.net類使用XmlSerializer序列化後的xml又能遵從這個xsd架構。
使用下面的指令行生成.net類:
xsd test2.xsd test1.xsd test.xsd /c
指令會産生一個cs檔案,裡面包含了生成的.net類,這個類如下:
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.chnking.com")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://www.chnking.com", IsNullable=false)]
public partial class BOOKxsd {
private string address1Field;
private string address2Field;
private string nameProField;
private string authorField;
public string address1 {
get {
return this.address1Field;
}
set {
this.address1Field = value;
}
}
public string address2 {
get {
return this.address2Field;
}
set {
this.address2Field = value;
}
}
[System.Xml.Serialization.XmlElementAttribute(Namespace="http://www.chnkingName.com")]
public string NamePro {
get {
return this.nameProField;
}
set {
this.nameProField = value;
}
}
[System.Xml.Serialization.XmlAttributeAttribute(Form=System.Xml.Schema.XmlSchemaForm.Qualified, Namespace="http://www.chnkingAttr.com")]
public string Author {
get {
return this.authorField;
}
set {
this.authorField = value;
}
}
}
2.3. 序列化xsd生成的.net類
将xsd生成的.net類,放到前面例子裡替代book類,然後序列化,看序列化後的結果:
可以跟前面使用自定義 .net類序列化後的xml對比一下,他們序列化後的xml結果是一樣的。