摘要
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方法。
MSDN建議:
盡管在 .NET Framework 2.0 版中,Microsoft .NET Framework 包括 XmlReader 類的具體實現,例如 XmlTextReader、XmlNodeReader 和 XmlValidatingReader類,但是,我們建議您使用 Create 方法創建 XmlReader 實例。
通過使用 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 命名空間中的所有類的默認解析器。
以下代碼創建一個 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);
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).aspx
4.2 讀取元素
下表介紹 XmlReader 類為處理元素提供的方法和屬性。
成員名稱 |
說明 |
---|---|
IsStartElement |
檢查當前節點是否是開始標記或空的元素標記。 |
ReadStartElement |
檢查當前節點是否為元素並將讀取器推進到下一個節點。 |
ReadEndElement |
檢查當前節點是否為結束標記並將讀取器推進到下一個節點。 |
ReadElementString |
讀取純文本元素。 |
ReadToDescendant |
將 XmlReader 前進到具有指定名稱的下一個子代元素。 |
ReadToNextSibling |
將 XmlReader 前進到具有指定名稱的下一個同輩元素。 |
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 }
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 }
輸出結果: