用C#讀xml文檔(流模型)

來源:互聯網
上載者:User

System.Xml命名空間下,XmlReader和XmlWriter類是用於讀寫xml文檔的抽象類別,它們使用流模型
使用XmlReader類讀XML文檔,它提供對XML資料的快速、非緩衝、只向前、唯讀訪問。

1.XmlReader有3個子類:
1)XmlTextReader:最快的 XmlReader 實現。它檢查 XML 格式是否正確,但不支援驗證。該讀取器不能展開常規實體(dtd中的概念),不支援預設屬性。
XmlReader 在發生 XML 分析錯誤時引發 XmlException 異常。

2)XmlValidatingReader:  可以使用 DTD 或 Schema 驗證資料的 XmlReader 的實現。該讀取器還可以展開常規實體並支援預設屬性。

3)XmlNodeReader:  從 XmlNode 讀取 XML 資料的 XmlReader 的實現

註:讀xml文檔,一般使用XmlTextReader類

===================================================

2.XmlTextReader 類
1)XmlTextReader把xml文檔看作是一個序列化的節點集合,即一個節點流

2)xml文檔中的 元素的開始標記(節點類型為Element)、元素的屬性(Attribute)、元素的常值內容(Text)、標記之間的空白/換行(SignificantWhitespace或Whitespace)、元素的結束標記(EndElement)等 都被視為節點。

3)Read()方法是XmlTextReader類的主要執行個體方法,它執行一次就讀節點流中的一個節點
但Read()方法不會自動讀取屬性節點(Attribute類型的節點),如果當前節點是Element節點後,下一次被讀的節點就是Text(如果當前元素有常值內容)或Whitespace節點(如果當前節點標記預下一個標記之間有空白/換行的話,如果沒有空白換行,就沒有Whitespace節點)
即Read()方法只會讀Element、Text、Whitespace、EndElement等類型的節點

3)如果當前當前節點是Element節點,如果想讀元素的屬性節點的話,可以使用以下方法:
MoveToAttribute 、MoveToFirstAttribute 、MoveToNextAttribute 等
如果當前節點是Attribute節點,要回到屬性所屬元素的節點上的話,可使用MoveToElement 方法

4)隨著當前節點的節點類型的不同,XmlReader類對象的某些屬性也會無效
例如XmlTextReader對象的AttributeCount屬性,對於不是Element、DocumentType 和 XmlDeclaration 類型的節點來說,該屬性無意義

5)關於SignificantWhitespace/Whitespace節點的處理:
XmlTextReader對象的WhitespaceHandling屬性可以指定如何處理空白

3.節點的類型
=====================================================================
節點類型 說明   樣本 XML
=====================================================================
Attribute  屬性    id='123'
---------------------------------------------------------------------
CDATA  CDATA節   <![CDATA[my escaped text]]>
---------------------------------------------------------------------
Comment  注釋   <!-- my comment -->
---------------------------------------------------------------------
Document  作為文檔樹的根的文檔對象提供對整個 XML 文檔的訪問
---------------------------------------------------------------------
DocumentFragment  文檔片段  
---------------------------------------------------------------------
DocumentType  文件類型聲明  <!DOCTYPE ...>
---------------------------------------------------------------------
Element  元素   <item>
---------------------------------------------------------------------
EndElement  結束元素標記  </item>
---------------------------------------------------------------------
EndEntity  由於調用 ResolveEntity 而使 XmlReader 到達實體替換的末尾時返回
---------------------------------------------------------------------
Entity   實體聲明  <!ENTITY ...>
---------------------------------------------------------------------
EntityReference 對實體的引用  &num;
---------------------------------------------------------------------
None   如果未調用 Read 方法,則由 XmlReader 返回
---------------------------------------------------------------------
Notation  文件類型聲明中的標記法 <!NOTATION ...>
---------------------------------------------------------------------
ProcessingInstruction  處理指示 <?pi test?>
---------------------------------------------------------------------
SignificantWhitespace  混合內容模型中標記間的空白或 xml:space="preserve"範圍內的空白
---------------------------------------------------------------------
Text   節點的常值內容。可以以Attribute、DocumentFragment、Element、  EntityReference 節點的子節點的形式出現
---------------------------------------------------------------------
Whitespace  標記間的空白
---------------------------------------------------------------------
XmlDeclaration  XML 聲明  <?xml version='1.0'?>
=====================================================================

