xml 是设计用于在各种不同的系统之间进行数据交换的技术。您可以轻松地在分布式组件之间传送xml,这归功于他的平台独立性、简介、基于文本、自描述格式,然而这些却很难构成可靠编程平台的基础。基于文本的数据没有强类型安全规则。程序员往往易受面向对象模式的诱惑,因为每个对象都属于某一类型,因为编译器可警惕潜在的类型问题,对象中封装的数据可以轻松的访问到。理想的编程环境是用面向对象的模型构建软件,但是充分利用xml在分布式组件(如在Internet 或 Messae Queue 中)之间优势。这就是xml串行化之所以重要的原因:它提供了一座桥梁,使您能够不露痕迹地将对象转换为xml,反之亦然。

        xml串行化是将数据的集合转换为信息流的过程。反串行化则是相反的过程:将信息流转换回原先生成该信息流的数据。有时将这两个相逆的过程称为脱水(dehydration)和水合(rehydration)。

下面将详细介绍以下内容:
1.xml串行化
2.如何将对象串行化为xml格式
3.用XmlSerializer类串行化对象图
4.用设计时间属性自定义串行化输出
5.在xml串行化期间处理命名空间
6.如何将xml表示反串行化为对象
7.用XmlSerializer类串行化和反串行化通用类型
8.通过使用新增的xml Serializer Gdnerator 工具改进串行化性能

串行化入门

串行化是运行时进程,将对象或对象的图转换为线性序列字节,然后可以将合成的内存块用于存储或通过特定协议在网络间传输。在.net framework 中,对象串行化可以有3种不同的输出格式:

Binary (二进制) -------- 将对象格式化为二进制
Simple Object Access Protocol (SOAP)  ---------- 将对象格式化为SOAP格式
XML  ------------ 将对象格式化为XML格式,从而可以传输到另一种应用程序中

运行时对象串行化(二进制和SOAP) 和 XML格式是非常不同的两种技术,不仅实现方式不同,更重要的目标不同。尽管如此,这两种形式都完成同一关键的事情:保存内容、内存外的活动对象,并从内存转移到其他任何存储介质。

注意:
System.Runtime.Serialization 命名空间中包含的格式化程序命名空间和类支持二进制和SOAP串行化。XML串行化主要由Sytem.Xml.Serialization命名空间中的XmlSerializer类支持。

串行化对于用简单的格式传输或存储复杂的数据很有用,例如,应用程序可以构建包含几十个对象的复杂数据结构,并将它串行化为文本字符串。然后可以通过网络将字符串传送到另一个程序。接受程序将反串行化文本,从而构建一个原始数据结构的副本。串行化不必将对象转换为文本。它可以将对象表示为二进制数据流。它也不必通过网络传送数据。串行化的这些用途有一个共同的特点:将可能非常复杂的数据通信转换为简单的串行表示,然后转换回来。

1.1 XmlSerializer
XmlSerializer.Serialize()方法的第一个参数是重写的,因此可以将XML串行化为Stream, TextWriter, XmlWriter
XmlSerializer 类在Sytem.Xml.Serialization命名空间的详细信息自己查询msdn,在这里不介绍了。

1.串行化对象

首先是创建要通过XmlSerializer 类串行化的类
                                                                        程序清单12-1

xml 之 十二 串行化using System;
xml 之 十二 串行化
xml 之 十二 串行化[Serializable]
xml 之 十二 串行化
public class Category
}

接下来就可以串行化该类并将其转换为xml格式。
                                                                        程序清单12-2
xml 之 十二 串行化<%@ Page Language="C#" %>
xml 之 十二 串行化
xml 之 十二 串行化
<%@ Import Namespace="System.IO" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Xml.Serialization" %>
xml 之 十二 串行化
xml 之 十二 串行化
<script runat="server">
xml 之 十二 串行化    
void Page_Load(object sender, System.EventArgs e)
>

