<?xml version="1.0" encoding="utf-8" ?> <theater> <name>The Camelot</name> <phone>(888)665-2222</phone> <movie minutes="120" stars="2"> <title>The Score</title> <rating>R</rating> <showing>16:15:00</showing> <showing>19:05:00</showing> <showing>21:40:00</showing> </movie> <movie minutes="100"> <title>Shrek</title> <rating>PG-13</rating> <showing>16:00:00</showing> <showing>19:00:00</showing> <showing>21:40:00</showing> </movie> </theater> |
表B中定义了一个Theater(电影院)类, 它包含了XmlSerializer使用的属性映射.
表B
using System; using System.xml.Serialization; namespace Articles.TechRepublic.xmlSerialization { [xmlRoot( "theater" )] public class Theater { [xmlElement( "name" )] public string Name = ""; [xmlElement( "phone" )] public string Phone = ""; [xmlElement( "movie" )] public Movie[] Movies; public override string ToString() { string movies = ""; if ( Movies != null ) foreach ( Movie movie in Movies ) movies += " " + movie.ToString(); return String.Format( " ", Name, Phone, movies ); } } |
xmlRoot 属性将类Theater映射到xml的根元素theater. xmlElement 属性将Name, Phone, 和 Movies数据域映射到嵌套在theater元素中的name, phone, 和 movie xml元素上去. 因为Movies是Movie数组, 所以XmlSerializer将它映射到多个xml movie元素.
表C展示了一个带有属性映射的Movie类
表C
public class Movie { [xmlElement( "title" )] public string Title = ""; [xmlAttribute( "minutes" )] public uint Minutes = 0; [xmlElement( "showing", DataType="time" )] public DateTime[] Showings; public override string ToString() { string showings = ""; if ( Showings != null ) { showings = "shows at "; foreach ( DateTime showing in Showings ) showings += showing.ToShortTimeString() + " "; } else { showings = "- No showings"; } return String.Format( " ( min) ", Title, Minutes, showings ); } } |
xmlElement 属性将Title和Showings数据域映射到movie元素内的title 和showing xml元素.就象 Theater.Movie一样, 做为DateTime数组的Movie.Showings 被映射到多个xml showing 元素. showing 数据域的属性包括位置属性参数DataType="time". 它将DateTime值映射到一个xml time值, 其间去掉了日期信息而只保留了时间信息. xmlAttribute 属性将Minutes 数据域映射到xml属性而不是xml元素.
xml数据中的moviestars(影星)属性和rating(上座率)元素没有被映射到Movie类中的任何东西上去. 当反串行化xml数据的时候, XmlSerializer只是简单的跳过它不能映射的项目. 当串行化一个对象的时候, 你可以在公共数据域和你希望XmlSerializer跳过的属性里加上xmlIgnore 属性.
xmlRoot, xmlElement, 和 xmlAttribute的属性类都应包括后缀"Attribute." 在我的属性申明里, 我使用了没有后缀的缩写形式. Theater和Movie类中的公共属性可以被改写成公共属性以求得更好的封装性. XmlSerializer 可以用相同的方式使用它们. 我在这里将它们做为数据域使用是为了使代码更紧凑.
将xml数据反串行化成对象
将xml数据加载到一个Theater对象里现在已经变得非常容易. 表D中的程序, xmlIn, 通过反串行化movie showings xml 数据创建一个Theater对象. 这个程序通过命令行执行, 你需要指明一个输入的xml文件.
表D
using System; using System.xml.Serialization; using System.IO; using Articles.TechRepublic.xmlSerialization; public class xmlIn { public static void Main( string[] args ) { if ( args.Length != 1 ) { Console.WriteLine( "Usage: xmlIn infile.xml" ); return; } try { // Deserialize the specified file to a Theater object. XmlSerializer xs = new XmlSerializer( typeof ( Theater ) ); FileStream fs = new FileStream( args[0], FileMode.Open ); Theater theater = (Theater)xs.Deserialize( fs ); // Display the theater object. Console.WriteLine ( theater ); } catch ( Exception x ) { Console.WriteLine( "Exception: " + x.Message ); } } } Output: >xmlIn theaterIn.xml The Camelot (888)665-2222 The Score (120 min) shows at 4:15 PM 7:05 PM 9:40 PM Shrek (100 min) shows at 4:00 PM 7:00 PM 9:40 PM |
using System; using System.xml; using System.xml.Serialization; using System.IO; using Articles.TechRepublic.xmlSerialization; public class xmlOut { // Returns a populated Theater object. public static Theater GetTheater() { Movie movie = new Movie(); movie.Title = "O Brother, Where Art Thou?"; movie.Minutes = 102; movie.Showings = new DateTime[3]; movie.Showings[0] = new DateTime( 2001, 8, 2, 13, 15, 0 ); movie.Showings[1] = new DateTime( 2001, 8, 2, 16, 30, 0 ); movie.Showings[2] = new DateTime( 2001, 8, 2, 19, 55, 0 ); Theater theater = new Theater(); theater.Name = "Hollywood Movies 10"; theater.Phone = "(972)555-154"; theater.Movies = new Movie[1]; theater.Movies[0] = movie; return theater; } public static void Main( string[] args ) { if ( args.Length != 1 ) { Console.WriteLine( "Usage: xmlOut outfile.xml" ); return; } try { Theater theater = GetTheater(); // Serialize the Theater object to an xml file. XmlSerializer xs = new XmlSerializer( typeof ( Theater ) ); FileStream fs = new FileStream( args[0], FileMode.Create ); xs.Serialize( fs, theater ); } catch ( Exception x ) { Console.WriteLine( "Exception: " + x.Message ); } } } Invocation: >xmlOut theaterOut.xml theaterOut.xml contents: <?xml version="1.0"?> <theater xmlns:xsi=http://www.w3.org/2001/xmlSchema-instance xmlns:xsd="http://www.w3.org/2001/xmlSchema"> <name>Hollywood Movies 10</name> <phone>(972)555-154</phone> <movie minutes="102"> <title>O Brother, Where Art Thou?</title> <showing>13:15:00.0000000-06:00</showing> <showing>16:30:00.0000000-06:00</showing> <showing>19:55:00.0000000-06:00</showing> </movie> </theater> |
主要的程序代码都放在Main 函数的try代码段里. 首先通过GetTheater帮助函数创建一个Theater对象. 然后, 打开一个文件流来生成输出的xml 文件. 调用XmlSerializer的Serialize方法, 传递给它文件流和Theater对象. 就是这样简单--xml文件生成了!
输出的theater 元素包含了为模板和模板实例命名空间生成的xml命名空间属性(xmlns), 虽然在这两个命名空间里这些数据并不代表任何东西. showing元素中的-06:00 指的是美国中部时间, 或者说GMT时间再减去个小时, 也就是我所在的时区.
移动数据是小菜一碟
XmlSerializer 使得在对象和xml间移动数据变得非常容易, 只要在类里加上xml映射属性. 但是对于更复杂的对象模型, 手工的创建xml映射会变得非常的麻烦而且容易出错. 在我的下一篇文章里, 我将告诉你如何自动化这个工作并实现对你的xml数据的更严格的控制.