4.XmlTextReader應用樣本:讀一個xml文檔-tmp.xml

文檔tmp.xml的內容:
-----------------------------------------------------------------------
<?xml version="1.0" encoding="GB2312"?>
<bookstore>
 <book name="文化苦旅">
  <author nation="中國" 年代="當代">餘秋雨&amp;</author>
  <price>32</price>
  <press>華夏出版社</press>
 </book> 
</bookstore>
  //文檔有一個空白尾行
------------------------------------------------------------------------

C#代碼:
------------------------------------------------------------------------
XmlTextReader xr4 = new XmlTextReader("temp.xml");  //裝載整個文檔到記憶體
xr4.WhitespaceHandling = WhitespaceHandling.All;    //設定如何處理空白節點
  while(xr4.Read())
  {   
 Console.Write((" Type: " + xr4.NodeType).PadRight(20));   //列印節點類型
 Console.Write((" Name: " +  xr4.Name).PadRight(18));   //列印節點名稱
 Console.WriteLine(" Value: " + xr4.Value);    //列印節點的值

 if (xr4.HasAttributes)   //如果當前節點有屬性的話(非元素節點的此屬性為null)
 {
     int tmp = xr4.AttributeCount;
   for (int i = 0; i < tmp; i++ ) //迴圈列印元素節點的屬性
   {
         xr4.MoveToAttribute(i);  //移動到第n個屬性上
  Console.WriteLine((" Type: " + xr4.NodeType).PadRight(20)
    + (" Name: " + xr4.Name).PadRight(16)
    + (" value: " + xr4.Value.PadRight(10))
    + (" AttributeCount: " + xr4.AttributeCount) );
  xr4.MoveToElement();  //回到元素節點
   }
 }
  }
xr4.Close();  //關閉流對象
Console.ReadLine();
------------------------------------------------------------------------

輸出:
----------------------------------------------------------------------------------
Type: XmlDeclaration Name: xml         Value: version="1.0" encoding="GB2312"
Type: Attribute     Name: version   value: 1.0        AttributeCount: 2
Type: Attribute     Name: encoding  value: GB2312     AttributeCount: 2
Type: Whitespace    Name:             Value:

Type: Element       Name: bookstore   Value: //該節點沒有屬性,AttributeCount為null
Type: Whitespace    Name:             Value: //該節點沒有屬性,AttributeCount為null

Type: Element       Name: book        Value:
Type: Attribute     Name: name      value: 文化苦旅       AttributeCount: 1
Type: Whitespace    Name:             Value:

Type: Element       Name: author      Value:
Type: Attribute     Name: nation    value: 中國         AttributeCount: 2
Type: Attribute     Name: 年代        value: 當代         AttributeCount: 2
Type: Text          Name:             Value: 餘秋雨&
Type: EndElement    Name: author      Value: 
Type: Whitespace    Name:             Value:

Type: Element       Name: price       Value:
Type: Text          Name:             Value: 32
Type: EndElement    Name: price       Value:
Type: Whitespace    Name:             Value:

Type: Element       Name: press       Value:
Type: Text          Name:             Value: 華夏出版社
Type: EndElement    Name: press       Value:
Type: Whitespace    Name:             Value:

Type: EndElement    Name: book        Value:  //即book元素的結束標記</book> 
Type: Whitespace    Name:             Value:

Type: EndElement    Name: bookstore   Value:  //即結束標記</bookstore>
Type: Whitespace    Name:             Value:  //文檔的空白尾行
----------------------------------------------------------------------------------

5.XmlTextReader類的常用方法
1)在元素節點和屬性節點之間移動
如果當前節點是元素節點,並且該元素擁有屬性的話:
·使用MoveToAttribute()方法可以移動到屬性節點,該方法要求指定屬性名稱或屬性的位置
·使用MoveToFirstAttribute()方法可以移動到第一個屬性上,並返回true
·如果當前節點是元素節點,使用MoveToNextAttribute()方法等效於MoveToFirstAttribute方法。
  如果已經移動到了屬性節點上,並且存在下一個屬性,調用該方法就會移動到下一個屬性節點上
  否則,讀取器位置不變並返回false

如果讀取器定位在屬性上,使用MoveToElement()方法,則當前節點移動到屬性所屬的元素節點上。

