我們需要在XML與實(shí)體類,DataTable,List之間進(jìn)行轉(zhuǎn)換,下面是XmlUtil類嗅虏,該類來自網(wǎng)絡(luò)并稍加修改。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Data;
using System.Xml;
using System.Xml.Serialization;
/// <summary>
/// Xml序列化與反序列化
/// </summary>
publicclass XmlUtil
{
#region 反序列化
/// <summary>
/// 反序列化
/// </summary>
/// <param name="type">類型</param>
/// <param name="xml">XML字符串</param>
/// <returns></returns>
publicstatic objectDeserialize(Type type, stringxml)
{
try
{
using(StringReader sr = newStringReader(xml))
{
XmlSerializer xmldes =new XmlSerializer(type);
returnxmldes.Deserialize(sr);
}
}
catch(Exception e)
{
returnnull;
}
}
/// <summary>
/// 反序列化
/// </summary>
/// <param name="type"></param>
/// <param name="xml"></param>
/// <returns></returns>
publicstatic objectDeserialize(Type type, Stream stream)
{
XmlSerializer xmldes =new XmlSerializer(type);
returnxmldes.Deserialize(stream);
}
#endregion
#region 序列化
/// <summary>
/// 序列化
/// </summary>
/// <param name="type">類型</param>
/// <param name="obj">對(duì)象</param>
/// <returns></returns>
publicstatic stringSerializer(Type type, objectobj)
{
MemoryStream Stream =new MemoryStream();
XmlSerializer xml =new XmlSerializer(type);
try
{
//序列化對(duì)象
xml.Serialize(Stream, obj);
}
catch(InvalidOperationException)
{
throw;
}
Stream.Position = 0;
StreamReader sr =new StreamReader(Stream);
stringstr = sr.ReadToEnd();
sr.Dispose();
Stream.Dispose();
returnstr;
}
#endregion
}
下面是測(cè)試代碼:
- 實(shí)體對(duì)象轉(zhuǎn)換到Xml
public class Student
{
publicstring Name { set; get; }
publicint Age { set;get; }
}
Student stu1 = new Student() { Name ="okbase", Age = 10 };
string xml = XmlUtil.Serializer(typeof(Student), stu1);
Console.Write(xml);
- Xml轉(zhuǎn)換到實(shí)體對(duì)象
Student stu2 = XmlUtil.Deserialize(typeof(Student), xml)as Student;
Console.Write(string.Format("名字:{0},年齡:{1}", stu2.Name, stu2.Age));
- DataTable轉(zhuǎn)換到Xml
// 生成DataTable對(duì)象用于測(cè)試
DataTable dt1 = new DataTable("mytable"); // 必須指明DataTable名稱
dt1.Columns.Add("Dosage",typeof(int));
dt1.Columns.Add("Drug",typeof(string));
dt1.Columns.Add("Patient",typeof(string));
dt1.Columns.Add("Date",typeof(DateTime));
// 添加行
dt1.Rows.Add(25,"Indocin", "David", DateTime.Now);
dt1.Rows.Add(50,"Enebrel", "Sam", DateTime.Now);
dt1.Rows.Add(10,"Hydralazine","Christoff", DateTime.Now);
dt1.Rows.Add(21,"Combivent","Janet", DateTime.Now);
dt1.Rows.Add(100,"Dilantin", "Melanie", DateTime.Now);
// 序列化
xml = XmlUtil.Serializer(typeof(DataTable), dt1);
Console.Write(xml);
- Xml轉(zhuǎn)換到DataTable
// 反序列化
DataTable dt2 = XmlUtil.Deserialize(typeof(DataTable), xml)as DataTable;
// 輸出測(cè)試結(jié)果
foreach(DataRow dr indt2.Rows)
{
foreach(DataColumn col indt2.Columns)
{
Console.Write(dr[col].ToString() +" ");
}
Console.Write("\r\n");
}
- List轉(zhuǎn)換到Xml
// 生成List對(duì)象用于測(cè)試
List<Student> list1 =new List<Student>(3);
list1.Add(newStudent() { Name = "okbase", Age = 10 });
list1.Add(newStudent() { Name = "csdn", Age = 15 });
// 序列化
xml = XmlUtil.Serializer(typeof(List<Student>), list1);
Console.Write(xml);
- Xml轉(zhuǎn)換到List
List<Student> list2 = XmlUtil.Deserialize(typeof(List<Student>), xml)as List<Student>;
foreach(Student stu inlist2)
{
Console.WriteLine(stu.Name +"," + stu.Age.ToString());
}
從代碼可以看到上沐,千變?nèi)f化不離其宗!
.Net Framework提供了對(duì)應(yīng)的System.Xml.Seriazliation.XmlSerializer負(fù)責(zé)把對(duì)象序列化到XML皮服,和從XML中反序列化為對(duì)象。Serializer的使用比較直觀参咙,需要多注意的是XML序列化相關(guān)的Attribute冰更,怎么把這些attribute應(yīng)用到我們的對(duì)象,以及對(duì)象公共屬性上面去昂勒,生成滿足預(yù)期格式的XML蜀细。
本文列出了最常用的方法和特性,涵蓋日常大部分的轉(zhuǎn)換工作戈盈,希望大家在工作中快速上手奠衔。為了給大家直觀的印象,這里給出具體的使用代碼塘娶,為了節(jié)省篇幅归斤,代碼異常處理沒有添加,各位同學(xué)使用的時(shí)候酌情添加刁岸。
1. Serializer方法
下面的方法封裝了XmlSerializer的調(diào)用脏里,這里列出了參數(shù)最全的一個(gè)版本,具體使用的時(shí)候需適當(dāng)添加重載:
public static class XmlSerializer
{
public static void SaveToXml(string filePath, object sourceObj, Type type, string xmlRootName)
{
if (!string.IsNullOrWhiteSpace(filePath) && sourceObj != null)
{
type = type != null ? type : sourceObj.GetType();
using (StreamWriter writer = new StreamWriter(filePath))
{
System.Xml.Serialization.XmlSerializer xmlSerializer = string.IsNullOrWhiteSpace(xmlRootName) ?
new System.Xml.Serialization.XmlSerializer(type) :
new System.Xml.Serialization.XmlSerializer(type, new XmlRootAttribute(xmlRootName));
xmlSerializer.Serialize(writer, sourceObj);
}
}
}
public static object LoadFromXml(string filePath, Type type)
{
object result = null;
if (File.Exists(filePath))
{
using (StreamReader reader = new StreamReader(filePath))
{
System.Xml.Serialization.XmlSerializer xmlSerializer = new System.Xml.Serialization.XmlSerializer(type);
result = xmlSerializer.Deserialize(reader);
}
}
return result;
}
}
2. 序列化常用Attribute講解說明:
[XmlRootAttribute("MyCity", Namespace="abc.abc", IsNullable=false)] // 當(dāng)該類為Xml根節(jié)點(diǎn)時(shí)虹曙,以此為根節(jié)點(diǎn)名稱迫横。
public class City
[XmlAttribute("AreaName")] // 表現(xiàn)為Xml節(jié)點(diǎn)屬性。<... AreaName="..."/>
public string Name
[XmlElementAttribute("AreaId", IsNullable = false)] // 表現(xiàn)為Xml節(jié)點(diǎn)酝碳。<AreaId>...</AreaId>
public string Id
[XmlArrayAttribute("Areas")] // 表現(xiàn)為Xml層次結(jié)構(gòu)矾踱,根為Areas,其所屬的每個(gè)該集合節(jié)點(diǎn)元素名為類名疏哗。<Areas><Area ... /><Area ... /></Areas>
public Area[] Areas
[XmlElementAttribute("Area", IsNullable = false)] // 表現(xiàn)為水平結(jié)構(gòu)的Xml節(jié)點(diǎn)呛讲。<Area ... /><Area ... />...
public Area[] Areas
[XmlIgnoreAttribute] // 忽略該元素的序列化。
3. 詳細(xì)舉例說明
這里用簡(jiǎn)單的城市,區(qū)域和街區(qū)作為例子贝搁,具體示范一下上面的規(guī)則吗氏。
[XmlRootAttribute("MyCity", Namespace = "abc.abc", IsNullable = false)]
public class City
{
[XmlAttribute("CityName")]
public string Name
{
get;
set;
}
[XmlAttribute("CityId")]
public string Id
{
get;
set;
}
[XmlArrayAttribute("Areas")]
public Area[] Areas
{
get;
set;
}
}
[XmlRootAttribute("MyArea")]
public class Area
{
[XmlAttribute("AreaName")]
public string Name
{
get;
set;
}
[XmlElementAttribute("AreaId", IsNullable = false)]
public string Id
{
get;
set;
}
[XmlElementAttribute("Street", IsNullable = false)]
public string[] Streets
{
get;
set;
}
}
根據(jù)以上類型,我們mock一些數(shù)據(jù)雷逆,然后用步驟1給出的Util方法輸出:
static void Main(string[] args)
{
Area area1 = new Area();
area1.Name = "Pudong";
area1.Id = "PD001";
area1.Streets = new string [] { "street 001", "street 002" };
Area area2 = new Area();
area2.Name = "Xuhui";
area2.Id = "XH002";
area2.Streets = new string [] { "street 003", "street 004" };
City city1 = new City();
city1.Name = "Shanghai";
city1.Id = "SH001";
city1.Areas = new Area[] { area1, area2 };
XmlSerializer.SaveToXml(@"C:\temp\XML\output003.xml", city1);
}
最終輸出的XML為:
<?xml version="1.0" encoding="utf-8"?>
<MyCity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
CityName="Shanghai" CityId="SH001" xmlns="abc.abc">
<Areas>
<Area AreaName="Pudong">
<AreaId>PD001</AreaId>
<Street>street 001</Street>
<Street>street 002</Street>
</Area>
<Area AreaName="Xuhui">
<AreaId>XH002</AreaId>
<Street>street 003</Street>
<Street>street 004</Street>
</Area>
</Areas>
</MyCity>
下面我們開始具體分析結(jié)果弦讽,其中包含一些很有用的結(jié)論和注意事項(xiàng):
xml的版本,編碼关面,以及命名空間xmlns:xsi坦袍,xmlns:xsd為Framework自動(dòng)添加十厢。
因?yàn)槲覀冇肅ity對(duì)象作為根節(jié)點(diǎn)等太,所以根節(jié)點(diǎn)名稱為我們定義的"MyCity"。
但是蛮放,注意缩抡!這里指的是用City自身直接做根節(jié)點(diǎn),如果是City集合比如City[]包颁,此時(shí)瞻想,該名稱失效,系統(tǒng)會(huì)自動(dòng)生成名稱ArrayOfCity作為根節(jié)點(diǎn)名稱(ArrayOf+類名)娩嚼,或者我們手動(dòng)指定名稱蘑险,這個(gè)就是在給大家的SaveToXml()方法中,參數(shù)xmlRootName的作用岳悟。如果以City為根節(jié)點(diǎn)并在XmlRootAttribute特性中給定名稱佃迄,同時(shí)也手動(dòng)指定了xmlRootName,系統(tǒng)會(huì)以手動(dòng)指定的名稱為準(zhǔn)贵少。
AreaName呵俏,AreaId,同為Area類的公共屬性滔灶,一個(gè)被解釋成屬性普碎,一個(gè)被解釋成子節(jié)點(diǎn)。
Areas集合被解釋成了層次結(jié)構(gòu)录平,Streets集合被解釋成了水平結(jié)構(gòu)麻车。
這兩組區(qū)別最能體現(xiàn)不同序列化Attribute的用法。
4. 結(jié)語(yǔ)
這里用例子說明了Xml Serializer的用法斗这,C#類和Xml之間的結(jié)構(gòu)映射绪氛,希望足夠同學(xué)們對(duì)付日常工作。更深入的討論會(huì)在后續(xù)的文章跟進(jìn)涝影。