[.net 面向对象程序设计进阶] (11) 序列化(Serialization)(三) 通过接口IXmlSerializable实现XML序列化及XML通用类
本节导读:本节主要介绍通过序列化接口IXmlSerializable实现XML序列化和反序列化,整理了XML基础操作及序列化的通用类(包括XML及节点的基础读写操作,XML到DataSet\DataTable互转换操作,XML序列化及反序列化通用方法等)。
读前必备:
A.类和类的实例 [.net 面向对象编程基础] (9) 类和类的实例
B.类的成员 [.net 面向对象编程基础] (10) 类的成员(字段、属性、方法)
C.数组与集合 [.net 面向对象编程基础] (17) 数组与集合
E.LINQ使用 [.net 面向对象编程基础] (20) LINQ使用
1. 通过序列化接口IXmlSerializable实现XML序列化
命名空间:System.Xml.Serialization
接口:IXmlSerializable
方法:
XmlSchema GetSchema();
void ReadXml(XmlReader reader);
void WriteXml(XmlWriter writer);
下面通过示例介绍关于序列化接口的使用,还是通过博客园文章为例:
定义文章实体类及文章调用方法:
public class MyBlogs { /// <summary> /// 获取我的博客园中文章 /// </summary> /// <returns></returns> public static List<MyArticle> GetMyArticle(int count) { var document = XDocument.Load( "http://wcf.open.cnblogs.com/blog/u/yubinfeng/posts/1/" + count ); List<MyArticle> myArticleList = new List<MyArticle>(); var elements = document.Root.Elements(); //在进行这个工作之前,我们先获取我博客中的文章列表 var result = elements.Where(m => m.Name.LocalName == "entry").Select(myArticle => new MyArticle { id = Convert.ToInt32(myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "id").Value), title = myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "title").Value, published = Convert.ToDateTime(myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "published").Value), updated = Convert.ToDateTime(myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "updated").Value), diggs = Convert.ToInt32(myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "diggs").Value), views = Convert.ToInt32(myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "views").Value), comments = Convert.ToInt32(myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "comments").Value), summary = myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "summary").Value, link = myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "link").Attribute("href").Value, author = myArticle.Elements().SingleOrDefault(x => x.Name.LocalName == "author").Elements().SingleOrDefault(x => x.Name.LocalName == "name").Value }).OrderByDescending(m => m.published); myArticleList.AddRange(result); return myArticleList; } } /// <summary /// 我的博客文章实体类 /// </summary> public class MyArticle { /// <summary> /// 文章编号 /// </summary> public int id { get; set; } /// <summary> /// 文章标题 /// </summary> public string title { get; set; } /// <summary> /// 文章摘要 /// </summary> public string summary { get; set; } /// <summary> /// 发布时间 /// </summary> public DateTime published { get; set; } /// <summary> /// 最后更新时间 /// </summary> public DateTime updated { get; set; } /// <summary> /// URL地址 /// </summary> public string link { get; set; } /// <summary> /// 推荐数 /// </summary> public int diggs { get; set; } /// <summary> /// 浏览量 /// </summary> public int views { get; set; } /// <summary> /// 评论数 /// </summary> public int comments { get; set; } /// <summary> /// 作者 /// </summary> public string author { get; set; } }
XML通过接口序列化和反序列化的方法
/// <summary> /// 序列化XML 对象=》XML文本 /// 下面注释项,可根据需要使用 /// </summary> /// <param name="Obj"></param> /// <returns></returns> public static string ObjectToXmlSerializer(Object Obj) { string XmlString = ""; XmlWriterSettings settings = new XmlWriterSettings(); //settings.OmitXmlDeclaration = true;//去除xml声明 settings.Encoding = Encoding.Default;//使用默认编码 //settings.IndentChars = "--"; //使用指定字符缩进 settings.Indent = true; //换行缩进 using (System.IO.MemoryStream mem = new MemoryStream()) { using (XmlWriter writer = XmlWriter.Create(mem, settings)) { //去除默认命名空间xmlns:xsd和xmlns:xsi XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("", ""); XmlSerializer formatter = new XmlSerializer(Obj.GetType()); formatter.Serialize(writer, Obj, ns); } XmlString = Encoding.Default.GetString(mem.ToArray()); } return XmlString; } /// <summary> /// 反序列化 XML文本=》对象 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="str"></param> /// <returns></returns> public static T ObjectToXmlDESerializer<T>(string str) where T : class { object obj; using (System.IO.MemoryStream mem = new MemoryStream(Encoding.Default.GetBytes(str))) { using (XmlReader reader = XmlReader.Create(mem)) { XmlSerializer formatter = new XmlSerializer(typeof(T)); obj = formatter.Deserialize(reader); } } return obj as T; }
调用如下:
//命名空间:System.Xml.Serialization //接口:IXmlSerializable //方法:XmlSchema GetSchema();void ReadXml(XmlReader reader);void WriteXml(XmlWriter writer); //(1)获取我博客园中最后10篇文章 (实际上这个过程也是反序列化) List<MyArticle> myArticleList = MyBlogs.GetMyArticle(10); //序列化并输出XML文本 string xmlString = ObjectToXmlSerializer(myArticleList); Console.Write(xmlString); //序列化XML文本,遍历输出对象 List<MyArticle> myNewArticleList = ObjectToXmlDESerializer<List<MyArticle>>(xmlString); //遍历输出反序化的新对象myNewArticleList myNewArticleList.ForEach(m => Console.WriteLine("文章编号:" + m.id + "\n文章标题:" + m.title) );
运行结果如下:
2. XML类
我们在序列化XML的时候,经常要操作XML,下面我列出XML类的一些成员,供参考查阅
XML操作的命名空间:System.Xml;
名称 |
描述 |
XmlAttribute |
表示一个特性对象的集合,这些对象控制XmlSerializer如何序列化和反序列化对象 |
XmlArrayAttribute |
指定XmlSerializer应将特定的类成员序列化为XML元素数组 |
XmlArrayItemAttribute |
指定XmlSerializer可以放置在序列化数组中的派生类型 |
XmlArrayItemAttributes |
表示XmlArrayItemAttribute对象的集合 |
XmlAttributeAttribute |
指定XmlSerializer应将类成员作为XML特性序列化 |
XmlChoiceIdentifierAttribute |
指定可以通过使用枚举来进一步消除成员的歧义 |
XmlElementAttribute |
在XmlSerializer序列化或反序列化包含对象时,指示公共字段或属性表示XML元素 |
XmlElementAttributes |
表示XmlElementAttribute的集合,XmlSerializer将其用于它重写序列化类的默认方式 |
XmlEnumAttribute |
控制XmlSerializer如何序列化枚举成员 |
XmlIgnoreAttribute |
指示XmlSerializer方法不序列化公共字段或公共读/写属性值 |
XmlIncludeAttribute |
允许XmlSerializer在它序列化或反序列化对象时识别类型 |
XmlRootAttribute |
控制视为XML根元素的属性目标的XML序列化 |
XmlTextAttribute |
当序列化或反序列化时,想XmlSerializer指示应将此成员作为XML文本处理 |
XmlTypeAttribute |
控制当属性目标由XmlSerializer序列化时生成的XML结构 |
XmlAnyAttributeAttribute |
指定成员(返回XmlAttribute对象的数组的字段)可以包含XML属性 |
XmlAnyElementAttribute |
指定成员可以包含对象,该对象表示在序列化或反序列化的对象中没有相应成员的所有XML元素 |
XmlAnyElementAttributes |
表示XmlAnyElementAttribute对象的集合 |
XmlAttributeEventArgs |
为UnKnowAttribute提供数据 |
XmlAttributeOverrides |
允许你在使用XmlSerializer序列化或反序列化时重写属性、字段和类特性 |
XmlElementEventArgs |
为UnknownElement事件提供数据 |
XmlNamespaceDeclarationsAttribute |
指定目标属性、参数、返回值或类成员包含与XML文档中所用命名空间关联的前缀 |
XmlNodeEventArgs |
为UnknownNode时间提供数据 |
XmlSerializer |
将对象序列化到XML文档中和从XML文档中反序列化对象,XmlSerializer使你得以控制如何将对象编码到XML中 |
XmlSerializerNamespaces |
包含XmlSerializer用于在XML文档实例中生成限定名的XML命名空间和前缀 |
XmlTypeMapping |
包含从一种类型到另一种类型的映射 |
更多更详细的说明,请看官方API:http://msdn.microsoft.com/zh-cn/library/System.Xml.Serialization(v=vs.110).aspx
3. XML封装类
最后整理一个XML的封装类提供给小伙伴们,里面包含了XML节点到DataSet,DataTable及XML序列化和反序列化,XML写入文件或读取XML文件及节点等。
文件名:XmlHelper.cs
代码如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.IO; 7 using System.Data; 8 using System.Xml; 9 using System.Xml.Serialization; 10 using System.Xml.Linq; 11 12 namespace Common 13 { 14 /// <summary> 15 /// Xml通用类 16 /// Author:YuBinfeng 17 /// Data:2015/07/10 18 /// </summary> 19 public class XmlHelper 20 { 21 22 #region XML的基础读写 23 24 #region 将XML文本写入到指定路径的文件 25 /// <summary> 26 /// 将XML文本写入到指定路径的文件 27 /// </summary> 28 /// <param name="XMLString"></param> 29 /// <param name="filePath"></param> 30 /// <returns></returns> 31 public static bool WriteXmlString(string XMLString,string filePath) 32 { 33 try 34 { 35 File.WriteAllText(filePath, XMLString,Encoding.Default); 36 return true; 37 } 38 catch 39 { 40 return false; 41 } 42 } 43 #endregion 44 45 #region 从指定的路径读取XML文本 46 /// <summary> 47 /// 将XML文本写入到指定路径的文件 48 /// </summary> 49 /// <param name="XMLString"></param> 50 /// <param name="filePath"></param> 51 /// <returns></returns> 52 public static string ReadXmlString( string filePath) 53 { 54 try 55 { 56 XmlDocument xmlDoc = new XmlDocument(); 57 xmlDoc.Load(filePath); 58 return xmlDoc.InnerXml; 59 } 60 catch (Exception ex) 61 { 62 return ""; 63 } 64 } 65 #endregion 66 67 #region 读取XML资源中的指定节点内容 68 /// <summary> 69 /// 读取XML资源中的指定节点内容 70 /// </summary> 71 /// <param name="source">XML资源</param> 72 /// <param name="xmlType">XML资源类型:文件,字符串</param> 73 /// <param name="nodeName">节点名称</param> 74 /// <returns>节点内容</returns> 75 public static object GetNodeValue(string source, XmlType xmlType, string nodeName) 76 { 77 XmlDocument xd = new XmlDocument(); 78 if (xmlType == XmlType.File) 79 { 80 xd.Load(source); 81 } 82 else 83 { 84 xd.LoadXml(source); 85 } 86 XmlElement xe = xd.DocumentElement; 87 XmlNode xn = xe.SelectSingleNode("//" + nodeName); 88 if (xn != null) 89 { 90 return xn.InnerText; 91 } 92 else 93 { 94 return null; 95 } 96 } 97 98 /// <summary> 99 /// 读取XML资源中的指定节点内容 100 /// </summary> 101 /// <param name="source">XML资源</param> 102 /// <param name="nodeName">节点名称</param> 103 /// <returns>节点内容</returns> 104 public static object GetNodeValue(string source, string nodeName) 105 { 106 if (source == null || nodeName == null || source == "" || nodeName == "" || source.Length < nodeName.Length * 2) 107 { 108 return null; 109 } 110 else 111 { 112 int start = source.IndexOf("<" + nodeName + ">") + nodeName.Length + 2; 113 int end = source.IndexOf("</" + nodeName + ">"); 114 if (start == -1 || end == -1) 115 { 116 return null; 117 } 118 else if (start >= end) 119 { 120 return null; 121 } 122 else 123 { 124 return source.Substring(start, end - start); 125 } 126 } 127 } 128 #endregion 129 130 #region 更新XML文件中的指定节点内容 131 /// <summary> 132 /// 更新XML文件中的指定节点内容 133 /// </summary> 134 /// <param name="filePath">文件路径</param> 135 /// <param name="nodeName">节点名称</param> 136 /// <param name="nodeValue">更新内容</param> 137 /// <returns>更新是否成功</returns> 138 public static bool UpdateNode(string filePath, string nodeName, string nodeValue) 139 { 140 bool flag = false; 141 142 XmlDocument xd = new XmlDocument(); 143 xd.Load(filePath); 144 XmlElement xe = xd.DocumentElement; 145 XmlNode xn = xe.SelectSingleNode("//" + nodeName); 146 if (xn != null) 147 { 148 xn.InnerText = nodeValue; 149 flag = true; 150 } 151 else 152 { 153 flag = false; 154 } 155 return flag; 156 } 157 #endregion 158 159 #region 操作xml文件中指定节点的数据 160 /// <summary> 161 /// 获得xml文件中指定节点的节点数据 162 /// </summary> 163 /// <param name="TableName"></param> 164 /// <returns></returns> 165 public static string GetNodeInfoByNodeName(string path, string nodeName) 166 { 167 string XmlString = ""; 168 XmlDocument xml = new XmlDocument(); 169 xml.Load(path); 170 System.Xml.XmlElement root = xml.DocumentElement; 171 System.Xml.XmlNode node = root.SelectSingleNode("//" + nodeName); 172 if (node != null) 173 { 174 XmlString = node.InnerText; 175 } 176 return XmlString; 177 } 178 #endregion 179 #endregion 180 181 #region 共有属性 182 /// <summary> 183 /// XML资源类型 184 /// </summary> 185 public enum XmlType 186 { 187 File, 188 String 189 }; 190 #endregion 191 192 #region XML与DataSet DataTable相关 193 194 #region 读取XML资源到DataSet中 195 /// <summary> 196 /// 读取XML资源到DataSet中 197 /// </summary> 198 /// <param name="source">XML资源,文件为路径,否则为XML字符串</param> 199 /// <param name="xmlType">XML资源类型</param> 200 /// <returns>DataSet</returns> 201 public static DataSet GetDataSet(string source, XmlType xmlType) 202 { 203 DataSet ds = new DataSet(); 204 if (xmlType == XmlType.File) 205 { 206 ds.ReadXml(source); 207 } 208 else 209 { 210 XmlDocument xd = new XmlDocument(); 211 xd.LoadXml(source); 212 XmlNodeReader xnr = new XmlNodeReader(xd); 213 ds.ReadXml(xnr); 214 } 215 return ds; 216 } 217 218 #endregion 219 220 #region 获取一个字符串xml文档中的ds 221 /// <summary> 222 /// 获取一个字符串xml文档中的ds 223 /// </summary> 224 /// <param name="xml_string">含有xml信息的字符串</param> 225 public static void get_XmlValue_ds(string xml_string, ref DataSet ds) 226 { 227 System.Xml.XmlDocument xd = new XmlDocument(); 228 xd.LoadXml(xml_string); 229 XmlNodeReader xnr = new XmlNodeReader(xd); 230 ds.ReadXml(xnr); 231 xnr.Close(); 232 int a = ds.Tables.Count; 233 } 234 #endregion 235 236 #region 读取XML资源到DataTable中 237 /// <summary> 238 /// 读取XML资源到DataTable中 239 /// </summary> 240 /// <param name="source">XML资源,文件为路径,否则为XML字符串</param> 241 /// <param name="xmlType">XML资源类型:文件,字符串</param> 242 /// <param name="tableName">表名称</param> 243 /// <returns>DataTable</returns> 244 public static DataTable GetTable(string source, XmlType xmlType, string tableName) 245 { 246 DataSet ds = new DataSet(); 247 if (xmlType == XmlType.File) 248 { 249 ds.ReadXml(source); 250 } 251 else 252 { 253 XmlDocument xd = new XmlDocument(); 254 xd.LoadXml(source); 255 XmlNodeReader xnr = new XmlNodeReader(xd); 256 ds.ReadXml(xnr); 257 } 258 return ds.Tables[tableName]; 259 } 260 #endregion 261 262 #region 读取XML资源中指定的DataTable的指定行指定列的值 263 /// <summary> 264 /// 读取XML资源中指定的DataTable的指定行指定列的值 265 /// </summary> 266 /// <param name="source">XML资源</param> 267 /// <param name="xmlType">XML资源类型:文件,字符串</param> 268 /// <param name="tableName">表名</param> 269 /// <param name="rowIndex">行号</param> 270 /// <param name="colName">列名</param> 271 /// <returns>值,不存在时返回Null</returns> 272 public static object GetTableCell(string source, XmlType xmlType, string tableName, int rowIndex, string colName) 273 { 274 DataSet ds = new DataSet(); 275 if (xmlType == XmlType.File) 276 { 277 ds.ReadXml(source); 278 } 279 else 280 { 281 XmlDocument xd = new XmlDocument(); 282 xd.LoadXml(source); 283 XmlNodeReader xnr = new XmlNodeReader(xd); 284 ds.ReadXml(xnr); 285 } 286 return ds.Tables[tableName].Rows[rowIndex][colName]; 287 } 288 #endregion 289 290 #region 读取XML资源中指定的DataTable的指定行指定列的值 291 /// <summary> 292 /// 读取XML资源中指定的DataTable的指定行指定列的值 293 /// </summary> 294 /// <param name="source">XML资源</param> 295 /// <param name="xmlType">XML资源类型:文件,字符串</param> 296 /// <param name="tableName">表名</param> 297 /// <param name="rowIndex">行号</param> 298 /// <param name="colIndex">列号</param> 299 /// <returns>值,不存在时返回Null</returns> 300 public static object GetTableCell(string source, XmlType xmlType, string tableName, int rowIndex, int colIndex) 301 { 302 DataSet ds = new DataSet(); 303 if (xmlType == XmlType.File) 304 { 305 ds.ReadXml(source); 306 } 307 else 308 { 309 XmlDocument xd = new XmlDocument(); 310 xd.LoadXml(source); 311 XmlNodeReader xnr = new XmlNodeReader(xd); 312 ds.ReadXml(xnr); 313 } 314 return ds.Tables[tableName].Rows[rowIndex][colIndex]; 315 } 316 #endregion 317 318 #region 将DataTable写入XML文件中 319 /// <summary> 320 /// 将DataTable写入XML文件中 321 /// </summary> 322 /// <param name="dt">含有数据的DataTable</param> 323 /// <param name="filePath">文件路径</param> 324 public static void SaveTableToFile(DataTable dt, string filePath) 325 { 326 DataSet ds = new DataSet("Config"); 327 ds.Tables.Add(dt.Copy()); 328 ds.WriteXml(filePath); 329 } 330 #endregion 331 332 #region 将DataTable以指定的根结点名称写入文件 333 /// <summary> 334 /// 将DataTable以指定的根结点名称写入文件 335 /// </summary> 336 /// <param name="dt">含有数据的DataTable</param> 337 /// <param name="rootName">根结点名称</param> 338 /// <param name="filePath">文件路径</param> 339 public static void SaveTableToFile(DataTable dt, string rootName, string filePath) 340 { 341 DataSet ds = new DataSet(rootName); 342 ds.Tables.Add(dt.Copy()); 343 ds.WriteXml(filePath); 344 } 345 #endregion 346 347 #region 使用DataSet方式更新XML文件节点 348 /// <summary> 349 /// 使用DataSet方式更新XML文件节点 350 /// </summary> 351 /// <param name="filePath">XML文件路径</param> 352 /// <param name="tableName">表名称</param> 353 /// <param name="rowIndex">行号</param> 354 /// <param name="colName">列名</param> 355 /// <param name="content">更新值</param> 356 /// <returns>更新是否成功</returns> 357 public static bool UpdateTableCell(string filePath, string tableName, int rowIndex, string colName, string content) 358 { 359 bool flag = false; 360 DataSet ds = new DataSet(); 361 ds.ReadXml(filePath); 362 DataTable dt = ds.Tables[tableName]; 363 364 if (dt.Rows[rowIndex][colName] != null) 365 { 366 dt.Rows[rowIndex][colName] = content; 367 ds.WriteXml(filePath); 368 flag = true; 369 } 370 else 371 { 372 flag = false; 373 } 374 return flag; 375 } 376 #endregion 377 378 #region 使用DataSet方式更新XML文件节点 379 /// <summary> 380 /// 使用DataSet方式更新XML文件节点 381 /// </summary> 382 /// <param name="filePath">XML文件路径</param> 383 /// <param name="tableName">表名称</param> 384 /// <param name="rowIndex">行号</param> 385 /// <param name="colIndex">列号</param> 386 /// <param name="content">更新值</param> 387 /// <returns>更新是否成功</returns> 388 public static bool UpdateTableCell(string filePath, string tableName, int rowIndex, int colIndex, string content) 389 { 390 bool flag = false; 391 392 DataSet ds = new DataSet(); 393 ds.ReadXml(filePath); 394 DataTable dt = ds.Tables[tableName]; 395 396 if (dt.Rows[rowIndex][colIndex] != null) 397 { 398 dt.Rows[rowIndex][colIndex] = content; 399 ds.WriteXml(filePath); 400 flag = true; 401 } 402 else 403 { 404 flag = false; 405 } 406 return flag; 407 } 408 #endregion 409 410 #endregion 411 412 #region XML序列化与反序列化相关 413 414 /// <summary> 415 /// 序列化XML 对象=》XML文本 416 /// 下面注释项,可根据需要使用 417 /// </summary> 418 /// <param name="Obj"></param> 419 /// <returns></returns> 420 public static string ObjectToXmlSerializer(Object Obj) 421 { 422 string XmlString = ""; 423 XmlWriterSettings settings = new XmlWriterSettings(); 424 //settings.OmitXmlDeclaration = true;//去除xml声明 425 settings.Encoding = Encoding.Default;//使用默认编码 426 //settings.IndentChars = "--"; //使用指定字符缩进 427 settings.Indent = true; //换行缩进 428 429 using (System.IO.MemoryStream mem = new MemoryStream()) 430 { 431 using (XmlWriter writer = XmlWriter.Create(mem, settings)) 432 { 433 //去除默认命名空间xmlns:xsd和xmlns:xsi 434 XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); 435 ns.Add("", ""); 436 437 XmlSerializer formatter = new XmlSerializer(Obj.GetType()); 438 formatter.Serialize(writer, Obj, ns); 439 } 440 XmlString = Encoding.Default.GetString(mem.ToArray()); 441 } 442 return XmlString; 443 } 444 445 /// <summary> 446 /// 反序列化 XML文本=》对象 447 /// </summary> 448 /// <typeparam name="T"></typeparam> 449 /// <param name="str"></param> 450 /// <returns></returns> 451 public static T ObjectToXmlDESerializer<T>(string str) where T : class 452 { 453 object obj; 454 using (System.IO.MemoryStream mem = new MemoryStream(Encoding.Default.GetBytes(str))) 455 { 456 using (XmlReader reader = XmlReader.Create(mem)) 457 { 458 XmlSerializer formatter = new XmlSerializer(typeof(T)); 459 obj = formatter.Deserialize(reader); 460 } 461 } 462 return obj as T; 463 } 464 465 #endregion 466 467 } 468 }
4. 本节要点:
A.本节主要介绍了通过序列化接口IXmlSerializable实现XML序列化
B.XML本身的操作简单介绍
C.最后提供了一个序列化及XML操作的通用类
==============================================================================================
<如果对你有帮助,记得点一下推荐哦,如有有不明白或错误之处,请多交流>
<对本系列文章阅读有困难的朋友,请先看《.net 面向对象编程基础》>
<转载声明:技术需要共享精神,欢迎转载本博客中的文章,但请注明版权及URL>
.NET 技术交流群:467189533
==============================================================================================