打开Category.xml文件
xml 之 十二 串行化<?xml version="1.0" encoding="utf-8"?>
xml 之 十二 串行化
<Category xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
xml 之 十二 串行化  
<CategoryID>1</CategoryID>
xml 之 十二 串行化  
<CategoryName>Beverages</CategoryName>
xml 之 十二 串行化  
<Description>Soft drinks, coffees, teas, beers, and ales</Description>
xml 之 十二 串行化
</Category>

Category类所有公有字段都串行化到xml元素中,其名称和类声明中的字段名相同。所有这些元素包含在根目录Category 元素中,该元素映射回类的名称。

2.处理对象图

同样的机制也可以用来串行化相关对象的整个图。例如Category类可以将所有产品(属于同样的类别)封装为一个嵌套元素。

xml 之 十二 串行化using System;
xml 之 十二 串行化
xml 之 十二 串行化
public class Product
}

与Category类相似,product类也由一些公有属性组成。
把下面这行代码添加到Category类中。
public Product[] products;

xml 之 十二 串行化using System;
xml 之 十二 串行化[Serializable]
xml 之 十二 串行化
public class Category
}

现在,您想串行化Category类,那么也会产生要串行化的Products数组。
                                                                    程序清单12-5
xml 之 十二 串行化<%@ Page Language="C#" %>
xml 之 十二 串行化
xml 之 十二 串行化
<%@ Import Namespace="System.IO" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Xml.Serialization" %>
xml 之 十二 串行化
xml 之 十二 串行化
<script runat="server">
xml 之 十二 串行化    
void Page_Load(object sender, System.EventArgs e)
>

打开Category.xml文件
xml 之 十二 串行化<?xml version="1.0" encoding="utf-8"?>
xml 之 十二 串行化
<Category xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
xml 之 十二 串行化  
<CategoryID>1</CategoryID>
xml 之 十二 串行化  
<CategoryName>Beverages</CategoryName>
xml 之 十二 串行化  
<Description>Soft drinks, coffees, teas, beers, and ales</Description>
xml 之 十二 串行化  
<Products>
xml 之 十二 串行化    
<Product>
xml 之 十二 串行化      
<ProductID>1</ProductID>
xml 之 十二 串行化      
<ProductName>Chai</ProductName>
xml 之 十二 串行化      
<QuantityPerUnit>10 boxes x 20 bags</QuantityPerUnit>
xml 之 十二 串行化      
<UnitPrice>18</UnitPrice>
xml 之 十二 串行化      
<UnitsInStock>39</UnitsInStock>
xml 之 十二 串行化    
</Product>
xml 之 十二 串行化  
</Products>
xml 之 十二 串行化
</Category>

高级串行化

        在前面几个例子中,类的公有字段直接映射到输出xml文档的xml元素中。虽然这个一对一的映射方法对简单串行化场景有效,然而有时候却需要您自定义生成的输出。幸运的是,xml串行化使您可以自定义要创建的xml数据的最终的输出结果。

1.xml串行化属性(Attrbute)

XmlAttributes类表示.net framework 属性的集合,这个集合使您能够联系XmlSerializer类如何处理对象的完整控件

说明:
XmlAttributes类与SoapAttributes类相似,只有一点不同:XmlAttributes类的输出为xml格式,而SoapAttributes类返回带类型信息的SOAP编码消息。

XmlAttributes类的每个属性都对应于一个属性类。

xml 之 十二 串行化namespace System.Xml.Serialization
}


 xml串行化的一个好处是,它使您能够控制要生成的xml文档的结构。您可以将特殊属性(上表)应用到这个类的成员来完成该功能。下面显示了带xml串行化属性的Category类。

xml 之 十二 串行化using System;
xml 之 十二 串行化
using System.Xml;
xml 之 十二 串行化
using System.Xml.Serialization;
xml 之 十二 串行化
xml 之 十二 串行化[XmlRoot(
"CategoryRoot", Namespace = "http://www.wrox.com", IsNullable = false)]
xml 之 十二 串行化
public class Category
}

