XmlReader类是组成.NET的关键技术之一,极大地方便了开发人员对Xml的操作。通过本文您将对XmlReader有一个很好的认识,并将其应用到实际开发中。
XmlReader 类是一个提供对 XML 数据的非缓存、只进只读访问的抽象基类。该类符合 W3C 可扩展标记语言 (XML) 1.0 和 XML 中的命名空间的建议。
XmlReader 类支持从流或文件读取 XML 数据。该类定义的方法和属性使您可以浏览数据并读取节点的内容。
XmlReader类是一个抽象类,XmlTextReader,XmlValidatingReader,和XmlNodeReader类都继承自XmlReader类。XmlReader类有很多方法和属性用来读取XML文件的内容、查找XML元素的深度、判断当前元素的内容是否为空,以及导航XML的属性等。
我们可以通过Create方法来创建一个XmlReader实例,也可以通过XmlReaderSettings类来配置XmlReader对象。使用XmlReaderSettings类的属性启用或禁用XmlReader对象的特定功能,然后将XmlReaderSettings对象传递给Create方法。
MSDN建议: 尽管在 .NET Framework 2.0 版中,Microsoft .NET Framework 包括 XmlReader 类的具体实现,例如 XmlTextReader、XmlNodeReader 和 XmlValidatingReader类,但是,我们建议您使用 Create 方法创建 XmlReader 实例。
通过使用 Create 方法和 XmlReaderSettings 类,您将得到下列好处:
提示:XmlReaderSettings 类的属性设置可以参考:http://msdn.microsoft.com/zh-cn/library/9khb6435(v=vs.80).aspx
实例化XmlReader:
1 XmlReaderSettings settings = new XmlReaderSettings();
2 settings.ConformanceLevel = ConformanceLevel.Fragment;
3 settings.IgnoreWhitespace = true;
4 settings.IgnoreComments = true;
5 XmlReader reader = XmlReader.Create("books.xml", settings);
XmlResolver类用于定位并访问XmlReader对象所需的任何资源。XmlResolver可以用于执行以下操作:
注意:如果未指定 XmlResolver,创建的读取器将使用没有用户凭据的默认 XmlUrlResolver。XmlUrlResover解析由统一资源标识符 (URI) 命名的外部 XML 资源,是 System.Xml 命名空间中的所有类的默认解析器。
以下代码创建一个 XmlReader 实例,使用具有默认凭据的 XmlUrlResolver。
1 // Create a resolver with default credentials.
2 XmlUrlResolver resolver = new XmlUrlResolver();
3 resolver.Credentials = System.Net.CredentialCache.DefaultCredentials;
4
5 // Set the reader settings object to use the resolver.
6 settings.XmlResolver = resolver;
7
8 // Create the XmlReader object.
9 XmlReader reader = XmlReader.Create("http://ServerName/data/books.xml", settings);
读取数据是处理XML文件最终目的,因此也是本文最重要的部分。下面将详细讨论如何通过XmlReader来读取Xml数据。
XmlReader 类提供了对 XML 流或文件的只进访问。当前节点是读取器当前所处的 XML 节点。所有调用的方法和执行的操作与当前节点相关,所有检索到的属性反映当前节点的值。
读取器通过调用一种读取方法(read方法)前进。重复调用该读取方法可以将读取器移至下一个节点。此类调用通常在 While 循环内执行。
下面的示例显示了如何在流中定位来确定当前的节点类型。
1 reader.MoveToContent();
2 // Parse the file and display each of the nodes.
3 while (reader.Read()) {
4 switch (reader.NodeType) {
5 case XmlNodeType.Element:
6 Console.Write("<{0}>", reader.Name);
7 break;
8 case XmlNodeType.Text:
9 Console.Write(reader.Value);
10 break;
11 case XmlNodeType.CDATA:
12 Console.Write("<![CDATA[{0}]]>", reader.Value);
13 break;
14 case XmlNodeType.ProcessingInstruction:
15 Console.Write("<?{0} {1}?>", reader.Name, reader.Value);
16 break;
17 case XmlNodeType.Comment:
18 Console.Write("<!--{0}-->", reader.Value);
19 break;
20 case XmlNodeType.XmlDeclaration:
21 Console.Write("<?xml version='1.0'?>");
22 break;
23 case XmlNodeType.Document:
24 break;
25 case XmlNodeType.DocumentType:
26 Console.Write("<!DOCTYPE {0} [{1}]", reader.Name, reader.Value);
27 break;
28 case XmlNodeType.EntityReference:
29 Console.Write(reader.Name);
30 break;
31 case XmlNodeType.EndElement:
32 Console.Write("</{0}>", reader.Name);
33 break;
34 }
35 }
提示:XmlNodeType为节点类型,详细信息可参考http://msdn.microsoft.com/zh-cn/library/3k5w5zc3(v=vs.80).aspx
下表介绍 XmlReader 类为处理元素提供的方法和属性。
成员名称 | 说明 |
---|---|
IsStartElement | 检查当前节点是否是开始标记或空的元素标记。 |
ReadStartElement | 检查当前节点是否为元素并将读取器推进到下一个节点。 |
ReadEndElement | 检查当前节点是否为结束标记并将读取器推进到下一个节点。 |
ReadElementString | 读取纯文本元素。 |
ReadToDescendant | 将 XmlReader 前进到具有指定名称的下一个子代元素。 |
ReadToNextSibling | 将 XmlReader 前进到具有指定名称的下一个同辈元素。 |
IsEmptyElement | 检查当前元素是否包含空的元素标记。此属性使您能够确定下面各项之间的差异: <item num="123"/>(IsEmptyElement 为 true。) <item num="123">(IsEmptyElement 为 false,尽管元素内容是空的。) 也就是说,IsEmptyElement 只是报告源文档中的元素是否包含结束元素标记。 |
也就是说,IsEmptyElement 只是报告源文档中的元素是否包含结束元素标记。
以下代码使用 ReadStartElement 和 ReadString 方法读取元素。
1 using (XmlReader reader = XmlReader.Create("book3.xml")) {
2
3 // Parse the XML document. ReadString is used to
4 // read the text content of the elements.
5 reader.Read();
6 reader.ReadStartElement("book");
7 reader.ReadStartElement("title");
8 Console.Write("The content of the title element: ");
9 Console.WriteLine(reader.ReadString());
10 reader.ReadEndElement();
11 reader.ReadStartElement("price");
12 Console.Write("The content of the price element: ");
13 Console.WriteLine(reader.ReadString());
14 reader.ReadEndElement();
15 reader.ReadEndElement();
16
17 }
XmlReader 类提供了各种方法和属性来读取属性。属性在元素上最常见。但是,XML 声明和文档类型节点上也允许使用属性。
在位于某个元素节点上时,使用 MoveToAttribute 方法可以浏览该元素的属性列表。调用了 MoveToAttribute 之后,节点属性(例如 Name、NamespaceURI、Prefix 等)将反映该属性的属性,而不是其所属的包含元素的属性。
下表介绍专门为处理属性而设计的方法和属性。
成员名 | 说明 |
---|---|
AttributeCount | 获取元素的属性列表。 |
GetAttribute | 获取属性的值。 |
HasAttributes | 获取一个值,该值指示当前节点是否有任何属性。 |
IsDefault | 获取一个值,该值指示当前节点是否是从 DTD 或架构中定义的默认值生成的属性。 |
Item | 获取指定属性的值。 |
MoveToAttribute | 移动到指定的属性。 |
MoveToElement | 移动到拥有当前属性节点的元素。 |
MoveToFirstAttribute | 移动到第一个属性。 |
MoveToNextAttribute | 移动到下一个属性。 |
ReadAttributeValue | 将属性值分析为一个或多个 Text、EntityReference 或 EndEntity 节点。 |
实例1:使用 AttributeCount 属性读取某个元素的所有属性。
1 // Display all attributes.
2 if (reader.HasAttributes) {
3 Console.WriteLine("Attributes of <" + reader.Name + ">");
4 for (int i = 0; i < reader.AttributeCount; i++) {
5 Console.WriteLine(" {0}", reader[i]);
6 }
7 // Move the reader back to the element node.
8 reader.MoveToElement();
9 }
实例2:在 While 循环中使用 MoveToNextAttribute 属性读取某个元素的所有属性。
1 if (reader.HasAttributes) {
2 Console.WriteLine("Attributes of <" + reader.Name + ">");
3 while (reader.MoveToNextAttribute()) {
4 Console.WriteLine(" {0}={1}", reader.Name, reader.Value);
5 }
6 // Move the reader back to the element node.
7 reader.MoveToElement();
8 }
实例3:按名称获取属性的值。
1 reader.ReadToFollowing("book");
2 string isbn = reader.GetAttribute("ISBN");
3 Console.WriteLine("The ISBN value: " + isbn);
提示:ReadToFollowing方法表示一直读取,直到找到具有指定限定名的元素。使用此方法可以提高在 XML 文档中查找命名元素的速度。 如果找到匹配的元素,它让读取器前进到与指定名称匹配的下一个后续元素,并返回 true。
1. 使用Value属性
Value 属性可以用于获取当前节点的文本内容。返回的值取决于当前节点的节点类型。下表介绍每种可能的节点类型所返回的内容。
节点类型 | 值 |
---|---|
Attribute | 属性的值。 |
CDATA | CDATA 节的内容。 |
Comment | 注释的内容。 |
DocumentType | 内部子集。 |
ProcessingInstruction | 全部内容(不包括指令目标)。 |
SignificantWhitespace | 混合内容模型中任何标记之间的空白。 |
Text | 文本节点的内容。 |
Whitespace | 标记之间的空白。 |
XmlDeclaration | 声明的内容。 |
所有其他节点类型 | 空字符串。 |
2.利用ReadString方法
ReadString 方法以字符串的形式返回元素或文本节点的内容。
如果 XmlReader 位于某个元素上,ReadString 将所有文本、有效空白、空白和 CDATA 节节点串联在一起,并以元素内容的形式返回串联的数据。当遇到任何标记时,读取器停止。这可以在混合内容模型中发生,也可以在读取元素结束标记时发生。
如果 XmlReader 位于某个文本节点上,ReadString 将对文本、有效空白、空白和 CDATA 节节点执行相同的串联。读取器在第一个不属于以前命名的类型的节点处停止。如果读取器定位在属性文本节点上,则 ReadString 与读取器定位在元素开始标记上时的功能相同。它返回所有串联在一起的元素文本节点。
3.利用ReadInnerXml方法
ReadInnerXml 方法返回当前节点的所有内容(包括标记)。不返回当前节点(开始标记)和对应的结束节点(结束标记)。例如,如果包含 XML 字符串 <node>this<child id="123"/></node>,ReadInnerXml 将返回 this<child id="123"/>。
节点类型 | 初始位置 | XML 片断 | 返回值 | 位于下列内容之后 |
---|---|---|---|---|
Element | 在 item1 开始标记上。 | <item1>text1</item1><item2>text2</item2> | text1 | 在 item2 开始标记上。 |
Attribute | 在 attr1 属性节点上。 | <item attr1="val1" attr2="val2">text</item> | val1 | 保留在 attr1 属性节点上。 |
如果读取器定位在叶节点上,则调用 ReadInnerXml 等效于调用 Read。
4.利用ReadOuterXml方法
ReadOuterXml 方法返回当前节点及其所有子级的所有 XML 内容,包括标记。其行为与 ReadInnerXml 类似,只是同时还返回开始标记和结束标记。
使用上表中的值,如果读取器位于 item1 开始标记上,ReadOuterXml 将返回 <item1>text1</item1>。如果读取器位于 attr1 属性节点上,ReadOuterXml 将返回 attr1="val1"。
将菜单food.xml的数据解析,并按一定的格式显示出来。
food.xml数据格式如下:
1 <?xml version="1.0" encoding="utf-8" ?>
2 <breakfast_menu>
3 <food>
4 <name>Belgian Waffles</name>
5 <price>$5.95</price>
6 <description>two of our famous Belgian Waffles with plenty of real maple syrup</description>
7 <calories>650</calories>
8 </food>
9 <food>
10 <name>Strawberry Belgian Waffles</name>
11 <price>$7.95</price>
12 <description>light Belgian waffles covered with strawberries and whipped cream</description>
13 <calories>900</calories>
14 </food>
15 </breakfast_menu>
C#代码:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Xml;
6
7 namespace myXmlReader
8 {
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 XmlReader reader = XmlReader.Create(@"E:\kemi\CodeNow\Project\XmlReader\food.xml");//创建XmlReader实例
14
15 while (reader.Read())
16 {
17 if (reader.NodeType.Equals(XmlNodeType.Element))//判断节点类型
18 {
19 switch (reader.Name)
20 {
21
22 case "breakfast_menu":
23 Console.WriteLine("===========breakfast menu==========");
24 break;
25 case "name":
26 Console.WriteLine("Name:{0}", reader.ReadString());//使用ReadString读取数据
27 break;
28 case "price":
29 Console.WriteLine("Price:{0}", reader.ReadString());
30 break;
31 case "description":
32 Console.WriteLine("Description:{0}", reader.ReadInnerXml());//使用ReadInnerXml读取数据
33 break;
34 case "calories":
35 Console.WriteLine("Description:{0}", reader.ReadInnerXml());
36 break;
37 default:
38 Console.WriteLine("");
39 break;
40 }
41 }
42 }
43
44 Console.Read();
45 }
46 }
47 }
输出结果: