认识XmlReader
摘要
XmlReader类是组成.NET的关键技术之一,极大地方便了开发人员对Xml的操作。通过本文您将对XmlReader有一个很好的认识,并将其应用到实际开发中。
目录
1.概要
XmlReader 类是一个提供对 XML 数据的非缓存、只进只读访问的抽象基类。该类符合 W3C 可扩展标记语言 (XML) 1.0 和 XML 中的命名空间的建议。
XmlReader 类支持从流或文件读取 XML 数据。该类定义的方法和属性使您可以浏览数据并读取节点的内容。
XmlReader类是一个抽象类,XmlTextReader,XmlValidatingReader,和XmlNodeReader类都继承自XmlReader类。XmlReader类有很多方法和属性用来读取XML文件的内容、查找XML元素的深度、判断当前元素的内容是否为空,以及导航XML的属性等。
2.创建Xml读取器
我们可以通过Create方法来创建一个XmlReader实例,也可以通过XmlReaderSettings类来配置XmlReader对象。使用XmlReaderSettings类的属性启用或禁用XmlReader对象的特定功能,然后将XmlReaderSettings对象传递给Create方法。
通过使用 Create 方法和 XmlReaderSettings 类,您将得到下列好处:
- 可以指定要在所创建的 XmlReader 对象上支持的功能。
- XmlReaderSettings 类可以重复使用,以创建多个读取器对象。可以使用相同的设置创建多个具有相同功能的读取器。另外,可以修改 XmlReaderSettings 对象并创建具有不同功能集的新读取器。
- 可以将功能添加到现有读取器中。Create 方法可以接受其他 XmlReader 对象。基础 XmlReader 对象可以是用户定义的读取器或 XmlTextReader 对象,也可以是要添加附加功能的另一个 XmlReader 实例。
- 充分利用 .NET Framework 2.0 版本的 XmlReader 类中增加的所有新功能。某些功能只能在通过 Create 方法创建的 XmlReader 对象上使用,例如更好的一致性检查以及与 XML 1.0 建议的一致性.
提示: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);
3.访问外部资源
XmlResolver类用于定位并访问XmlReader对象所需的任何资源。XmlResolver可以用于执行以下操作:
- 定位并打开 XML 实例文档。
- 定位并打开 XML 实例文档所引用的任何外部资源。其中可以包括实体、文档类型定义、架构等。
- 如果资源存储在要求身份验证的系统上,System.Xml.XmlResolver.Credentials 属性可以用于指定必要的凭据。
注意:如果未指定 XmlResolver,创建的读取器将使用没有用户凭据的默认 XmlUrlResolver。XmlUrlResover解析由统一资源标识符 (URI) 命名的外部 XML 资源,是 System.Xml 命名空间中的所有类的默认解析器.
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);
4.读取数据
读取数据是处理XML文件最终目的,因此也是本文最重要的部分。下面将详细讨论如何通过XmlReader来读取Xml数据。
4.1 当前节点位置
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).aspx4.2 读取元素
下表介绍 XmlReader 类为处理元素提供的方法和属性。
成员名称
说明
IsStartElement
检查当前节点是否是开始标记或空的元素标记。
ReadStartElement
检查当前节点是否为元素并将读取器推进到下一个节点。
ReadEndElement
检查当前节点是否为结束标记并将读取器推进到下一个节点。
ReadElementString
读取纯文本元素。
ReadToDescendant
将 XmlReader 前进到具有指定名称的下一个子代元素。
ReadToNextSibling
将 XmlReader 前进到具有指定名称的下一个同辈元素。
IsEmptyElement
检查当前元素是否包含空的元素标记。此属性使您能够确定下面各项之间的差异:
<item num="123"/>(IsEmptyElement 为 true。)
<item num="123">(IsEmptyElement 为 false,尽管元素内容是空的。)
也就是说,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 }
4.3 读取属性
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。
4.4 读取内容
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"。
5. 一个简单实例
将菜单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 }