65.9K
CodeProject 正在变化。 阅读更多。
Home

XML序列化和反序列化:第1部分

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.87/5 (160投票s)

2012 年 10 月 24 日

CPOL

5分钟阅读

viewsIcon

717684

使用C#的XML序列化和反序列化

引言

本文讨论了对象以 XML 格式进行序列化以及将 XML 文件反序列化回对象的过程。序列化是通过某种序列化数据格式(如 XML 或二进制格式)将对象的当前状态转换出去的过程。而反序列化则用于将数据(如 XML 或二进制数据)的字节转换为对象类型。序列化是将对象转换为易于传输的格式的过程。例如,您可以序列化一个对象并通过 HTTP 在客户端和服务器之间通过 Internet 传输它。在另一端,反序列化则从流中重建对象。XML 序列化会生成具有 `public` 属性和字段的强类型类,这些属性和字段将被转换为序列化格式(在本例中为 XML)以进行存储或传输。

让我们从一个基本示例开始。以下是一个需要序列化的简单类

public class AddressDetails
{
    public int HouseNo { get; set; }
    public string StreetName { get; set; }
    public string City { get; set; }
    private string PoAddress { get; set; }
}     

创建用于序列化的类时应注意以下几点

  1. XML 序列化仅序列化 `public` 字段和属性。
  2. XML 序列化不包含任何类型信息。
  3. 为了序列化对象,我们需要有一个默认/无参数构造函数。
  4. `ReadOnly` 属性不会被序列化。

序列化上述类的代码

public static void Main(string[] args) 
{ 
    AddressDetails details = new AddressDetails();
    details.HouseNo = 4;
    details.StreeName = "Rohini";
    details.City = "Delhi";
    Serialize(details);
}   
static public void Serialize(AddressDetails details)
{ 
    XmlSerializer serializer = new XmlSerializer(typeof(AddressDetails)); 
    using (TextWriter writer = new StreamWriter(@"C:\Xml.xml"))
    {
        serializer.Serialize(writer, details); 
    } 
}

`XmlSerializer`(位于 `System.Xml.Serialization` 命名空间)类用于序列化和反序列化。调用 `Serialize` 类方法。由于我们需要在文件中进行序列化,因此我们创建了一个“`TextWriter`”。由于 `TextWriter` 实现了 `IDisposable`,因此我们使用了 `using` 语句,这样就不需要关闭写入器了。

序列化后的输出是

<?xml version="1.0" encoding="utf-8"?> 
<AddressDetails>
  <HouseNo>4</HouseNo>
  <StreetName>Rohini</StreetName>
  <City>Delhi</City>
</AddressDetails>

在这里,在 XML 中,我们可以看到 XML 创建的 `Head` 标签与类名相同,子标签名称与 `AddressDetails` 类中的属性相同。每个 `public` 属性都以创建的 XML 中 `Tags` 的形式显示。我们可以看到这里只显示了 `public` 字段。

XML 序列化和属性

序列化期间可用的常见属性有

  • `XmlAttribute`:此成员将被序列化为 XML 属性。
  • `XmlElement`:字段将被序列化为 XML 元素。
  • `XmlIgnore`:在序列化过程中将忽略该字段。
  • `XmlRoot`:表示 XML 文档的根元素。

使用 XmlElement

进一步地,如果我们希望 XML 中的 `Tag` 名称与类属性 `Name` 不同。我们可以在类结构中引入 `XmlElement` 属性。

public class AddressDetails
{ 
    [XmlElement("Number")]
    public int HouseNo { get; set; }
    [XmlElement("Street")] 
    public  string StreetName { get; set; } 
    [XmlElement("CityName")]
}

`[XmlElement("Number")]` 指定属性 `HouseNo` 将在 XML 文件中以“`Number`”的 `Tag` 名称进行序列化。它帮助我们在 XML `Tag` 名称和类属性名称之间进行映射。下面给出了带有自定义标签名称的 XML `string` 的结果

<AddressDetails> 
  <Number>4</Number>
  <Street>Rohini</Street>
  <CityName>Delhi</CityName>
</AddressDetails>

使用 XmlAttribute

如果我们希望属性 `HouseNo` 作为 `AddressDetails` 标签的**属性**出现,那么我们应该使用 `XmlAttribute`。`XmlAttribute` 将 `object` 属性序列化为父标签的属性。以下代码说明了此功能

public class AddresssDetails
{ 
    [XmlAttribute]("Number")]
    public int HouseNo { get; set; }
    [XmlElement("Street")] 
    public  string StreetName { get; set; } 
    [XmlElement("CityName")]
    public string City {get; set;}
}

代码的 XML 序列化输出将是

<AddressDetails Number="4">
  <Street>Rohini</Street>
  <CityName>Delhi</CityName>
</AddressDetails>

注意,由于类属性 `HouseNo` 被指定为 `XMLAttribute`,因此该属性是父标签 `AddressDetails` 的属性。

使用 XmlIgnore

默认情况下,所有 `public` 字段和 `public` 读/写属性都会被 `X`mlSerializer 序列化。也就是说,每个 `public` 字段或属性的值会以 XML 元素或 XML 属性的形式持久化到 XML 文档实例中。为了覆盖此属性,请对其应用 `XmlIgnore` 属性。这将从 XML 中删除该元素。下面的代码对此进行了说明

public class AddressDetails
{
    [XmlElement("Number")]
    public int HouseNo;
    [XmlElement("Street")]
    public string StreetName;
    [XmlIgnore]
    public string City;
}

