代码改变世界

XML序列化

2010-09-28 16:53  czyhsl  阅读(661)  评论(1编辑  收藏  举报

序列化是将对象转化成易于传输的形式的过程。例如:可以序列化对象,并使用HTTP通过Internet在客户端和服务器之间进行传输。另一方面,反序列化在流中重新构造对象。

XML序列化只将对象的公共字段和属性值序列化为XML流。它不能转换方法、索引器、私有字段或只读属性(只读集合除外)。若要序列化对象的所有公共和私有字段和属性,需要使用DataContractSerializer而不要使用XML序列化。

代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Runtime.Serialization;
using System.Xml;
using System.IO;

namespace DataContractSerializerDemo
{
[DataContract(Name
= "Customer", Namespace = "http://www.contoso.com")]
class Person
{
[DataMember()]
public string FirstName;
[DataMember]
public string LastName;
[DataMember()]
public int ID;

public Person(string newfName, string newlName, int newID)
{
FirstName
= newfName;
LastName
= newlName;
ID
= newID;
}

private ExtensionDataObject extensionData_Value;
public ExtensionDataObject ExtensionData
{
get
{
return extensionData_Value;
}
set
{
extensionData_Value
= value;
}
}
}

class Test
{
private Test() { }

static void Main(string[] args)
{
try
{
WriteObject(
"DataContractSerializerDemo.xml");
ReadOjbect(
"DataContractSerializerDemo.xml");
}
catch (SerializationException serExc)
{
Console.WriteLine(
"Serialization Failed");
Console.WriteLine(serExc.Message);
}
catch(Exception exc)
{
Console.WriteLine(
"The serialization operation failed: {0} StackTrace: {1}",
exc.Message, exc.StackTrace);
}
finally
{
Console.WriteLine(
"Press <Enter> to exit....");
Console.ReadLine();
}
}

public static void WriteObject(string fileName)
{
Console.WriteLine(
"Creating a Person object and serializing it.");
Person p1
= new Person("Zighetti", "Barbara", 101);
FileStream write
= new FileStream(fileName, FileMode.Create);
DataContractSerializer ser
= new DataContractSerializer(typeof(Person));
ser.WriteObject(write, p1);
write.Close();
}

public static void ReadOjbect(string fileName)
{
Console.WriteLine(
"Deserializing an instance of the object.");
FileStream fs
= new FileStream(fileName, FileMode.Open);
XmlDictionaryReader reader
=
XmlDictionaryReader.CreateTextReader(fs,
new XmlDictionaryReaderQuotas());
DataContractSerializer ser
= new DataContractSerializer(typeof(Person));
Person deserializedPerson
= (Person)ser.ReadObject(reader, true);
reader.Close();
fs.Close();
Console.WriteLine(String.Format(
"{0} {1}, ID: {2}",
deserializedPerson.FirstName, deserializedPerson.LastName,
deserializedPerson.ID));
}
}
}

这是DataContractSerializer的一个Demo,必须要在Person类上指定或实现一个数据协定,当用于类成员时,指定该成员是数据协定的一部分。


 

谈到XML序列化,就不得不提XmlSerializer类,它的主要用途就是将对象序列化到文档中和从XML文档中反序列化对象。XML可序列化的项包含以下:

1)公共类的读/写属性和字段

2)实现ICollection或IEnumerable的类

3)XmlElement对象

4)XmlNode对象

5)DataSet对象


 

序列化数据集

代码
using System.Text;
using System.Xml;
using System.IO;
using System.Xml.Serialization;
using System.Data;

namespace XmlSerializerDemo
{
class Test
{
static void Main(string[] args)
{
SerializeDataSet(
@"D:\Dataset.xml");
}

private static void SerializeDataSet(string filename)
{
XmlSerializer ser
= new XmlSerializer(typeof(DataSet));

DataSet ds
= new DataSet("myDataSet");
DataTable t
= new DataTable("table1");
DataColumn c
= new DataColumn("thing");
t.Columns.Add(c);
ds.Tables.Add(t);
DataRow r;
for (int i = 0; i < 10; i++)
{
r
= t.NewRow();
r[
0] = "Thing " + i;
t.Rows.Add(r);
}
TextWriter writer
= new StreamWriter(filename);
ser.Serialize(writer, ds);
writer.Close();
}
}
}
 


 

序列化XmlElement和XmlNode

代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml.Serialization;

namespace XmlSerializerDemo
{
class Test
{
static void Main(string[] args)
{
SerializeElement(
@"D:\Dataset.xml");
}

private static void SerializeElement(string filename)
{
XmlSerializer ser
= new XmlSerializer(typeof(XmlElement));
XmlElement myElement
=
new XmlDocument().CreateElement("MyElement", "ns");
myElement.InnerText
= "Hello World";
TextWriter writer
= new StreamWriter(filename);
ser.Serialize(writer, myElement);
writer.Close();
}

private static void SerializeNode(string filename)
{
XmlSerializer ser
= new XmlSerializer(typeof(XmlNode));
XmlNode myNode
= new XmlDocument().
CreateNode(XmlNodeType.Element,
"MyNode", "ns");
myNode.InnerText
= "Hello Node";
TextWriter writer
= new StreamWriter(filename);
ser.Serialize(writer, myNode);
writer.Close();
}
}
}
输出
<?xml version="1.0" encoding="utf-8"?>
<MyElement xmlns="ns">Hello World</MyElement>


 