2)跳過內容-兩種方法
·一種方法是調用使用 MoveToContent 方法直接移動到內容節點
MoveToContent()方法檢查當前節點以查看它是否是內容節點。
內容節點被定義為任意 Text、CDATA、Element、EndElement、EntityReference 或 EndEntity 節點。如果當前節點不是前述內容節點的類型之一,則將跳過該節點並跳到下一個內容節點或檔案結尾。
它一直跳,直到找到下一個內容節點或到檔案的結尾才停止。
如果當前節點是一個屬性節點,則此方法將讀取器移回擁有該屬性的元素。

樣本:
-----------------------------------------------------------------------------
if (reader.MoveToContent() == XmlNodeType.Element && reader.Name == "price")
 {
    _price = reader.ReadString();
 }
-----------------------------------------------------------------------------

·另一種方法是直接調用 Skip 方法,該方法從當前節點跳過所有子節點到下一個同級節點
如果當前節點類型為XmlNodeType.Element,則調用skip方法將跳到同級的下一個節點上。
如果當前節點是屬性節點,則調用skip方法將跳到屬性所屬元素節點的下一個同級節點上。

3)讀方法
·Read()方法:如果成功讀取了下一個節點,則為true;如果沒有其他節點可讀取,則為false
  第一次建立和初始化讀取器時,沒有可用的資訊。必須調用 Read() 讀取第一個節點。

·ReadStartElement()方法:
  檢查當前節點是否為元素(類型為Element的節點)並將讀取器推進到下一個節點

·ReadEndElement()方法:
  檢查當前節點是否為結束標記(類型為EndElement的節點)並將讀取器推進到下一個節點

·ReadAttributeValue()方法:
  將當前屬性節點的屬性值分解為一個或多個 Text、EntityReference 或 EndEntity 節點。
  如果有可返回的節點,則返回true。如果進行初始調用時讀取器不是定位在屬性節點上,或者如果已讀取了所有屬性值,則返回false
  如果是空屬性(如 misc=""),則返回true,同時將屬性值分解為 String.Empty 的單個節點
  一般,當讀取器移動到一個屬性節點上後,通過迴圈調用ReadAttributeValue方法來分解屬性的值

樣本:讀xml文檔 <book genre='novel' misc='sale-item &h; 1987'></book>
---------------------------------------------------------------------
.......
reader.MoveToAttribute("misc");  //移動到屬性misc上
while (reader.ReadAttributeValue()) //misc屬性值包含實體應用,屬性值被分解
{     //分解完屬性值後,迴圈結束
   if (reader.NodeType==XmlNodeType.EntityReference) //遇到實體引用節點
     Console.WriteLine("{0} {1}", reader.NodeType, reader.Name);
   else
     Console.WriteLine("{0} {1}", reader.NodeType, reader.Value);
}
--------------------------------------------------------------------

4)使用字元流進行完整的內容讀取
方法ReadChars、ReadBinHex、ReadBase64用於讀取大型的流。ReadChars方法原樣讀取文本 (US-ASCII),ReadBase64方法解碼Base64編碼的文本,而ReadBinHex方法則解碼binhex編碼的資料。
ReadChars、ReadBinHex和ReadBase64方法只能用在元素上。在其他節點類型上使用這些方法不起作用
這三個方法都返回元素的開始標記和結束標記之間的所有內容,包括所有標記,就像在讀出流一樣。

·ReadChars方法: public int ReadChars(char[] buffer,int index,int count);
  將元素的內容讀入字元緩衝區。通過連續調用此方法,可以讀取當前元素的非常大的嵌入文字資料流
  此方法設計只用於元素節點。其他節點類型導致ReadChars返回0
  此方法返回元素的實際字元內容,返回元素開始標記和結束標記之間的所有內容,包括標記
  ReadChars方法忽略格式不正確的XML標記
  當ReadChars方法已到達字元流的結尾時,它傳回值0並且將讀取器定位在結束標記之後

·ReadBase64方法: public int ReadBase64(byte[] array,int offset,int len);
  和ReadChars方法一樣,可以連續調用此方法以讀取大的嵌入文字資料流。
  它對Base64內容進行解碼,並將解碼的二進位位元組(例如內聯Base64編碼的GIF映像)返回到緩衝區中