在这里,我们可以看到属性 `City` 包含 `XmlIgnore` 属性。创建的 XML 结果将不包含 `City` 标签。

<AddressDetails>
    <Number>4</Number>
    <Street>ABC</Street>
</AddressDetails>

请注意,由于 `XmlIgnore` 属性置于 `City` 属性上,因此该属性未被序列化。

使用 XmlRoot

每个 XML 都有一个 `root` 元素。默认情况下,`root` 元素的名称与序列化的类名称相同。为了给 XML 的**根元素指定自定义名称**,我们使用 `XmlRoot` 属性。下面提供了此属性的实现

[XmlRoot("Root")]
public class AddressDetails
{
    [XmlElement("Number")]
    public int HouseNo;
    [XmlElement("Street")]
    public string StreetName;
    [XmlElement("CityName")]
    public string City;
} 

在这里,我们可以看到 `XmlRoot` 属性置于 `AddressDetails` 类之上。这将覆盖默认的序列化行为,该行为将 XML 标签的根名称与类名称相同。XML 现在将“`Root`”作为根标签。

<Root>
  <HouseNo>4</HouseNo>
  <StreetName>Rohini</StreetName>
  <City>Delhi</City> 
</Root>   

请注意,这里的根标签现在是“`Root`”,而不是类名称。

对象列表的序列化

现在,让我们尝试将**一个 `AddressDetails` 对象列表**序列化到 XML 文件中

public static void Main(string[] args) 
{ 
    List<AddressDetails> AddressList = new List<AddressDetails>();
    AddressDetails detail1 = new AddressDetails();
    detail1.HouseNo ="4";
    detail1.StreetName = "ABC";
    detail1.City = "Delhi";
 
    AddressDetails detail2 = new AddressDetails(); 
    detail2.HouseNo ="3";
    detail2.StreetName = "ABCD";
    detail2.City = "New Delhi";
 
    AddressList.Add(detail1); 
    AddressList.Add(detail2); 
    Serialize(AddressList); 
}   
public void Serialize(List<AddressDetails> list)
{
    XmlSerializer serializer = new XmlSerializer(typeof(List<AddressDetails>));
    using ( TextWriter writer = new StreamWriter( @"C:\Xml.txt")
    {
        serializer.Serialize(writer, list) 
    }  
}

以上执行的 XML 输出将是

<ArrayOfAddressDetails>
  <AddressDetails>
    <Number>4</Number>
    <Street>ABC</Street>
    <CityName>Delhi</CityName>
  </AddressDetails>
  <AddressDetails>
    <Number>3</Number>
    <Street>ABCD</Street>
    <CityName>New Delhi</CityName>
  </AddressDetails>
</ArrayOfAddressDetails>

请注意,生成的 XML 提供了 `AddressDetails` 对象列表。

包含其他类对象的类的序列化

如果类结构是这样,一个类包含另一个类的对象,并且我们希望将该类对象也包含在序列化中。让我们看下面的例子

public class PersonalDetails
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Address address;
}
public class Address
{
    public int HouseNo { get; set; }
    public string StreetName { get; set; }
    public string City { get; set; }
}

这是 `PersonalDetails` 类的序列化方式

<PersonalDetails>
  <Name>Mayank</Name>
  <Age>24</Age>
  <Address>
    <HouseNo>4</HouseNo>
    <StreetName>Rohini</StreetName>
    <City>Delhi</City>
  </Address>
</PersonalDetails>

为了增加复杂性,让我们尝试创建以下 XML 结构

<PersonalDetails>
  <Name>Mayank</Name>
  <Age>24</Age>
  <Address HouseNo="4">
    <StreetName>Rohini</StreetName>
    <City>Delhi</City>
  </Address>
</PersonalDetails>

观察这里的区别在于,我们需要将“`HouseNo`”作为 `Address` 标签的属性。让我们看看为了创建这种结构,类中会发生什么变化

public class PersonalDetails
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Address address;
    public PersonalDetails()
    {
        Name = "Mayank";
        Age = 24;
        address = new Address();
    }    
}
public class Address
{
    [XmlAttribute("HouseNo")]
    public int HouseNo { get; set; }
    public string StreetName { get; set; }
    public string City { get; set; }
    public Address()
    {
        HouseNo = 8;
        StreetName = "Rohini";
        City = "Delhi";
    }
}

根据要求,我们希望将“`HouseNo`”作为 XML 属性,而不是普通的 `XMLElement`。因此,我们在属性上引入了“`XmlAttribute`”。

让我们尝试创建以下 XML 结构

<PersonalDetails>
  <Name>Mayank</Name>
  <Age>24</Age>
  <address HouseNo="8">Rohini</address>
</PersonalDetails>

这里的区别在于,我们需要将**StreetName 作为 XML 节点“`address`”的 innertext**。因此,为了创建这种结构,我们有了另一个属性 `XmlText`。这有助于我们将特定属性添加为标签的 `innertext`。

因此,创建这种结构的 K 的代码是

public class PersonalDetails
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Address address;
}
public class Address
{
    [XmlAttribute("HouseNo")]
    public int HouseNo { get; set; }
    [XmlText]
    public string StreetName { get; set; }
}

这里的“`XmlText`”属性将 `StreetName` 添加为“`address`”标签的 `InnerText`

XML 的反序列化

有关反序列化的详细信息,请参阅以下文章:XML 序列化和反序列化(第二部分)

结论

序列化是将对象转换为 XML 的非常有效的方式。这可以节省大量时间和精力。

© . All rights reserved.