序列化复杂对象

代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml.Serialization;

namespace XmlSerializerDemo
{
class Test
{
static void Main(string[] args)
{
SerailizeClass(
@"D:\SerialClass.xml");
}

private static void SerailizeClass(string filename)
{
XmlSerializer serializer
=
new XmlSerializer(typeof(PurchaseOrder));
TextWriter write
= new StreamWriter(filename);
PurchaseOrder po
= new PurchaseOrder();
Address addr
= new Address();
addr.FirstName
= "Beijing";

po.MyAddress
= addr;
serializer.Serialize(write, po);
write.Close();
}
}

public class PurchaseOrder
{
public Address MyAddress;
}

public class Address
{
public string FirstName;
}
}
输出

代码
<?xml version="1.0" encoding="utf-8"?>
<PurchaseOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MyAddress>
<FirstName>Beijing</FirstName>
</MyAddress>
</PurchaseOrder>

 


 

 序列化对象数组

代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml.Serialization;

namespace XmlSerializerDemo
{
class Test
{
static void Main(string[] args)
{
SerializeClassArray(
@"D:\Dataset.xml");
}

private static void SerializeClassArray(string filename)
{
XmlSerializer serializer
=
new XmlSerializer(typeof(PurchaseOrder));
TextWriter write
= new StreamWriter(filename);
PurchaseOrder po
= new PurchaseOrder();

Item item
= new Item();
item.ItemID
= "xz01";
item.ItemPrice
= (decimal)3.2;

Item item1
= new Item();
item1.ItemID
= "xz02";
item1.ItemPrice
= (decimal)4.5;

Item[] items
= { item, item1};
po.ItemsOrders
= items;
serializer.Serialize(write, po);
write.Close();
}
}

public class PurchaseOrder
{
public Item[] ItemsOrders;
}

public class Item
{
public string ItemID;
public decimal ItemPrice;
}
}
输出
代码
<?xml version="1.0" encoding="utf-8"?>
<PurchaseOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ItemsOrders>
<Item>
<ItemID>xz01</ItemID>
<ItemPrice>3.2</ItemPrice>
</Item>
<Item>
<ItemID>xz02</ItemID>
<ItemPrice>4.5</ItemPrice>
</Item>
</ItemsOrders>
</PurchaseOrder>

序列化实现ICollection的类

代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml.Serialization;
using System.Collections;
using System.Xml;

namespace XmlSerializerDemo
{
class Test
{
static void Main(string[] args)
{
SerializeCollection(
@"D:\SerialCollection.xml");
}

private static void SerializeCollection(string filename)
{
Employees Emps
= new Employees();
Emps.CollectionName
= "Employees";
Employee emp
= new Employee("Yao", "1111");
Emps.Add(emp);

XmlSerializer serializer
= new XmlSerializer(typeof(Employees));
TextWriter write
= new StreamWriter(filename);
serializer.Serialize(write, Emps);
write.Close();
}
}

public class Employee
{
public string EmpName;
public string EmpID;

public Employee() { }

public Employee(string empName, string empID)
{
EmpName
= empName;
EmpID
= empID;
}
}

public class Employees : ICollection
{
public string CollectionName;
public ArrayList empArray = new ArrayList();

public Employee this[int index]
{
get { return (Employee)empArray[index]; }
}

#region ICollection 成员

public void CopyTo(Array array, int index)
{
empArray.CopyTo(array, index);
}

public int Count
{
get { return empArray.Count; }
}

public bool IsSynchronized
{
get { return false; }
}

public object SyncRoot
{
get { return this; }
}

#endregion

#region IEnumerable 成员

public IEnumerator GetEnumerator()
{
return empArray.GetEnumerator();
}

#endregion

public void Add(Employee newEmployee)
{
empArray.Add(newEmployee);
}
}
}
输出
代码
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfEmployee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Employee>
<EmpName>Yao</EmpName>
<EmpID>1111</EmpID>
</Employee>
</ArrayOfEmployee>

 

下面这是一个综合到前面所讲到所有的序列化的示例

代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml.Serialization;
using System.Collections;
using System.Xml;