·ReadBinHex方法: public int ReadBinHex(byte[] array,int offset,int len);
  與 ReadChars 一樣,可以連續調用此方法以讀取大的嵌入文字資料流。
  它對BinHex內容進行解碼並將解碼的二進位位元組(例如內聯BinHex編碼的GIF映像)返回到緩衝區中
 

5)讀取字元內容
·ReadElementString方法:讀取簡單文本元素的方法
  調用ReadElementString方法時,讀取器將移動到下一個節點並讀取其簡單常值內容,如果該節點不是簡單文本元素,則會報錯。讀取完之後,讀取器將再向下移動一個節點

·ReadString方法:元素或文本節點的內容當做字串讀取
  如果讀取器定位在元素或文本節點以外的位置,或者當前上下文中沒有其他常值內容,則返回Null 字元串

·ReadInnerXml方法:將節點的所有內容(包括子項目、常值內容等)當做字串讀取
  如果當前讀取器位於開始標記,則該方法返回開始標記與對應的結束標記之間所有的內容
  如果當前讀取器位於屬性節點,則該方法返回屬性的值
  如果當前節點既非元素,也非屬性,則返回Null 字元串

·ReadOuterXml方法:此方法類似於 ReadInnerXml,但它還返回開始標記和結束標記
  如果當前讀取器位於開始標記,則該方法返回  <開始標記>..內容..<結束標記/>  字串
  如果當前讀取器位於屬性節點,則該方法返回   屬性名稱="屬性值"  字串
  如果當前節點既非元素,也非屬性,則返回Null 字元串

===================================================

2.XmlValidatingReader類
1)XmlValidatingReader類是一個能夠提供 DTD、XDR 和 XSD 驗證的讀取器,能夠提供資料驗證、解析常規實體的能力和對預設屬性的支援,該類也是繼承自 XmlReader 類。

2)XmlValidatingReader類基本上類似於XmlTextReader類,但它增加了ValidationType、Schema和 SchemaType、XmlResolver 等新的屬性
·ValidationType屬性指示驗證的類型,其範圍為:Auto,DTD,Schema,XDR,None
·Schema屬性用於需要多個xdr或xsd參與驗證的情況,Schema屬性實質上是一個XmlSchemaCollection
·SchemaType屬性返回當前節點的類型:XSD內建類型、使用者自訂類型(simpleType/complexType)
·XmlResolver屬性用於解析外部實體(比如DTD中定義的外部實體)

3)使用XmlValidatingReader類進行驗證的最佳操作:
·建立一個XmlTextReader對象tr,將tr對象傳給XmlValidatingReader建構函式產生一個對象trv
·設定XmlValidatingReader類型對象trv的ValidationType屬性(預設值為Auto)
·為事件ValidationEventHandler定義和分配事件處理方法ValidationEvent
  trv.ValidationEventHandler += new ValidationEventHandler(this.ValidationEvent)
  因為如果驗證出錯誤時,就會引發trv對象的ValidationEventHandler事件,需要對該事件進行處理
·像使用XmlTextReader類對象那樣使用XmlValidatingReader對象trv

4)僅當在調用Read、ReadInnerXml、ReadOuterXml或Skip方法的過程中,且XmlValidatingReader對象trv的ValidationType屬性不是ValidationType.None時,才可能發生ValidationEventHandler驗證事件
  如果不提供ValidationEventHandler事件的處理常式,當遇到層級為Warning的驗證錯誤時,仍會繼續讀取資料不引發異常。當遇到第一個層級為Error的驗證錯誤時,XmlValidatingReader對象trv將會引發異常XmlException,之後trv對象也將無法重新啟動。
  當根據架構或DTD進行驗證時,如果發生驗證錯誤,也將引發XmlSchemaException異常
  如果某個元素報告驗證錯誤,則不驗證該元素其餘的內容模型,但是將驗證其子級。讀取器只報告給定元素的第一個錯誤
  ValidationEventHandler事件處理常式可以使用ValidationEventArgs類對象e的Severity屬性來保證根據結構描述驗證了XML執行個體文檔。Severity屬性可以區分驗證錯誤和驗證警告,驗證錯誤(Severity 等於 XmlSeverityType.Error)表示致命錯誤,而驗證警告(Severity 等於 XmlSeverityType.Warning)指示沒有可用的架構資訊。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.