XML 序列化与反序列化:第二部分






4.93/5 (76投票s)
XML 的序列化与反序列化
引言
我之前的文章 XML 序列化与反序列化(第一部分) 讨论了将对象序列化为 XML 格式。在这篇文章中,我们将讨论如何将 XML "反序列化" 回对象形式。反序列化用于将数据字节(如 XML 或二进制数据)转换为 "Object
" 类型。XML 文件可以使用反序列化重新转换回对象。
让我们从一个基本示例开始。这是需要反序列化的 XML 文件:
<AddressDetails>
<HouseNo>4</HouseNo>
<StreetName>Rohini</StreetName>
<City>Delhi</City>
</AddressDetails>
因此,为了反序列化这个 XML 文件,我们需要创建一个类:
public class Address
{
public int HouseNo { get; set; }
public string StreetName { get; set; }
public string City { get; set; }
}
这个类包含一个名为 `name` 的变量,它与 XML 标签相同,XML 标签的值默认会映射到类中的相应变量。类 "Address
" 中的 "HouseNo
" 将自动映射到 XML 标签 "HouseNo
"。
现在,让我们看一个将此 XML 映射到类对象的简单程序:
public static void Main(string[] args)
{
XmlSerializer deserializer = new XmlSerializer(typeof(Address));
TextReader reader = new StreamReader(@"D:\myXml.xml");
object obj = deserializer.Deserialize(reader);
Address XmlData = (Address)obj;
reader.Close();
}
"deserializer.Deserialize
" 函数用于反序列化 XML 文件中的 XML 数据。现在,由于我们将 XML 文件结构反序列化为对象形式,我们可以访问 XML 标签值了:
Address.HouseNo
Address.StreetName
Address.City
在创建用于反序列化的类时,应注意以下几点:
- 类变量/属性应始终声明为
public
。 - 为了反序列化,我们需要有一个默认/无参数构造函数。
任何没有 "默认/无参数" 构造函数的类都会导致错误,因为 "deserializer.Deserialize(reader)
" 没有提供向带参数构造函数传递值的方式。
在上面的代码中,我们有简单的 XML 元素,没有子元素。让我们进一步探索并处理一些更复杂的情况,即 XML 元素可能包含进一步的子标签:
让我们进一步复杂化情况,并尝试 "反序列化" 以下 "XML":
<?xml version="1.0"?>
<AddressDirectory>
<Address>
<HouseNo>1</HouseNo>
<StreetName>Pitampura</StreetName>
<City>Delhi</City>
</Address>
<Address>
<HouseNo>4</HouseNo>
<StreetName>Rohini</StreetName>
<City>Delhi</City>
</Address>
</AddressDirectory>
让我们看看这里的区别。在下面的 XML 中,我们有多个 "Address
" 标签。并且 Address
标签还包含进一步的子标签。因此,我们需要创建我们的类,以便它可以包含多个 "Address
" 标签及其子标签。让我们看看如何创建类:
public class AddressDirectory
{
[XmlElement("Address")]
public List<Address> addressList = new List<Address>();
}
public class Address
{
public int HouseNo { get; set; }
public string StreetName { get; set; }
public string City { get; set; }
}
请记住,在为任何标签的反序列化创建类时,我们只能深入一层。简单来说,举个例子。在上面的 XML 中,我们有 "AddressDirectory
" 标签。为了反序列化,我们为 "AddressDirectory
" 标签创建一个类。现在,这个类可以包含 "AddressDirectory
" XML 标签的以下详细信息:
- "
AddressDirectory
" 标签的属性(如果存在)。 - 它的子节点,例如 "
Address
"(只能访问 "Address
" 标签,不能深入到 "Address
" 标签的子节点)。 InnerText
(如果存在)。
类 AddressDirectory
无法提取关于 "Address
" 的子标签以及 "Address
" 标签的属性的信息。为了获取关于 "ChildNodes
" (子节点) 关于 "Address
" 标签的信息,我们需要创建另一个类来存储属性信息和childnode
信息(最多第一层)。
在这里,我们创建了一个类 AddressDirectory
,它映射到 "XML" 的根标签元素。根标签进一步包含 "Address
" 标签。我们可以在此处有多个 "Address
" 标签,因此我们在 "AddressDirectory
" 类中创建了一个类 "Address
" 的列表,以便可以存储多个 "Address
" 标签的信息。这里,在类中,我们看到 XmlElement
写在 addressList
上。此属性用于类变量的名称与 XML 文件中的名称不同,因此为了将类变量与 XML 标签映射,我们使用关键字 XmlElement
。我们将在文章后面讨论这一点。
我们将在文章后面看到更多关于此的示例。
反序列化 XML 需要执行的程序是:
XmlSerializer deserializer = new XmlSerializer(typeof(AddressDirectory));
TextReader reader = new StreamReader(@"D:\myXml.xml");
object obj = deserializer.Deserialize(reader);
AddressDirectory XmlData = (AddressDirectory)obj;
reader.Close();
结果对象 "XmlData
" 将包含一个 "Address
" 类型的对象列表。我们可以按如下方式访问第一个 Address
标签的数据:
XmlData.addressList[0].HouseNo;
XmlData.addressList[0].StreetName;
XmlData.addressList[0].City;
XML 可以进一步复杂化,让我们看看下面的 XML 文件结构及其类表示:
<?xml version="1.0"?>
<AddressDirectory>
<Owner>Mayank</Owner>
<Age>24</Age>
<Company>BIPL</Company>
<Address>
<HouseNo>1</HouseNo>
<StreetName>Pitampura</StreetName>
<City>Delhi</City>
</Address>
<Address>
<HouseNo>4</HouseNo>
<StreetName>Rohini</StreetName>
<City>Delhi</City>
</Address>
</AddressDirectory>
在这里,我们可以看到 "AddressDirectory
" 中除了 "Address
" 标签列表之外,还有一些额外的标签,如 "Owner
"、"Age
"、"Company
"。所以 XML 的类结构将是:
public class AddressDirectory
{
public string Owner { get; set; }
public string Age { get; set; }
public string Company { get; set; }
[XmlElement("Address")]
public List<Address> addressList = new List<Address>();
}
public class Address
{
public string HouseNo { get; set; }
public string StreetName { get; set; }
public string City { get; set; }
}
"AddressDirectory
" 标签的子节点存在于 AddressDirectory
类中,而 Address
标签的childnode
s 存在于 address
类中。
注意:这里重要的是要观察,类只能包含那些是其直接子节点的“标签值”,即 AddressDirectory
只能包含其直接子节点的信息,如 "Owner
"、"Company
"、"Age
" 和 "Address
"。但是,这里 "Address
" 进一步包含更多标签。 "Address
" 标签的子节点不能由类 "AddresssDirectory
" 表示。因此,我们需要为 "Address
" 标签创建另一个类,该类存储 "Address
" 类的childnode
信息。 "Address
" 类将进一步包含其直接childnode
"HouseNo
"、"StreetName
"、"City
" 的值。由于我们有多个 Address
标签,因此我们有一个 "List
" 的 "Address
" 类。
反序列化期间的 XML 属性
反序列化期间可能很有用的属性包括:
XmlElement
XmlAttribute
XmlText
这三个属性提供映射信息。它提供了关于 XML 标签的哪个元素将映射到类的哪个变量的信息。
观察以下 XML:
<?xml version="1.0" encoding="utf-8" ?>
<AddressDirectory id="1">
<DirectoryOwner>Mayank</DirectoryOwner>
<PinCode>110085</PinCode>
<Designation place="Delhi">Engineer</Designation>
<Address AddressId="12">
<HouseNo>4</HouseNo>
<StreetName>Rohini</StreetName>
<City>Delhi</City>
</Address>
<Address AddressId="13">
<HouseNo>4</HouseNo>
<StreetName>Rohini</StreetName>
<City>Delhi</City>
</Address>
</AddressDirectory>
让我们观察此 XML 文件的不同组成部分:
AddressDirectory
是 XML 文件的根节点。AddressDirectory
包含一个 "XmlAttribute
",名为 "id
",值为 "1
"。- "
AddressDirectory
" 包含 "XmlElement
",如DirectoryOwner
、Address
、Designation
、Address
。 - "
Designation
" 标签包含一个 "XmlAttribute
"("place
")和一个 "XmlText
"("Delhi
")。
因此,从上面的 XML 中,我们可以找出什么是 "XmlElement
"、"XmlAttribute
"、"XmlText
"。在反序列化这种复杂的 XML,其中可能包含所有这三个组件时,我们需要明确指定类变量存储的是 "Element
"、"Attribute
" 还是 "XmlText
"。
让我们尝试反序列化此 XML:
public class AddressDirectory
{
[XmlElement("DirectoryOwner")]
public string DirectoryOwner { get; set; }
[XmlElement("PinCode")]
public string PinCode { get; set; }
[XmlElement("Address")]
public List<Address> Address { get; set; }
[XmlElement("Designation")]
public Designation designation { get; set; }
}
在这里,我们将类变量 DirectoryOwner
映射到了 XML 文件的 DirectoryOwner
标签。
请注意,类 AddressDirectory
包含 AddressAttribute
标签的子节点。它只深入到第一层,即它无法检索 Designation
的属性值,也无法获取 Address
标签的子节点的信息。因此,为了提取这些信息,我们需要为 Address
和 Designation
创建另一个类。由于我们有多个 Address
标签,因此 AddressDirectory
中有一个 Address
类的列表。
让我们探索 Address
类和 Designation
类:
public class Designation { [XmlAttribute("place")] public string place { get; set; } [XmlText] public string JobType { get; set; } }
这里的 Designation
类包含两个变量,一个用于存储 innerText
,另一个用于存储 Designation
标签的 place
属性。
public class Addresse
{
[XmlAttribute("AddressId")]
public string AddressId { get; set; }
[XmlElement("HouseNo")]
public string HouseNo { get; set; }
[XmlElement("StreetName")]e
public string StreetName { get; set; }
[XmlElement("City")]
public string City { get; set; }
}
Address
类进一步包含一个变量,可以存储 Address
标签的属性和子节点详细信息。
反序列化 XML 需要执行的程序是:
XmlSerializer deserializer = new XmlSerializer(typeof(AddressDirectory));
TextReader reader = new StreamReader(@"D:\myXml.xml");
object obj = deserializer.Deserialize(reader);
AddressDirectory XmlData = (AddressDirectory)obj;
reader.Close();
还需要记住的一点是,关键字 XmlElement
、XmlAttribute
和 XmlText
用于将 XML 标签内的信息映射到类变量。类变量名可以与 XML 中的不同。例如:
[XmlElement("HouseNo")]
public string Number { get; set; }
在这里,我们可以看到 XML 元素 HouseNo
将被映射到类变量 Number
。
结论
反序列化和序列化是将对象转换为 XML 以及反之的一种非常有效的方法。这可以节省大量的时间和精力。