C# ~ 從 XML 到 Linq 到 Linq to XML

.XML

  可擴展標記語言 (Extensible Markup Language), 標記 (markup) 是關鍵部分,是標準通用標記語言 (Standard Generalized Markup Language,SGML) 的子集,一種簡單的存儲和提取數據的文本格式,允許用戶對自己的標記語言進行定義的源語言。XML數據是分層組織的,組織數據的結構化方式,易於使用和擴展的標記語言,主要用於傳輸和存儲數據,是各種應用程序之間進行數據傳輸的常用工具,而HTML主要用於顯示數據。.XML 文件由內容標記組成,具體地: 

  1. 文檔類型定義 (Document Type Definition,DTD),規定文檔的邏輯結構;
  2. 可擴展的樣式語言(Extensible Style Language,XSL),規定XML文檔樣式;
  3. 可擴展鏈接語言 (Extensible Link Language,XLL),支持Web上已有的簡單鏈接; 
     

XML方便有效地表示結構化數據,使用XML進行信息描述和數據交換已經成爲計算機軟件領域的標準技術模式。通過XML實現數據的標準化、結構化,解決了不同平臺、不同系統之間數據結構/模式的差異,使數據層在XML技術的支持下統一起來。

XML語法

 XML文檔用XML聲明、XML名稱空間、XML元素和特性構建。聲明定義XML版本,名稱空間定義詞彙表,元素和特性 定義XML文檔的內容。 

  <?xml version="1.0" encoding="gb2312"?>

 元素是XML文檔最重要的部分,包含文檔的實際數據,元素之間不允許交叉重疊。相較於HTML,XML沒有任何預定義的元素和結構。根元素是通過XmlDocument類的屬性DocumentElement獲得。主要的類:XDocument、XElement、XAttribute


讀取方法

  在程序中訪問並操作.XML文件一般有兩種模型,分別是使用文檔對象模型DOM流模型。使用DOM的好處在於它允許編輯和更新XML文檔,可以隨機訪問文檔中的數據、可以使用XPath查詢,但是,DOM的缺點是需要一次性加載整個文檔到內存,對於大型文檔會造成資源問題。流模型很好的解決這個問題,因爲它對.XML文件的訪問採用流的概念,也就是說,任何時候內存中只有當前節點,但它是隻讀的、向前的,不能在文檔中執行向後導航操作。三種常用的讀取XML文件的方法:

  1. - - 使用 XmlDocument
  2. - - 使用 XmlTextReader
  3. - - 使用 Linq to Xml

以如下.XML文檔爲例進行說明:

<?xml version="1.0" encoding="gb2312">
<RootConfig>
  <campaigns>
     <campaign Year="2015">
        <DictDatas Page="p1">
            <Dict name="DeviceNo">
                <item value="010">北京</item>
                <item value="021">上海</item>
                <item value="0536">濰坊</item>
                <IsComboBox>Yes</IsComboBox>
            </Dict>
        </DictDatas>
     </campaign>
     <campaign  Year="2016">
        <DictDatas Page="p1|p2">
            <Dict name="Student">
                <FirstName>Sun</FirstName>
                <LastName>Wjcx.com</LastName>
            </Dict>
            <Dict name="SexNo">
                <item value="1">女</item>
                <item value="2">男</item>
                <IsComboBox>Yes</IsComboBox>
            </Dict>
        </DictDatas>
        <searchFields Page="p1|p2">
            <searchField name="SchoolInfo">
                <ID>00.00</ID>
                <SchoolName>Whut.Seu</SchoolName>
                <Address>Wuhan.NanJing</Address>
            </searchField>
        </searchFields>     
     </campaign>
  </campaigns>
</RootConfig>  

1、使用XmlDocument
  
  XmlDocument是以基於文檔結構模型的方式讀取.XML文件,可以把.XML文件看作是由文檔聲明(Declare)、元素(Element)、屬性(Attribute)、文本(Text)等構成的一棵樹,最開始的一個結點爲根結點,每個結點都可以有自己的子結點,得到一個結點後,可以通過一系列屬性或方法得到結點的值或其它屬性:

 例:xn代表一個結點
 xn.Name; // 這個結點的名稱
 xn.Value; // 這個結點的值
 xn.ChildNodes; // 這個結點的所有子結點鏈表
 xn.ParentNode; // 這個結點的父結點

  使用時首先聲明一個XmlDocument對象,調用Load方法,從指定路徑加載XML文件,推薦格式:

 XmlDocument doc = new XmlDocument();
 XmlReaderSettings settings = new XmlReaderSettings();
 settings.IgnoreComments = true;  // 忽略文檔裏面的註釋
 settings.IgnoreWhiteSpace = true;  // 忽略空白
 XmlReader reader = XmlReader.Create(@"..\..\sqh.xml", settings);
 doc.Load(reader);

 具體屬性和方法: 

 - XmlNode xnCamps = doc.SelectSingleNode("campaigns"); // 定位結點 
 - XmlNodeList campList = doc.SelectNodes("campaign"); // 定位結點鏈表
 - XmlNodeList campList = doc.SelectNodes("campaign[Year<='2016']"); 

  關於定位結點,有必要學習XML文檔的查詢語言:xPath,待續…    

 foreach(XmlNode xnCamp in campList)
 {
     XmlElement xeCamp = (XmlElement)xnCamp; // 將節點轉換爲元素,便於得到節點的屬性值
     string nameCamp = xeCamp.Name;
     string yearCamp = xeCamp.GetAttribute("Year").ToString();
     string yearCamp = xeCamp.Attributes["Year"].Value; // 此2行代碼等價

     XmlElement xeDict =  (XmlElement)xeCamp.SelectSingleNode("DictDatas");
     foreach(XmlNode xnDict in xeDict.ChildNodes)
     {
        XmlElement xeDict = (XmlElement)xnDict;
        string isComboBox = xeDict["ComboBox"].InnerText;

        XmlNodeList itemList = xeDic.SelectNodes("item");
        foreach (XmlNode xnItem in itemList)
        {
            XmlElement xeItem = (XmlElement)xnItem;
            string value = xeItem.GetAttribute("value").ToString();
            string innerText = xeItem.InnerText;
        }
     }
 }

以上代碼僅供學習參考,歡迎批評指正。


2、使用XmlTextReader

待續吧…


3、使用 Linq to Xml

 首先了解下Linq,OK.
 Linq (Language Itergrated Query,語言集成查詢) 是內置於C#中的一種數據查詢語言,允許以數據庫查詢的方式查詢數據集合,可以在大型的對象集合、XML、數據庫中查詢數據。不同的Linq變體(Linq to Objects、Linq to Entities、Linq to XML等)可以用於查詢、處理不同的數據源(數據庫和XML等)。

Linq查詢

 a. 查詢語法 Query Syntax
  聲明形式。利用查詢表達式。簡單易理解,推薦。
  查詢表達式:fromselect子句,group子句,where子句,join子句,orderby子句等。
  · join 子句
    用一個查詢搜索兩個列表中的相關數據,用鍵字段把結果鏈接起來。
   from c in Table1
   join o in Table2 on c.ID equals o.ID
  · group 子句
    分組鍵用 key 區分,返回結果 res 是關於 key 的可枚舉類型(分組),每個組也是可枚舉類型。  
 b. 方法語法 Method Ayntax
  命令形式。利用標準查詢運算符。特殊情況需要傳送函數或方法,以委託的形式。注意,方法調用順序並不固定,因爲Linq方法調用返回的類型都實現了 IEnumerable<T> 接口,但是應根據查詢特性,合理安排調用順序。
  System.Linq.Enumerable類聲明瞭標準查詢運算符的方法,是擴展了泛型 IEnumerable<T> 的 擴展方法:公共靜態方法,參數列表以 this 開始!
  · 直接語法調用:Enumerable.Function(可枚舉類型實例);
  · 擴展語法調用:可枚舉類型實例.Function();或 可枚舉類型實例.Function(Lambda表達式); 
 :返回結果res爲 可枚舉類型,內存中的表示形式:
 
 其中,res 並不保存查詢結果,而是指向 IEnumerable<T>類型的對象。當處理枚舉類型時,查詢表達式纔會執行(延遲執行)。

 聚合運算符:查詢大型數據集,分析查詢結果。
  Count()、Max()、Min()、Average()、Sum()
 投影 Projection:在查詢中創建新的對象。
  a. 投影查詢的查詢語法
   在select子句中利用 new{} 創建新對象,不能採用 select + 字段列表 的形式。
  b. 投影查詢的方法語法
   調用Linq的 Select(Lambda表達式) 方法。
 多級排序
  a. 查詢語法
   orderby + 字段列表。
  b. 多級排序的方法語法
   OrderBy().ThenBy()/ThenByDescending()方法。
 組合查詢 group
  把數據分解爲組,允許按組來排序、計算聚合值以及進行比較。分組產生的結果集實現了 Linq接口 IEnumerable<IGrouping>,它支持 key 屬性,所以組合查詢中的數據通過一個鍵(Key)字段來組合,每個組中的所以數據共享這個字段值。
 <-!- 幾種常用方法 -!->
 . 分區運算符
  - Take():從查詢結果中提取前n個結果;
  - Skip():與Take()相反,跳過前n個結果,返回剩餘的結果;
 . 條件查詢運算符
  - First():返回結果集中第一個匹配給定條件的元素;
  - FirstOrDefault():查詢條件不滿足,返回默認元素,而不必添加錯誤處理代碼;
 . 標準的集(合)運算符 set operator
  - Intersect():交集,QryRes1.Intersect(QryRes2);
  - Except():差集,QryRes1.Except(QryRes2);
  - Union():並集,QryRes1.Union(QryRes2);

Linq to XML

構建對象
 C#:利用匿名類型 var 和對象初始化器。
 Linq to XML:函數構建方式 (Function Construction)。此方式可以創建XML文檔,並且可以反映XML文檔的嵌套結構。需要引用命名空間:using System.Xml.Linq;
  . XDocument:XML文檔聲明。
  . XElement:元素。
  . XAttribute:特性。

XDocument personsDoc = new XDocument(
  new XElement("persons", new XAttribute("Nationality","China"),
    new XElement("person", new XAttribute("ID","101"),  // 屬性
      new XElement("Name","sqh"),                      // 元素
      new XElement("Sex","male"),
      new XElement("City", new XAttribute("Province", "ShanDong"), "WeiFang")
    ),
    new XElement("person", new XAttribute("ID", "102"),
      new XElement("Name", "pm"),
      new XElement("Sex", "female"),
      new XElement("City", new XAttribute("Province", "SiChuan"), "NanChong")
    )
  ));
  
personsDoc.Save/Load(); // 保存/加載
XElement root = personsDoc.Root;  // 根結點 
IEnumerable<XElement> rootChilds = root.Elements("person");
foreach (XElement xe in rootChilds){
  xe.Name.ToString(), xe.Attribute("ID").Value // 結點/子結點名字及屬性
  xe.Element("City").Value, xe.Element("City").Attribute("Province").Value
} 

// 增-Add、刪-Remove、改-SetElement
root.SetAttributeValue("民族", "漢");  // 增加/修改屬性
root.Attribute("民族").Remove();       // 刪除屬性
root.Add(new XElement("person", new XAttribute("ID","103"),  // 增加結點
       new XElement("Name", "ymn"),
       new XElement("Sex", "female"),
       new XElement("City", new XAttribute("Province", "HuBei"), "XianNing")
   ));
xe.Remove();   // 刪除結點           

 利用 Linq 查詢表達式進行 XML 樹搜索。

// 查 - Linq to Xml 
var res = from xe in root.Elements("person")
      where int.Parse(xe.Attribute("ID").Value) <= 102
      select new { Name = xe.Element("Name").Value, City = xe.Element("City").Value};

參考鏈接
 c# 讀取XML - 1; - c# 讀取XML - 2; 
 關於XmlReader/XmlWriter 類;

 Linq系列 ~ Linq to XML;
 LINQ to XML 建立,讀取,增,刪,改;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章