对Category类做了这些修改后,如果您从浏览器请求程序清单12-2中所示的aspx页时,打开生成的Category.xml应看到下面代码:
xml 之 十二 串行化<?xml version="1.0" encoding="utf-8"?>
xml 之 十二 串行化
<CategoryRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xml 之 十二 串行化              ID
="1" Name="Beverages" xmlns="http://www.wrox.com">
xml 之 十二 串行化  
<Description>Soft drinks, coffees, teas, beers, and ales</Description>
xml 之 十二 串行化
</CategoryRoot>

正如您所看到的,已经用XmlRoot属性类将根元素重命名为CategoryRoot。作为XmlRoot属性的一部分,您也可以为Namespace 和 IsNullable 属性指定值。然后,CategoryID、CategoryName 元素将被分别重命名为ID、Name,这两者也将作为属性创建。

2.用XmlAttributeOverride控制输出

前面介绍了如何用硬编码的xml串行化属性的方式来重写xml元素。

说明:
    在运行时重写xml元素的功能是非常有用的,可以是很多场景有用。设想将应用程序的目录更新内容用xml格式发送到感兴趣的聚会上。由于某些原因,有一个客户需要一种略微不同的格式。您可以用XmlAttributeOverrides类简单地自定义现有这套类即可,而不用写一整套不同的类来生成自定义格式。

        就本例而言,使用清单12-1显示的Category类。但是在串行化时,您将在Category类将CategoryID字段重命名为ID,同时将其作为xml属性添加,而不是作为xml元素添加。

XmlAttrite 对象收集所有想加入给定元素的重写。在这种情况下,新建一个XmlAttributeAttribute对象后,可以修改属性名称,并将结果对象存储在重写容器的XmlAttribute属性中。

                                                                程序清单 12-8
xml 之 十二 串行化<%@ Page Language="C#" %>
xml 之 十二 串行化
<%@ Import Namespace="System.IO" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Xml.Serialization" %>
xml 之 十二 串行化
xml 之 十二 串行化
<script runat="server">
xml 之 十二 串行化    
void Page_Load(object sender, System.EventArgs e)
>

打开生成的Category.xml应看到下面代码:
xml 之 十二 串行化<?xml version="1.0" encoding="utf-8"?>
xml 之 十二 串行化
<Category xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ID="1">
xml 之 十二 串行化  
<Name>Beverages</Name>
xml 之 十二 串行化  
<Description>Soft drinks, coffees, teas, beers, and ales</Description>
xml 之 十二 串行化
</Category>

注意:
    对于每个重写对象,需要一个独特的Xmlattribute对象。这就意味着如果试图重写两个元素,则需要创建两个不同的Xmlattribute对象,并将其体那家到XmlAttributeOverrides对象中。

3.用命名空间生成受限的名称

        通常,应用程序需要将新信息添加到已存在的xml文档中,或者已有的xml文档组合起来。为了避免在这些场合中的冲突,WC3联盟标准化了xml命名空间。您可以将命名空间看作元素和属性的最后一个名称。
        
        添加到由XmlSerializer生成的xml中的默认命名空间是xmlns:xsd="http://www.w3.org/2001/XMLSchema" 和 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 。通过创建XmlSerializerNamespaces对象并用一列命名空间和别名可以对默认的命名空间进行重写。

使用Category类

xml 之 十二 串行化using System;
xml 之 十二 串行化
using System.Xml;
xml 之 十二 串行化
using System.Xml.Serialization;
xml 之 十二 串行化
xml 之 十二 串行化[XmlRoot(Namespace 
= "http://northwind.com/category")]
xml 之 十二 串行化
public class Category
}

                                  程序清单12-9 使用XmlSerializerNamespaces生成受限的名称
