程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WCF系列(四) 也談序列化(上)

WCF系列(四) 也談序列化(上)

編輯:關於.NET

一、概述........................................................................................2

二、為remoting提供的BinaryFormatter和SoapFormatter.............2

1、BinaryFormatter和SoapFormatter兩個主要特點......................2

1.1.序列化數據中包含類型信息.....................................................2

1.2.具有類型保真(type fidelity)的特性...........................................2

2、SoapFormatter.......................................................................2

2.1.准備需要序列化的類...............................................................3

2.2.准備需要序列化的對象和流....................................................3

2.3.將准備好的對象序列化到准備好的流對象中............................4

2.4.查看序列化的結果..................................................................5

2.5.將流對象中數據反序列化為對象..............................................5

3、BinaryFormatter......................................................................6

3.1.將准備好的對象序列化到准備好的流對象中............................6

3.2.查看序列化的結果...................................................................6

3.3.將流對象中數據反序列化為對象..............................................7

三、XmlSerializer..........................................................................7

1、使用自定義.net類型的序列化...................................................8

1.1.定義需要用XmlSerializer序列化的.net類型..............................8

1.1.1.XmlRootAttribute................................................................8

1.1.2.XmlAttribute.......................................................................8

1.1.3.XmlElementAttribute..........................................................8

1.2.准備需要序列化的對象和流...................................................10

1.3.將准備好的對象序列化到准備好的流對象中..........................10

1.4.查看序列化的結果.................................................................10

1.5.將流對象中數據反序列化為對象..........................................11

1.6.測試在web services中序列化對象是否跟XmlSerializer一致......11

2、使用工具把現有xml架構轉換成.net類........................................12

2.1.准備xsd架構文件......................................................................13

2.2.根據xsd生成.net類....................................................................14

2.3.序列化xsd生成的.net類............................................................15

一、概述

為什麼要序列化一個對象,大概出於兩個目的。

第一保存對象以便以後再處理,這是出於對象持久化(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]屬性。

/// <summary>
 /// 需要被序列化的類
 /// </summary>
 [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對象,或者是文件流,或者是內存流等等。

所以這一步將要准備需要被序列化的對象和序列化後的目標,一個內存流。

/// <summary>
/// 聲明一個流對象,用來保存序列化後的對象
/// </summary>
private static MemoryStream myMemoryStream;
/// <summary>
/// 需要序列化的對象
/// </summary>
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當前位置復位到起始位置。

/// <summary>
/// 將准備好的對象序列化到准備好的流對象中
/// </summary>
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方法

/// <summary>
/// 將Serialize方法序列化到流中的數據反序列化為對象
/// </summary>
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編碼,而且好像無法改變這個編碼。

/// <summary>
/// 將准備好的對象序列化到准備好的流對象中
/// </summary>
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一樣進行反序列化。

/// <summary>
/// 將Serialize方法序列化到流中的數據反序列化為對象
/// </summary>
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後如何轉換這個字符的。

/// <summary>
 /// 聲明一個流對象,用來保存序列化後的對象
 /// </summary>
 private static MemoryStream myMemoryStream;
 /// <summary>
 /// 需要序列化的對象
 /// </summary>
 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結果是一樣的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved