在關係型數據庫系統中,數據被組織放入規範化很好的表中,而且經過簡單且強大的SQL語言來進行訪問。由於數據在表中聽從某些嚴格的規則,因此SQL能夠和它們很好的配合使用。
然而,在程序中卻與數據庫相反,保存在類對象或結構中的數據差別很大。所以,沒有通用的查詢語言來從數據結構中獲取數據。從對象獲取數據的方法一直都是做爲程序的一部分而設計的。然而使用LINQ能夠很輕鬆地查詢對象集合。
以下是LINQ的重要高級特性。css
例:LINQ示例程序員
class Program { static void Main() { int[] numbers={2,12,5,15}; IEnumerable<int> lowNums= from n in numbers where n<10 select n; foreach(var x in lowNums) { Console.WriteLine(x); } } }
在以前的示例中,數據源只是int數組,它是程序在內存中的對象。然而,LINQ還能夠和各類類型的數據源一塊兒工做。然而,對於每種數據源類型,在其背後必定有根據該數據源類型實現LINQ查詢的代碼模塊。這些代碼模塊叫作LINQ提供程序(provider)。
有關LINQ提供程序的要點以下數據庫
本章中,咱們主要介紹LINQ並解釋如何將其用於程序對象(LINQ to Object)和XML(LINQ to XML),其餘細節和用法不作討論。數組
在介紹LINQ查詢特性的細節前,咱們先學習一個容許咱們建立無名類類型的特性。匿名類型(anonymous type)常常用於LINQ查詢的結果中。
第6章介紹了對象初始化語句,它容許咱們在使用對象建立表達式時初始化新類實例的字段和屬性。提醒一下,這種形式的對象建立表達式由三部分組成:new關鍵字、類名或構造函數以及對象初始化語句。對象初始化語句在一組大括號內包含了以逗號分隔的成員初始化列表。
建立匿名類型的變量使用相同的形式,可是沒有類名和構造函數。以下的代碼行演示了匿名類型的對象建立表達式:瀏覽器
沒有類名 ↓ new {FieldProp=InitExpr,FieldProp=InitExpr,...} ↑ 成員初始化語句
例:建立和使用匿名類型的示例。數據結構
class Program { static void Main() { 必須使用var ↓ var student=new{Name="Mary Jones",Age=19,Major="History"}; Console.WriteLine("{0},Age {1},Major: {2}",student.Name,student.Age,studeng.Major); } }
須要瞭解的有關匿名類型的重要事項以下。框架
當編譯器遇到匿名類型的對象初始化語句時,它建立一個有名字的新類類型。低於每一個成員初始化語句,它推斷其類型並建立一個只讀屬性來訪問它的值。屬性和成員初始化語句具備相同名字。匿名類型被構造後,編譯器建立了這個類型的對象。
除了對象初始化語句的賦值形式,匿名類型的對象初始化語句還有其餘兩種容許的形式:簡單標識符和成員訪問表達式。這兩種形式叫作投影初始化語句(projection initializer)。下面的變量聲明演示了3種形式。ide
var student=new{Age=19,Other.Name,Major};
例:使用3總初始化語句。注意,投影初始化語句必須定義在匿名類型聲明以前。函數
class Other { static public string Name="Mary Jones"; } class Program { static void Main() { string Major="History"; var student=new{Age=19,Other.Name,Major}; Console.WriteLine("{0},Age {1},Major: {2}",student.Name,student.Age,studeng.Major); } }
若是編譯器遇到了另外一個具備相同的參數名、相同的推斷類型和相同順序的匿名類型,它會重用這個類型並直接建立新的實例,不會建立新的匿名類型。工具
咱們在寫LINQ查詢時可使用兩種形式的語法:方法語法和查詢語法。
方法語法是命令式(imperative)的,它指明瞭查詢方法調用的順序。
查詢語法是聲明式(declarative)的,即查詢描述的是你想返回的東西,但並麼有指明如何執行這個查詢。
編譯器會將使用查詢語法表示的查詢翻譯爲方法調用的形式。這兩種形式在運行時沒有性能上的差別。
微軟推薦使用查詢語法,由於它更易讀,能更清晰地代表查詢意圖,所以也更不容易出錯。然而,有些運算符必須使用方法語法來書寫。
例:方法語法和查詢語法演示
class Program { static void Main() { int[] numbers={2,5,28,31,17,16,42}; var numsQuery=from n in numbers //查詢語法 where n<20 select n; var numsMethod=numbers.Where(x=>x<20); //方法語法 int numsCount=(from n in numbers //兩種形式組合 where n<20 select n).Count(); foreach(var x in numsQuery) { Console.Write("{0}, ",x); } Console.WriteLine(); foreach(var x in numsMethod) { Console.Write("{0}, ",x); } Console.WriteLine(); Console.WriteLine(numsCount); } }
LINQ查詢能夠返回兩種類型的結果–能夠是一個枚舉(可枚舉的一組數據,不是枚舉類型),它知足查詢參數的項列表;也能夠是一個叫作標量(scalar)的單一值,它是知足查詢條件的結果的某種摘要形式。
例:查詢變量示例
int[] numbers={2,5,28}; IEnumerable<int> lowNums=from n in numbers //返回枚舉數 where n<20 select n; int numsCount=(from n in numbers //返回一個整數 where n<20 select n).Count();
理解查詢變量的用法很重要。在執行前面的代碼後,lowNums查詢變量不會包含查詢的結果。相反,編譯器會建立可以執行這個查詢的代碼。
查詢變量numCount包含的是真實的整數值,它只能經過真實運行查詢後得到。
區別在於查詢執行的時間,可總結以下:
查詢表達式由查詢體後的from子句組成。有關查詢表達式須要瞭解一些重要事項:
from子句指定了要做爲數據源使用的數據集合。它還引入了迭代變量。有關from子句的要點以下:
from Type Item in Items
下圖演示了from子句的語法。類型說明符是可選的。能夠有任意多個join子句。
儘管LINQ的from子句和foreach語句很是類似,但主要不一樣點以下:
LINQ中的join子句和SQL中的JOIN(聯結)子句類似。不一樣的是,咱們如今不但能夠在數據庫的表上進行聯結,還能夠在集合對象上進行該操做。若是你不熟悉聯結,那麼下面的內容會幫你理清思路。
須要先了解有關聯結的語法:
聯結語法以下
關鍵字 關鍵字 關鍵字 關鍵字 ↓ ↓ ↓ ↓ join Identifier in Collection2 on Field1 equals Field1 ↑ 指定另外的集合和ID引用它 var query=from s in students join c in studentsInCourses on s.StID equals c.StID
LINQ中的join接受兩個集合而後建立一個新的集合,每一個元素包含兩個原始集合中的原始成員。
例:聯結示例
class Program { public class Student { public int StID; public string LastName; } public class CourseStudent { public string CourseName; public int StID; } static Student[] students=new Student[]{ new Student{StID=1,LastName="Carson"}, new Student{StID=2,LastName="Klassen"}, new Student{StID=3,LastName="Fleming"}, }; static CourseStudent[] studentsInCourses=new CourseStudent[]{ new CourseStudent{CourseName="Art",StID=1}, new CourseStudent{CourseName="Art",StID=2}, new CourseStudent{CourseName="History",StID=1}, new CourseStudent{CourseName="History",StID=3}, new CourseStudent{CourseName="Physics",StID=3}, } static void Main() { var query=from s in students join c in studentsInCourses on s.StID equals c.STID where c.CourseName=="History" select.LastName; foreach(var q in query) { Console.WriteLine("Student taking History:{0}",q); } } }
可選的from…let…where部分是查詢主體的第一部分,能夠由任意數量的3個子句來組合–from子句、let子句和where子句。
查詢表達式從必需的from子句開始,後面跟查詢主體。主體自己能夠從任何數量的其餘from子句開始,每一個from子句都指定了一個額外的源數據集合並引入了要在以後運算的迭代變量,全部from子句的語法和含義都同樣。
例:from子句示例
class Program { static void Main() { var groupA=new[]{3,4,5,6}; var groupA=new[]{6,7,8,9}; var someInts=from a in groupA from b in groupB where a>4&&b<=8 select new{a,b,sum=a+b};//匿名類型對象 foreach(var a in someInts) { Console.WriteLine(a); } } }
let子句接受一個表達式的運算而且把它賦值給一個須要在其餘運算中使用的標識符。let子句的語法以下:
let Identifier=Expression
例:let子句示例
class Program { static void Main() { var groupA=new[]{3,4,5,6}; var groupA=new[]{6,7,8,9}; var someInts=from a in groupA from b in groupB let sum=a+b //在新的變量中保存結果 where sum==12 select new{a,b,sum}; foreach(var a in someInts) { Console.WriteLine(a); } } }
where子句根據以後的運算來篩選指定項。
只要是在from…let…where部分中,查詢表達式能夠有多個where。
例:where子句示例
class Program { static void Main() { var groupA=new[]{3,4,5,6}; var groupA=new[]{6,7,8,9}; var someInts=from a in groupA from b in groupB let sum=a+b where sum>=11 ←條件1 where a==4 ←條件2 select new{a,b,sum}; foreach(var a in someInts) { Console.WriteLine(a); } } }
orderby子句根據表達式按順序返回結果項。
orderby子句語法以下圖。可選的ascending和descending關鍵字設置了排序方向。表達式一般是項的一個字段。該字段不必定非得是數值字段,也能夠是字符串這樣的可排序類型。
例:按照學生年齡排序
class Program { static void Main() { var students=new[] { new{LName="Jones",FName="Mary",Age=19,Major="History"}, new{LName="Smith",FName="Bob",Age=20,Major="CompSci"}, new{LName="Fleming",FName="Carol",Age=21,Major="History"}, }; var query=from student in students orderby student.Age select student; foreach(var s in query) { Console.WriteLine("{0},{1}: {2} - {3}",s.LName,s.FName,s.Age,s.Major); } } }
select…group子句的功能以下所示。
例:select整個數據項
using System; using System.Linq; class Program { static void Main() { var students=new[] { new{LName="Jones",FName="Mary",Age=19,Major="History"}, new{LName="Smith",FName="Bob",Age=20,Major="CompSci"}, new{LName="Fleming",FName="Carol",Age=21,Major="History"}, }; var query=from s in students select s; foreach(var s in query) { Console.WriteLine("{0},{1}: {2} , {3}",s.LName,s.FName,s.Age,s.Major); } } }
var query=from s in students select s.LName; foreach(var s in query) { Console.WriteLine(s); }
查詢結果能夠由原始集合的項、項的某些字段或匿名類型組成。
例:使用select建立一個匿名類型
using System; using System.Linq; class Program { static void Main() { var students=new[] { new{LName="Jones",FName="Mary",Age=19,Major="History"}, new{LName="Smith",FName="Bob",Age=20,Major="CompSci"}, new{LName="Fleming",FName="Carol",Age=21,Major="History"}, }; var query=from s in students select new{s.LName,s.FName,s.Major}; foreach(var s in query) { Console.WriteLine("{0} {1} -- {2} , {3}",s.FName,s.LName,s.Major); } } }
group子句把select的對象根據一些標準進行分組。例如,以前示例的學士數組,程序能夠根據它們的主修課程進行分組。
例:根據學士的主修課程進行分組
using System; using System.Linq; class Program { static void Main() { var students=new[] { new{LName="Jones",FName="Mary",Age=19,Major="History"}, new{LName="Smith",FName="Bob",Age=20,Major="CompSci"}, new{LName="Fleming",FName="Carol",Age=21,Major="History"}, }; var query=from s in students group s by s.Major; foreach(var s in query) { Console.WriteLine("{0}",s.Key); foreach(var t in s) { Console.WriteLine(" {0},{1}",t.LName,t.FName); } } } }
查詢延續子句能夠接受查詢的一部分結果並賦予一個名字,從而能夠在查詢的另外一部分中使用。
例:鏈接groupA和groupB並命名爲groupAandB
class Program { static void Main() { var groupA=new[]{3,4,5,6}; var groupA=new[]{6,7,8,9}; var someInts=from a in groupA join b in groupB on a equals b into groupAandB from c in groupAandB select c; foreach(var a in someInts) { Console.WriteLine(a); } } }
輸出:6
標準查詢運算符由一系列API方法組成,它能讓咱們查詢任何.NET數組或集合。
標準查詢運算符的重要特性以下:
IEnumerable<T>
接口,T是類型例:Sum和Count運算符的使用
class Program { static int[] numbers=new int[]{2,4,6}; static void Main() { int total=numbers.Sum(); int howMany=number.Count(); Console.WriteLine("Total: {0},Count: {1}",total,howMany); } }
標準查詢運算符可用來操做一個或多個序列。序列指實現了IEnumerable<>接口的類型,包括List<>、Dictionary<>、Stack<>、Array等。
System.Linq.Enumerable類聲明瞭標準查詢運算符方法。這些方法不只是一些方法,它們是擴展了IEnumerable<T>
泛型類的擴展方法。
第7章和第17章介紹類擴展方法,在本節是學習如何使用擴展方法的好機會。
簡單回顧一下。擴展方法是公共的靜態方法,儘管定義在一個類中,但目的是爲另外一個類(第一個形參)增長功能。該參數前必須有關鍵字this。
例:3個標準查詢運算符的簽名
始終是public static 名字和泛型參數 第一個參數 ↓ ↓ ↓ public static int Count<T>(this IEnumerable<T> source); public static T First<T>(this IEnumerable<T> source); public static IEnumerable<T> Where<T>(this IEnumerable<T> source,...);
例:直接調用擴展方法和將其做爲擴展進行調用的不一樣
using System.Linq; ... static void Main() { int[] intArray=new int[]{3,4,5,6,7,9}; //方法語法 var count1=Enumerable.Count(intArray); var firstNum1=Enumerable.First(intArray) //擴展語法 var count2=intArray.Count(); var firstNum2=intArrya.First(); Console.WriteLine("Count: {0},FirstNumber: {1}",count1,firstNum1); Console.WriteLine("Count: {0},FirstNumber: {1}",count2,firstNum2); }
查詢表達式和方法語法能夠組合。編譯器把每一個查詢表達式翻譯成標準查詢運算符的形式。
class Program { static void Main() { var numbers=new int[]{2,6,4,8,10}; int howMany(from n in numbers where n<7 select n).Count(); Console.WriteLine("Count: {0}",howMany); } }
前面咱們看到,每一個運算符的第一個參數是IEnumerable<T>
對象的引用,以後的參數能夠是任何類型。不少運算符接受泛型委託做爲參數(第17章)。泛型委託用於給運算符提供用戶自定義代碼。
爲了解釋這一點,咱們首先從演示Count運算符的幾種使用方式的示例開始。
Count運算符被重載且有兩種形式,第一種以前示例中用過,它有一個參數,返回集合中元素的個數。
public static int Count<T>(this IEnumerable<T> source);
然而,假設咱們但願看看數組中奇數元素的總數。Count方法必須可以檢測整數是否爲奇數。
咱們須要使用Count方法的第二種形式。以下所示,它有一個泛型委託做爲參數。調用時,咱們提供一個接受單個T類型的輸入參數並返回布爾值的委託對象。委託代碼的返回值必須指定元素是否包含在總數中。
public static int Count<T>(this IEnumerable<T> source,Func<T,bool> predicate);
class Program { static void Main() { int[] intArray=new int[] {3,4,5,6,7,9}; var countOdd=intArray.Count(n=>n%2!=0); Console.WriteLine("Count of odd numbers: {0}",countOdd); } }
和前面示例中的Count運算符差很少,不少LINQ運算符須要咱們提供代碼來指示運算符如何執行它的操做。咱們經過委託對象做爲參數來實現。
LINQ定義了兩套泛型委託類型與標準查詢運算符一塊兒使用,即Func委託和Action委託,各有17個成員。
public delegate TR Func<in T1,in T2,out TR>(T1 a1,T2 a2); ↑ ↑ ↑ 返回類型 類型參數 方法參數
注意返回類型參數有out關鍵字,使之能夠協變,便可以接受聲明的類型或從這個類型派生的類型。輸入參數有in關鍵字,使之能夠逆變,即你能夠接受聲明的類型或從這個類型派生的類型。
class Program { static bool IsOdd(int x) { return x%2!=0; } static void Main() { int[] intArray=new int[] {3,4,5,6,7,9}; Func<int,bool>myDel=new Func<int,bool>(IsOdd); var countOdd=intArray.Count(myDel); Console.WriteLine("Count of odd numbers: {0}",countOdd); } }
以前示例使用獨立的方法和委託來把代碼附加到運算符上。這須要聲明方法和委託對象,而後把委託對象傳遞給運算符。若是下面的條件任意一個成立,這種方法是不錯的方案:
若是這兩個條件都不成立,咱們可能但願使用更簡潔和更局部化的方法來給運算符提供代碼,那就是Lambda表達式。
例:用Lambda表達式修改以前的示例
class Program { static void Main() { int[] intArray=new int[] {3,4,5,6,7,9}; var countOdd=intArray.Count(n=>n%2!=0);//Lambda表達式 Console.WriteLine("Count of odd numbers: {0}",countOdd); } }
咱們也能夠用匿名方法來替代Lambda表達式。然而,這種方式比較累贅,並且Lambda表達式在語義上與匿名方法徹底等價,且更簡潔,所以沒有理由再去使用匿名方法了。
class Program { static void Main() { int[] intArray=new int[] {3,4,5,6,7,9}; Func<int,bool> myDel=delegate(int x) //匿名方法 { return x%2!=0; }; var countOdd=intArray.Count(myDel); Console.WriteLine("Count of odd numbers: {0}",countOdd); } }
可擴展標記語言(XML)是存儲和交換數據的重要方法。LINQ爲語言增長了一些特性,使得XML用起來比XPath和XSLT容易得多。
儘管本書不會完整介紹XML,但在接受LINQ to XML前,我會先簡單介紹一下XML。
標記語言(markup language)是文檔中的一組標籤,它提供有關文檔的信息並組織其內容。即標記標籤不是文檔的數據–它們包含關於數據的數據。有關數據的數據稱爲元數據。
標記語言是被定義的一組標籤,旨在傳遞有關文檔內容的特定類型的元數據。例如,HTML是衆所周知的標記語言。標籤中的元數據包含了Web頁面如何在瀏覽器中呈現已經如何使用超連接在頁面中導航的信息。
XML中僅有少許預約義標籤,其餘由程序員定義,來表示特定文檔類型須要的任何元數據。只要數據的讀者和編寫者都知道標籤的含義,標籤就能夠包含任何設計者但願的有用信息。
XML文檔中的數據包含了一個XML樹,它主要由嵌套元素組成。
元素是XML樹的基本要素。每一個元素都有名字且包含數據,一些元素還包含其餘被嵌套元素。元素由開始和關閉標籤進行劃分。任何元素包含的數據都必須介於開始和關閉標籤之間。
<ElementName>
</ElementName>
<ElementName/>
例:
開始標籤 內容 結束標籤 ↓ ↓ ↓ <EmployeeName>Sally Jones</EmployeeName> <PhoneNumber/> ←沒有內容的元素
有關XML的重要事項:
<Employees> <Employee> <Name>Bob Smith</Name> <PhoneNumber>408-555-1000</PhoneNumber> <CellPhone/> </Employee> <Employee> <Name>Sally Jones</Name> <PhoneNumber>415-555-2000</PhoneNumber> <PhoneNumber>415-555-2001</PhoneNumber> </Employee> </Employees>
LINQ to XML能夠以兩種方式和XML配合使用。第一種是做爲簡化的XML操做API,第二種是使用本章前面看到的LINQ查詢工具。
我會先介紹API方式。
LINQ to XML API由不少表示XML樹組件的類組成。咱們主要使用3個類,XElement、XAttribute和XDocument。
下圖演示了用於構造XML樹的類以及它們如何被嵌套。
除了XAttribute類,大多數用於建立XML樹的類都從一個叫作XNode的類繼承,通常在書中也叫作「XNodes」。
例:建立一個包含Employees節點的XML樹
using System; using System.Xml.Linq; class Program { static void Main() { XDocument employees1= new XDocument( //建立XML文檔 new XElement("Employees", new XElement("Name","Bob Smith"), new XElement("Name","Sally Jones") ) ); employees1.Save("EmployeesFile.xml"); //保存到文件 XDocument employees2=XDocument.Load("EmployeesFile.xml"); ↑ 靜態方法 Console.WriteLine(employees2); //顯式文件 } }
例:建立XML樹
using System; using System.Xml.Linq; class Program { static void Main() { XDocument employeeDoc= new XDocument( //建立XML文檔 new XElement("Employees", new XElement("Employee", new XElement("Name","Bob Smith"), new XElement("PhoneNumber","408-555-1000")), new XElement("Employee", new XElement("Name","Sally Jones"), new XElement("PhoneNumber","415-555-2000"), new XElement("PhoneNumber","415-555-2001")) ) ); Console.WriteLine(employeeDoc); } }
當咱們遍歷XML樹來獲取或修改值時才體現了XML的強大。下表給出了用於獲取數據的主要方法。
關於上表,須要注意的一些事項以下:
IEnumerable<object>
類型的對象,由於返回的節點多是不一樣的類型,好比XElement、XComment等。咱們可使用以類型做爲參數的方法OfType(type)
來指定返回某類型的節點。例如,以下代碼只能獲取XComment節點
IEnumerable<XComment> comments=xd.Nodes().OfType<XComment>()
IEnumerable<XElement> empPhones=emp.Elements("PhoneNumber");
using System; using System.Collections.Generic; using System.Xml.Linq; class Program { static void Main() { XDocument employeeDoc= new XDocument( //建立XML文檔 new XElement("Employees", new XElement("Employee", new XElement("Name","Bob Smith"), new XElement("PhoneNumber","408-555-1000")), new XElement("Employee", new XElement("Name","Sally Jones"), new XElement("PhoneNumber","415-555-2000"), new XElement("PhoneNumber","415-555-2001")) ) ); //獲取第一個名爲「Employees」的子XElement XElement root=employeeDoc.Element("Employees"); IEnumerable<XElement> employees=root.Elements(); foreach(XElement emp in employees) { XElement empNameNode=emp.Element("Name"); Console.WriteLine(empNameNode.Value); IEnumerable<XElement> empPhones=emp.Elements("PhoneNumber"); foreach(XElement phone in empPhones) { Console.WriteLine(phone.Value); } } } }
咱們可使用Add方法位現有元素增長子元素。
using System; using System.Xml.Linq; class Program { static void Main() { XDocument xd=new XDocument( new XElement("root", new XElement("first") ) ); Console.WriteLine("Original tree"); Console.WriteLine(xd); Console.WriteLine(); XElement rt=xd.Element("root"); rt.Add(new XElement("second")); rt.Add(new XElement("third"), new XComment("Important Comment"), new XElement("fourth")); Console.WriteLine("Modified tree"); Console.WriteLine(xd); } }
下表列出了最重要的一些操做XML的方法。
特性提供了有關XElement節點的額外信息,它放在XML元素的開始標籤中。
咱們以函數方法構造XML樹時,只需在XElement的構造函數中包含XAttribute構造函數來增長特性。XAttribute構造函數有兩種形式一種是接受name和value,另外一種是接受現有XAttribute的引用。
例:爲root增長兩個特性。
XDocument xd=new XDocument( new XElement("root", new XAttribute("color","red"), new XAttribute("size","large"), new XElement("first"), new XElement("second") ) );
例:獲取特性
class Program { static void Main() { XDocument xd=new XDocument( new XElement("root", new XAttribute("color","red"), new XAttribute("size","large"), new XElement("first"), ) ); Console.WriteLine(xd); Console.WriteLine(); XElement rt=xd.Element("root"); XAttribute color=rt.Attribute("color"); XAttribute size=rt.Attribute("size"); Console.WriteLine("color is {0}",color.Value); Console.WriteLine("size is {0}",size.Value); } }
例:移除特性
class Program { static void Main() { XDocument xd=new XDocument( new XElement("root", new XAttribute("color","red"), new XAttribute("size","large"), new XElement("first"), ) ); XElement rt=xd.Element("root"); rt.Attribute("color").Remove();//移除color特性 rt.SetAttributeValue("size",null);//移除size特性 Console.WriteLine(xd); } }
例:增長或改變特性的值
class Program { static void Main() { XDocument xd=new XDocument( new XElement("root", new XAttribute("color","red"), new XAttribute("size","large"), new XElement("first"), ) ); XElement rt=xd.Element("root"); rt.SetAttributeValue("size","midium"); //改變特性值 rt.SetAttributeValue("width","narrow"); //添加特性 Console.WriteLine(xd); } }
XML註釋由<!--和-->
記號間的文本組成。記號間的文本會被XML解析器忽略。咱們可使用XComment類向一個XML文檔插入文本。以下面代碼所示:
new XComment("This is a comment")
這段代碼產生以下XML文檔:
<!--This is a comment-->
XML文檔從包含XML使用的版本號、字符編碼類型以及文檔是否依賴外部引用的一行開始。這是有關XML的信息,所以它實際上是有關數據的元數據。這叫作XML聲明,可使用XDeclaration類來插入,以下代碼給出了XDeclaration的示例:
new XDeclaration("1.0","uff-8","yes")
這段代碼產生以下XML文檔:
<?xml version="1.0" encoding="utf-8 " standalone="yes"?>
XML處理指令用於提供XML文檔如何被使用和翻譯的額外數據,最多見的就是把處理指令用於關聯XML文檔和一個樣式表。
咱們可使用XProecssingInstruction構造函數來包含處理指令。它接受兩個字符串參數:目標和數據串。如歌處理指令接受多個數據參數,這些參數必須包含在XProecssingInstruction構造函數的第二個字符串參數中,以下的構造函數代碼所示。
new XProecssingInstruction("xml-stylesheet",@"href=""stories"",type=""text/css""")
這段代碼產生以下XML文檔:
<?xml-stylesheet href="stories.css" type="text/css"?>
例:
class Program { static void Main() { XDocument xd=new XDocument( new XDeclaration("1.0","uff-8","yes"), new XComment("This is a comment"), new XProecssingInstruction("xml-stylesheet",@"href=""stories"",type=""text/css"""), new XElement("root", new XElement("first"), new XElement("second") ) ); } }
代碼會產生以下的輸出文件。然而若是使用WriteLine(xd)
,聲明語句不會被打印出來。
如今,咱們能夠把LINQ XML API和LINQ查詢表達式組合爲簡單而強大的XML樹搜索。
例:建立示例用XML樹
class Program { static void Main() { XDocument xd=new XDocument( new XElement("MyElements", new XElement("first", new XAttribute("color","red"), new XAttribute("size","small")), new XElement("second", new XAttribute("color","red"), new XAttribute("size","midium")), new XElement("third", new XAttribute("color","blue"), new XAttribute("size","large")) ) ); Console.WriteLine(xd); xd.Save("SimpleSample.xml"); } }
例:LINQ to XML
class Program { static void Main() { XDocument xd=XDocument.Load("SimpleSample.xml"); XElement rt=xd.Element("MyElements"); var xyz=from e in rt.Elements() where e.Name.ToString().Length==5 select e; foreach(XElement x in xyz) { Console.WriteLine(x.Name.ToString()); } Console.WriteLine(); foreach(XElement x in xyz) { Console.WriteLine("Name: {0}, color: {1}, size: {2}", x.Name, x.Attribute("color").Value, x.Attribute("size").Value); } } }
例:獲取XML樹的全部頂層元素,併爲每一個元素建立了匿名類型對象
using System; using System.Linq; using System.Xml.Linq; class Program { static void Main() { XDocument xd=XDocument.Load("SimpleSample.xml"); XElement rt=xd.Element("MyElements"); var xyz=from e in rt.Elements() select new{e.Name,color=e.Attribute("color")}; //建立匿名類型 foreach(var x in xyz) { Console.WriteLine(x); } Console.WriteLine(); foreach(var x in xyz) { Console.WriteLine("{0,-6}, color:{1,-7}",x.Name,x.color.Value); } } }
從這些示例咱們能夠看到,能夠輕易地組合XML API和LIQN查詢工具來產生強大的XML查詢能力。