xml 之 十二 串行化<%@ Page Language="C#" %>
xml 之 十二 串行化
<%@ Import Namespace="System.IO" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Xml" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Xml.Serialization" %>
xml 之 十二 串行化
xml 之 十二 串行化
<script runat="server">
xml 之 十二 串行化    
void Page_Load(object sender, System.EventArgs e)
>

删除xsd 和 xsi 声明

如果您以前曾经做过任何串行化,那么您一定会知道:当用XmlSerializer串行化类时将获得若干声明,这些声明作为结果xml的一部份,类似下面的输出:

<Category xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

正如您所见,xsd 和 xsi 命名空间声明被串行器放在输出结果中。要删除xsd 和 xsi 命名空间,需要创建一个空的XmlSerializerNamespaces类,并添加一个简单条目,指定一个空的命名空间前缀和命名空间url。代码如下:

XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add("", "");


4.串行化集合

集合类与数组类似,但是其长度不需要固定,可以容纳非相关的类型,是不同使用场景的最佳选择。.NET Framework 提供了大量用于System.Collection命名空间的集合,如ArrayList、Dictionary、或Hashtable 等只是其中一部分。
您也可以串行化多个对象的图。要串行化集合或数组,也必须向XmlSerializer对象提供关于集合的类型和其中的内容的一个或几个类型。例如要串行化的对象是ArrayList而其中的内容是Category和Product对象时。XmlSerializer类为这样的可能性准备了一个构造函数----它期待包含类的类型号,以及描述一些类的类型数组:

xml 之 十二 串行化<%@ Page Language="C#" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Collections" %>
xml 之 十二 串行化
<%@ Import Namespace="System.IO" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Xml" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Xml.Serialization" %>
xml 之 十二 串行化
xml 之 十二 串行化
<script runat="server">
xml 之 十二 串行化    
void Page_Load(object sender, System.EventArgs e)

 

然后可以创建一个流,并和以前一样串行化该流。

串行化自定义集合

XmlSerializer也可以处理自定义集合对象,只要这些对象实现这两个.NET Framework 的集合接口之一:IEnumerable 或 ICollection 。.NET Framework提供的所有集合将实现这些接口,因此您可以串行化或反串行化这些集合,而不必增加额外工作。

说明:
只要符合一些条件,像集合(实现ICollection接口的对象)这样的容器对象的内容将被自动串行化;Add方法必须采用简单的正行参数。除了选择适当的对象类型外,当然,您必须确保集合的内容本身符合xml串行化需求,需求如下:每个类必须提供一个默认的构造函数,您应该提供一种通过可用的公开成员或属性访问类中的方式。

                                                程序清单12-10 CategoriesList类的实现

xml 之 十二 串行化using System;
xml 之 十二 串行化
using System.Collections;
xml 之 十二 串行化
using System.Xml.Serialization;
xml 之 十二 串行化
xml 之 十二 串行化
public class CategoriesList
}

                                       程序清单12-11 串行化CategoriesList对象

xml 之 十二 串行化<%@ Page Language="C#" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Collections" %>
xml 之 十二 串行化
<%@ Import Namespace="System.IO" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Xml.Serialization" %>
xml 之 十二 串行化
xml 之 十二 串行化
<script runat="server">
xml 之 十二 串行化    
void Page_Load(object sender, System.EventArgs e)
>

产生的xml结果
xml 之 十二 串行化<?xml version="1.0" encoding="utf-8"?>
xml 之 十二 串行化
<CategoriesList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
xml 之 十二 串行化  
<Categories>
xml 之 十二 串行化    
<Category>
xml 之 十二 串行化      
<CategoryID>1</CategoryID>
xml 之 十二 串行化      
<CategoryName>Beverages</CategoryName>
xml 之 十二 串行化      
<Description>Soft drinks, coffees, teas, beers, and ales</Description>
xml 之 十二 串行化    
</Category>
xml 之 十二 串行化    
<Category>
xml 之 十二 串行化      
<CategoryID>2</CategoryID>
xml 之 十二 串行化      
<CategoryName>Condiments</CategoryName>
xml 之 十二 串行化      
<Description>Sweet and savory sauces, relishes, spreads, and seasonings</Description>
xml 之 十二 串行化    
</Category>
xml 之 十二 串行化  
</Categories>
xml 之 十二 串行化
</CategoriesList>

