Collection主要是指像Array, ArrayList, List, Dictionary, HashTable這 些數據類型,大家平時用的很多。如果一個類中有一個Collection類型的成員, 在對這個類進行XML序列化的時候,應該如何處理?應該說在.net當中這是比較 簡單的,只要建立一個XmlSerializer類就可以幫你自動搞定,不過有的時候你 可能需要對自動的序列化過程施加更多的控制,比如XML的結構是實現固定的, 你必須按照要求去生成XML結構。
使用不同的屬性可以靈活的控制生成的XML,這裡我就不多介紹了,主要講一 下如何序列化比較復雜的Collection結構。下面的方法,對於所有實現了 IEnumerable接口的Collection都有效。
我使用MSDN中的例子,不過沒有使用數組或者ArrayList,而是使用了比較高 級的數據類型List<T>,希望在講解如何序列化XML的同時給使用 List<T>的同學提供點參考。
序列化一個List<T>
下面的代碼示范了如何序列化一個List<T>,實際上和序列化其它類一 樣,把這個類扔給Serialize()函數即可。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.IO;
namespace SerializeCollection
{
class Program
{
static void Main(string[] args)
{
Program test = new Program();
test.SerializeDocument ("e:\\books.xml");
}
public void SerializeDocument(string filename)
{
// Creates a new XmlSerializer.
XmlSerializer s =
new XmlSerializer(typeof (MyRootClass));
// Writing the file requires a StreamWriter.
TextWriter myWriter = new StreamWriter (filename);
// Creates an instance of the class to serialize.
MyRootClass myRootClass = new MyRootClass();
//create items
Item item1 = new Item();
// Sets the objects' properties.
item1.ItemName = "Widget1";
item1.ItemCode = "w1";
item1.ItemPrice = 231;
item1.ItemQuantity = 3;
Item item2 = new Item();
// Sets the objects' properties.
item2.ItemName = "Widget2";
item2.ItemCode = "w2";
item2.ItemPrice = 800;
item2.ItemQuantity = 2;
// Sets the class's Items property to the list.
myRootClass.Items.Add(item1);
myRootClass.Items.Add(item2);
/* Serializes the class, writes it to disk, and closes
the TextWriter. */
s.Serialize(myWriter, myRootClass);
myWriter.Close();
}
}
// This is the class that will be serialized.
[Serializable]
public class MyRootClass
{
public MyRootClass()
{
items = new List<Item>();
}
private List<Item> items;
public List<Item> Items
{
get { return items; }
set { items = value; }
}
}
public class Item
{
[XmlElement(ElementName = "OrderItem")]
public string ItemName;
public string ItemCode;
public decimal ItemPrice;
public int ItemQuantity;
}
}
最後序列化成的XML:
<?xml version="1.0" encoding="utf-8"?>
<MyRootClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Items>
<Item>
<OrderItem>Widget1</OrderItem>
<ItemCode>w1</ItemCode>
<ItemPrice>231</ItemPrice>
<ItemQuantity>3</ItemQuantity>
</Item>
<Item>
<OrderItem>Widget2</OrderItem>
<ItemCode>w2</ItemCode>
<ItemPrice>800</ItemPrice>
<ItemQuantity>2</ItemQuantity>
</Item>
</Items>
</MyRootClass>
如果這個List<T>中的成員的類還有繼承關系
現在把情況變得復雜一點,因為多態,List<T>中的類可能是指定類型 的子類型,這個時候會出現什麼情況呢?
我們增加一個BookItem類,繼承自Item 類。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.IO;
namespace SerializeCollection
{
class Program
{
static void Main(string[] args)
{
Program test = new Program();
test.SerializeDocument ("e:\\books.xml");
}
public void SerializeDocument(string filename)
{
// Creates a new XmlSerializer.
XmlSerializer s =
new XmlSerializer(typeof (MyRootClass));
// Writing the file requires a StreamWriter.
TextWriter myWriter = new StreamWriter (filename);
// Creates an instance of the class to serialize.
MyRootClass myRootClass = new MyRootClass();
/* Uses a more advanced method of creating an list:
create instances of the Item and BookItem, where BookItem
is derived from Item. */
Item item1 = new Item();
// Sets the objects' properties.
item1.ItemName = "Widget1";
item1.ItemCode = "w1";
item1.ItemPrice = 231;
item1.ItemQuantity = 3;
BookItem bookItem = new BookItem();
// Sets the objects' properties.
bookItem.ItemCode = "w2";
bookItem.ItemPrice = 123;
bookItem.ItemQuantity = 7;
bookItem.ISBN = "34982333";
bookItem.Title = "Book of Widgets";
bookItem.Author = "John Smith";
// Sets the class's Items property to the list.
myRootClass.Items.Add(item1);
myRootClass.Items.Add(bookItem);
/* Serializes the class, writes it to disk, and closes
the TextWriter. */
s.Serialize(myWriter, myRootClass);
myWriter.Close();
}
}
// This is the class that will be serialized.
[Serializable]
public class MyRootClass
{
public MyRootClass()
{
items = new List<Item>();
}
private List<Item> items;
public List<Item> Items
{
get { return items; }
set { items = value; }
}
}
public class Item
{
[XmlElement(ElementName = "OrderItem")]
public string ItemName;
public string ItemCode;
public decimal ItemPrice;
public int ItemQuantity;
}
public class BookItem : Item
{
public string Title;
public string Author;
public string ISBN;
}
}
修改代碼後,我們再運行,出現如下錯誤“不應是類型 SerializeCollection.BookItem。使用 XmlInclude 或 SoapInclude 屬性靜態 指定非已知的類型”,看來是系統在做序列化的時候,搞不清楚List中的成員到 底是什麼類型。這個時候就要使用XmlArrayItem來幫忙了。MyRootClass類的 Item成員前加入XmlArrayItem標志。
[XmlArrayItem(ElementName= "Item",
IsNullable=true,
Type = typeof(Item),
Namespace = "http://www.aboutdnn.com"),
XmlArrayItem(ElementName = "BookItem",
IsNullable = true,
Type = typeof(BookItem),
Namespace = http://www.aboutdnn.com)]
修改後的代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.IO;
namespace SerializeCollection
{
class Program
{
static void Main(string[] args)
{
Program test = new Program();
test.SerializeDocument ("e:\\books.xml");
}
public void SerializeDocument(string filename)
{
// Creates a new XmlSerializer.
XmlSerializer s =
new XmlSerializer(typeof (MyRootClass));
// Writing the file requires a StreamWriter.
TextWriter myWriter = new StreamWriter (filename);
// Creates an instance of the class to serialize.
MyRootClass myRootClass = new MyRootClass();
/* Uses a more advanced method of creating an list:
create instances of the Item and BookItem, where BookItem
is derived from Item. */
Item item1 = new Item();
// Sets the objects' properties.
item1.ItemName = "Widget1";
item1.ItemCode = "w1";
item1.ItemPrice = 231;
item1.ItemQuantity = 3;
BookItem bookItem = new BookItem();
// Sets the objects' properties.
bookItem.ItemCode = "w2";
bookItem.ItemPrice = 123;
bookItem.ItemQuantity = 7;
bookItem.ISBN = "34982333";
bookItem.Title = "Book of Widgets";
bookItem.Author = "John Smith";
// Sets the class's Items property to the list.
myRootClass.Items.Add(item1);
myRootClass.Items.Add(bookItem);
/* Serializes the class, writes it to disk, and closes
the TextWriter. */
s.Serialize(myWriter, myRootClass);
myWriter.Close();
}
}
// This is the class that will be serialized.
[Serializable]
public class MyRootClass
{
public MyRootClass()
{
items = new List<Item>();
}
private List<Item> items;
[XmlArrayItem(ElementName = "Item",
IsNullable = true,
Type = typeof(Item),
Namespace = "http://www.aboutdnn.com"),
XmlArrayItem(ElementName = "BookItem",
IsNullable = true,
Type = typeof(BookItem),
Namespace = "http://www.aboutdnn.com")]
public List<Item> Items
{
get { return items; }
set { items = value; }
}
}
public class Item
{
[XmlElement(ElementName = "OrderItem")]
public string ItemName;
public string ItemCode;
public decimal ItemPrice;
public int ItemQuantity;
}
public class BookItem : Item
{
public string Title;
public string Author;
public string ISBN;
}
}
序列化後的XML如下:
<?xml version="1.0" encoding="utf-8"?>
<MyRootClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Items>
<Item xmlns="http://www.aboutdnn.com">
<OrderItem>Widget1</OrderItem>
<ItemCode>w1</ItemCode>
<ItemPrice>231</ItemPrice>
<ItemQuantity>3</ItemQuantity>
</Item>
<BookItem xmlns="http://www.aboutdnn.com">
<ItemCode>w2</ItemCode>
<ItemPrice>123</ItemPrice>
<ItemQuantity>7</ItemQuantity>
<Title>Book of Widgets</Title>
<Author>John Smith</Author>
<ISBN>34982333</ISBN>
</BookItem>
</Items>
</MyRootClass>
可以看到,已經根據不同的數據類型,序列化為不同名字的節點。這個時候 ,如果你還想修改XML中<Items>節點的名字或者添加屬性, XmlArrayAttribute可以幫你的忙,這個你可以自己試試。