如何使用XmlSerializer类控制串行化

ZDNet软件频道 时间:2009-02-04 作者: | 中国IT实验室 我要评论()
本文关键词:串行化 控制 XmlSerializer xml 软件
人们一直高喊XML是解决系统互联问题的关键, 而.NET framework 也为处理XML数据提供了许多不同的类库. XmlDocument 类能让你像处理文件一样处理XML 数据
人们一直高喊xml是解决系统互联问题的关键, 而.NET framework 也为处理xml数据提供了许多不同的类库. xmlDocument 类能让你像处理文件一样处理xml 数据, 而xmlReader, xmlWriter, 和它们的派生类使你能够将xml 数据做为数据流处理. XmlSerializer 则提供了另外的方法, 它使你能够将自己的对象串行和反串行化xml. 串行化数据既能够让你像处理文件一样对数据进行随机存取, 同时又能够跳过你不感兴趣的元素. 在本文中, 我将向你展示如何使用XmlSerializer类以及如何在你的类中添加属性来控制串行化过程.

XmlSerializer
    XmlSerializer类存在于System.xml.Serialization命名空间的System.xml.dll中, 它用一种高度松散耦合的方式提供串行化服务. 你的类不需要继承特别的基类, 而且它们也不需要实现任何特别的接口. 相反的, 你只需要在你的类或者这些类的公共域以及读/写属性里加上自定义的属性. XmlSerializer 通过相反映射读取这些属性并用它们将你的类和类成员映射到xml元素和属性.

xml 映射到对象
考虑表A中的xml语句, 哪一个正确的描述了一家电影院中上映的电影呢?

表A
<?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
 
主要的程序代码都放在Main 函数的try代码段里. 首先创建一个XmlSerializer对象并指明一个System.Type 对象来告诉反串行化程序要创建的对象的类型. typeof操作符为Theater类返回一个System.Type 对象. 然后, 打开一个文件流读取输入的xml文件. 调用XmlSerializer的Deserialize方法, 并把文件流传递给它. Deserialize 返回对Theater对象的引用. Theater和Movie 对象中的ToString方法能够让你简单的输出它们.

将对象串行化xml
    从一个Theater对象生成xml数据同样是容易的. 表E中的程序,xmlOut, 就是将一个Theater对象串行化xml 文件里. 这个程序通过命令行执行, 你需要指明输出的xml文件.
表E
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数据的更严格的控制.


串行化

控制

XmlSerializer

xml

软件


百度大联盟认证黄金会员Copyright© 1997- CNET Networks 版权所有。 ZDNet 是CNET Networks公司注册服务商标。
中华人民共和国电信与信息服务业务经营许可证编号:京ICP证010391号 京ICP备09041801号-159
京公网安备:1101082134