1.3 反串行化xml

要反串行化文件Category.xml(在前面的示例中创建的)中的Category对象,您可以直接打开文件流、初始XmlSerializer,并调用Deserialize。

                                            程序清单12-12 将xml文件反串行化为对象

xml 之 十二 串行化<%@ Page Language="C#" %>
xml 之 十二 串行化
xml 之 十二 串行化
<%@ Import Namespace="System.IO" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Xml.Serialization" %>
xml 之 十二 串行化
xml 之 十二 串行化
<script runat="server">
xml 之 十二 串行化    
void Page_Load(object sender, System.EventArgs e)
>

5.处理XmlSerializer引发的事件

 如果输入流不符合预期的形式,那么反串行化过程将试图尽最大能力恢复,但是当过程完成时,作为结果的一个或多个对象可以设置为空值,为了帮助处理这些情况,XmlSerializer类发布了4个您可以遇到的事件。
 
XmlSerializer类的事件
UnknownAttribute  当 XmlSerializer 在反序列化过程中遇到未知类型的 XML 属性 (Attribute) 时发生。 
UnknownElement  当 XmlSerializer 在反序列化过程中遇到未知类型的 XML 元素时发生。 
UnknownNode  当 XmlSerializer 在反序列化过程中遇到未知类型的 XML 节点时发生。 
UnreferencedObject  在反序列化 SOAP 编码的 XML 流的过程中发生,此时 XmlSerializer 遇到未使用(或未引用)的识别类型。

通过创建适当的委托,可捕获这些事件。

                                     程序清单12-13 处理由XmlSerializer类引发的事件

xml 之 十二 串行化<%@ Page Language="C#" %>
xml 之 十二 串行化
xml 之 十二 串行化
<%@ Import Namespace="System.IO" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Xml" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Xml.Serialization" %>
xml 之 十二 串行化
xml 之 十二 串行化
<script runat="server">
xml 之 十二 串行化    
void Page_Load(object sender, System.EventArgs e)
>

该代码假定Category类的声明如下。
public class Category
{
 public long CategoryID;
 public string CategoryName;
}
正如前面所见,前面示例中用到的Description字段在Category类中消失了。作为程序清单12-13中的xml输入文档使用的xml文件内容如下:
xml 之 十二 串行化<?xml version="1.0" encoding="utf-8"?>
xml 之 十二 串行化
<Category xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
xml 之 十二 串行化  
<CategoryID>1</CategoryID>
xml 之 十二 串行化  
<Name>Beverages</Name>
xml 之 十二 串行化  
<Description>Soft drinks, coffees, teas, beers, and ales</Description>
xml 之 十二 串行化
</Category>

输出结果如下:

Unknown Element:
Unknown Element Name: Description
Unknown Element Value: Soft drinks, coffees, teas, beers, and ales

Result of Deserialization:
CategoryID: 1
Category Name: Beverages

注意:XmlElementEventArgs对象提供了名为ObjectBeingDeserialized的属性,使您可以在反串行化期间引用Category对象。当您想执行一些基于对象将填充的内容时,非常有用。

6.用反串行化映射SQL Server 数据

xml 文档

xml 之 十二 串行化<Contacts>
xml 之 十二 串行化  
<ContactID>2</ContactID>
xml 之 十二 串行化  
<FirstName>Catherine</FirstName>
xml 之 十二 串行化  
<MiddleName>R.</MiddleName>
xml 之 十二 串行化  
<LastName>Abel</LastName>
xml 之 十二 串行化  
<EmailAddress>catherine0@adventure-works.com</EmailAddress>
xml 之 十二 串行化
</Contacts>