namespace XmlSerializerDemo
{
class Test
{
static void Main(string[] args)
{
Test t
= new Test();
t.CreatePO(
"po.xml");
t.ReadPO(
"po.xml");
}

private void CreatePO(string filename)
{
XmlSerializer serializer
=
new XmlSerializer(typeof(PurchaseOrder));
TextWriter write
= new StreamWriter(filename);
PurchaseOrder po
= new PurchaseOrder();

Address address
= new Address();
address.Name
= "Teresa Atkinson";
address.Line1
= "1 Main St.";
address.City
= "AnyTown";
address.State
= "WA";
address.Zip
= "00000";

po.ShipTo
= address;
po.OrderDate
= DateTime.Now.ToLongDateString();

OrderItem ol
= new OrderItem();
ol.ItemName
= "Widget S";
ol.Description
= "Small widget";
ol.UnitPrice
= (decimal)5.23;
ol.Quantity
= 3;
ol.Calculate();

OrderItem[] items
= { ol };
po.OrderItems
= items;
decimal subTotal = new decimal();
foreach (OrderItem oi in items)
{
subTotal
+= oi.LineTotal;
}
po.SubTotal
= subTotal;
po.ShipCost
= (decimal)12.51;
po.TotalCost
= po.SubTotal + po.ShipCost;
serializer.Serialize(write, po);
write.Close();
}

protected void ReadPO(string filename)
{
XmlSerializer serializer
=
new XmlSerializer(typeof(PurchaseOrder));
serializer.UnknownNode
+= new
XmlNodeEventHandler(serializer_UnknownNode);
serializer.UnknownAttribute
+= new
XmlAttributeEventHandler(serializer_UnknownAttribute);
FileStream fs
= new FileStream(filename, FileMode.Open);
PurchaseOrder po;
po
= (PurchaseOrder)serializer.Deserialize(fs);
Console.WriteLine(
"OrderDate: " + po.OrderDate);

Address shipTo
= po.ShipTo;
ReadAddress(shipTo,
"Ship To:");
OrderItem[] items
= po.OrderItems;
Console.WriteLine(
"Items to be shipped:");
foreach (OrderItem oi in items)
{
Console.WriteLine(
"\t" +
oi.ItemName
+ "\t" +
oi.Description
+ "\t" +
oi.UnitPrice
+ "\t" +
oi.Quantity
+ "\t" +
oi.LineTotal);
}
Console.WriteLine(
"\t\t\t\t\t Subtotal\t" + po.SubTotal);
Console.WriteLine(
"\t\t\t\t\t Shipping\t" + po.ShipCost);
Console.WriteLine(
"\t\t\t\t\t Total\t\t" + po.TotalCost);
}

protected void ReadAddress(Address a, string label)
{
Console.WriteLine(label);
Console.WriteLine(
"\t" + a.Name);
Console.WriteLine(
"\t" + a.Line1);
Console.WriteLine(
"\t" + a.City);
Console.WriteLine(
"\t" + a.State);
Console.WriteLine(
"\t" + a.Zip);
Console.WriteLine();
}

private void serializer_UnknownNode(object sender, XmlNodeEventArgs e)
{
Console.WriteLine(
"Unknown Node:" + e.Name + "\t" + e.Text);
}

private void serializer_UnknownAttribute(object sender, XmlAttributeEventArgs e)
{
XmlAttribute attr
= e.Attr;
Console.WriteLine(
"Unknown attribute " +
attr.Name
+ "='" + attr.Value + "'");
}
}

[XmlRootAttribute(
"PurchaseOrder",
IsNullable
= false)]
public class PurchaseOrder
{
public Address ShipTo;
public string OrderDate;

[XmlArrayAttribute(
"Items")]
public OrderItem[] OrderItems;
public decimal SubTotal;
public decimal ShipCost;
public decimal TotalCost;
}

public class Address
{
[XmlAttribute]
public string Name;
public string Line1;

[XmlElementAttribute(IsNullable
= false)]
public string City;
public string State;
public string Zip;
}

public class OrderItem
{
public string ItemName;
public string Description;
public decimal UnitPrice;
public int Quantity;
public decimal LineTotal;

public void Calculate()
{
LineTotal
= UnitPrice * Quantity;
}
}
}

 

最后附带上使用XmlSerializer类时,应该注意的一些事项:

1)序列化数据只包含数据本身和类的结构。类型标识和程序集信息不包括在内。

2)只能序列化公共属性和字段。属性必须具有公共访问器(get和set方法)。如果必须序列化非公共数据,使用DataContractSerializer类而不使用XML序列化。

3)类必须具有默认的构造函数才能被XmlSerailizer序列化。

4)方法不能被序列化。

5)如果可实现 IEnumerable 或 ICollection 的类满足特定要求。实现 IEnumerable 的类必须实现采用单个参数的公共 Add 方法。Add 方法的参数必须与从        IEnumerator.Current 属性返回的类型一致(多态),该属性是从 GetEnumerator 方法返回的。实现 ICollection(如 CollectionBase)的类还必须有一个采用整数的公共 Item 索引属性(在 C# 中为索引器),而且必须有一个 integer 类型的公共 Count 属性。传递给 Add 方法的参数的类型必须与从 Item 属性返回的类型相同,或者为此类型的基之一。