程序清单12-4 Contace类
xml 之 十二 串行化using System;
xml 之 十二 串行化
using System.Xml;
xml 之 十二 串行化
using System.Xml.Serialization;
xml 之 十二 串行化
xml 之 十二 串行化
xml 之 十二 串行化[XmlRoot(
"Contacts")]
xml 之 十二 串行化
public class Contact
}

程序清单12-5 使用Contace对象将Contact数据映射到AdventureWorks数据库中
xml 之 十二 串行化<%@ Page Language="C#" %>
xml 之 十二 串行化
xml 之 十二 串行化
<%@ Import Namespace="System.Collections" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Web.Configuration" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Data.SqlClient" %>
xml 之 十二 串行化
<%@ Import Namespace="System.IO" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Xml" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Xml.Serialization" %>
xml 之 十二 串行化
xml 之 十二 串行化
<script runat="server">
xml 之 十二 串行化    
void Page_Load(object sender, System.EventArgs e)
>

输出结果:

Unknown Element:
Unknown Element Name: EmailAddress
Unknown Element Value: catherine0@adventure-works.com

Result of Deserialization:
ID: 2
First Name: Catherine
Middle Name: R.
Last Name: Abel

1.4 泛型和XML串行化

 CLR使用.NET Framwork2.0 大大增强表达力,泛型类型可增加对运行时的完全支持。xml串行化已延伸到串行化和反串行化的通用类型。

现分析一下泛型类型的代码,见程序清单12-16

xml 之 十二 串行化using System;
xml 之 十二 串行化
using System.Collections;
xml 之 十二 串行化
using System.Xml.Serialization;
xml 之 十二 串行化
xml 之 十二 串行化[XmlRoot(
"NameValuePair")]
xml 之 十二 串行化
public class NameValue<KeyType, ValueType>
}

程序清单12-17 用泛型执行串行化和反串行化
xml 之 十二 串行化<%@ Page Language="C#" %>
xml 之 十二 串行化
xml 之 十二 串行化
<%@ Import Namespace="System.IO" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Xml.Serialization" %>
xml 之 十二 串行化
xml 之 十二 串行化
<script runat="server">
xml 之 十二 串行化    
xml 之 十二 串行化    
private string _xmlFilePath = @"C:\Data\NameValue.xml";
xml 之 十二 串行化
xml 之 十二 串行化    
void Serialize(object sender, EventArgs e)
>

串行化泛型集合


除了创建简单的泛型类型外,您还可以创建强类型化泛型集合,这些集合的类型安全和性能比非泛型的强类型化集合更好。System.Collection.Generic命名空间包含若干用于定义泛型集合的接口和类。看一下下列代码,理解如何用List类创建强类型化的类别集合对象。
 List<Category> list = new List<Category>();
 
 程序清单12-18 Serializing Typed Generics Collections
 
xml 之 十二 串行化<%@ Page Language="C#" %>
xml 之 十二 串行化
xml 之 十二 串行化
<%@ Import Namespace="System.IO" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Collections.Generic" %>
xml 之 十二 串行化
<%@ Import Namespace="System.Xml.Serialization" %>
xml 之 十二 串行化
xml 之 十二 串行化
<script runat="server">   
xml 之 十二 串行化    
void Page_Load(object sender, EventArgs e)

相关文章:

  • 2021-06-12
  • 2022-01-01
  • 2022-12-23
  • 2022-12-23
  • 2022-02-01
  • 2021-09-02
猜你喜欢
  • 2022-12-23
  • 2021-08-08
  • 2022-01-10
  • 2021-07-31
  • 2022-12-23
  • 2021-11-05
  • 2021-07-19
相关资源
相似解决方案