https://www.cnblogs.com/moonache/p/6552843.html#wiz_toc_9
LINQ
什么是LINQ
LINQ提供程序
匿名类型
方法语法和查询语法
查询变量
查询表达式的结构
from子句
join子句
什么是联结
查询主体中的from…let…where片段
from子句
let子句
where子句
orderby子句
select…group子句
查询中的匿名类型
group子句
查询延续:into子句
标准查询运算符
标准查询运算符的签名
查询表达式和标准查询运算符
将委托作为参数
LINQ预定义的委托类型
使用委托参数的示例
使用Lamba表达式参数的示例
LINQ to XML
标记语言
XML基础
XML类
创建、保存、加载和显式XML文档
创建XML树
使用XML树的值
增加节点以及操作XML
使用XML特性
节点的其他类型
XComment
XDeclaration
XProecssingInstruction
使用LINQ to XML的LINQ 查询
在关系型数据库系统中,数据被组织放入规范化很好的表中,并且通过简单且强大的SQL语言来进行访问。因为数据在表中遵从某些严格的规则,所以SQL可以和它们很好的配合使用。
然而,在程序中却与数据库相反,保存在类对象或结构中的数据差异很大。因此,没有通用的查询语言来从数据结构中获取数据。从对象获取数据的方法一直都是作为程序的一部分而设计的。然而使用LINQ可以很轻松地查询对象集合。
如下是LINQ的重要高级特性。
例:LINQ示例
class Program { static void Main() { int[] numbers={2,12,5,15}; IEnumerablelowNums= 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种形式。
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}; IEnumerablelowNums=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子句的要点如下:
from Type Item in Items
下图演示了from子句的语法。类型说明符是可选的。可以有任意多个join子句。
尽管LINQ的from子句和foreach语句非常相似,但主要不同点如下:
join子句
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片段
可选的from…let…where部分是查询主体的第一部分,可以由任意数量的3个子句来组合–from子句、let子句和where子句。
from子句
查询表达式从必需的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子句的语法如下:
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子句
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子句根据表达式按顺序返回结果项。
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…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子句
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); } } } }
查询延续:into子句
查询延续子句可以接受查询的一部分结果并赋予一个名字,从而可以在查询的另一部分中使用。
例:连接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是类型例: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
泛型类的扩展方法。
第7章和第17章介绍类扩展方法,在本节是学习如何使用扩展方法的好机会。
简单回顾一下。扩展方法是公共的静态方法,尽管定义在一个类中,但目的是为另一个类(第一个形参)增加功能。该参数前必须有关键字this。
例:3个标准查询运算符的签名
始终是public static 名字和泛型参数 第一个参数 ↓ ↓ ↓ public static int Count(this IEnumerable source); public static T First (this IEnumerable source); public static IEnumerable Where (this IEnumerable 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
对象的引用,之后的参数可以是任何类型。很多运算符接受泛型委托作为参数(第17章)。泛型委托用于给运算符提供用户自定义代码。
为了解释这一点,我们首先从演示Count运算符的几种使用方式的示例开始。
Count运算符被重载且有两种形式,第一种之前示例中用过,它有一个参数,返回集合中元素的个数。
public static int Count(this IEnumerable source);
然而,假设我们希望看看数组中奇数元素的总数。Count方法必须能够检测整数是否为奇数。
我们需要使用Count方法的第二种形式。如下所示,它有一个泛型委托作为参数。调用时,我们提供一个接受单个T类型的输入参数并返回布尔值的委托对象。委托代码的返回值必须指定元素是否包含在总数中。
public static int Count(this IEnumerable source,Func 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); } }
LINQ预定义的委托类型
和前面示例中的Count运算符差不多,很多LINQ运算符需要我们提供代码来指示运算符如何执行它的操作。我们通过委托对象作为参数来实现。
LINQ定义了两套泛型委托类型与标准查询运算符一起使用,即Func委托和Action委托,各有17个成员。
public delegate TR Func(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}; FuncmyDel=new Func (IsOdd); var countOdd=intArray.Count(myDel); Console.WriteLine("Count of odd numbers: {0}",countOdd); } }
使用Lamba表达式参数的示例
之前示例使用独立的方法和委托来把代码附加到运算符上。这需要声明方法和委托对象,然后把委托对象传递给运算符。如果下面的条件任意一个成立,这种方法是不错的方案:
如果这两个条件都不成立,我们可能希望使用更简洁和更局部化的方法来给运算符提供代码,那就是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}; FuncmyDel=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树,它主要由嵌套元素组成。
元素是XML树的基本要素。每个元素都有名字且包含数据,一些元素还包含其他被嵌套元素。元素由开始和关闭标签进行划分。任何元素包含的数据都必须介于开始和关闭标签之间。
例:
开始标签 内容 结束标签 ↓ ↓ ↓Sally Jones ←没有内容的元素
有关XML的重要事项:
Bob Smith 408-555-1000 Sally Jones 415-555-2000 415-555-2001
XML类
LINQ to XML可以以两种方式和XML配合使用。第一种是作为简化的XML操作API,第二种是使用本章前面看到的LINQ查询工具。
我会先介绍API方式。
LINQ to XML API由很多表示XML树组件的类组成。我们主要使用3个类,XElement、XAttribute和XDocument。
下图演示了用于构造XML树的类以及它们如何被嵌套。
除了XAttribute类,大多数用于创建XML树的类都从一个叫做XNode的类继承,一般在书中也叫做“XNodes”。
创建、保存、加载和显式XML文档
例:创建一个包含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树
例:创建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树来获取或修改值时才体现了XML的强大。下表给出了用于获取数据的主要方法。
关于上表,需要注意的一些事项如下:
IEnumerable
类型的对象,因为返回的节点可能是不同的类型,比如XElement、XComment等。我们可以使用以类型作为参数的方法OfType(type)
来指定返回某类型的节点。例如,如下代码只能获取XComment节点
IEnumerable comments=xd.Nodes().OfType()
IEnumerable 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"); IEnumerableemployees=root.Elements(); foreach(XElement emp in employees) { XElement empNameNode=emp.Element("Name"); Console.WriteLine(empNameNode.Value); IEnumerable empPhones=emp.Elements("PhoneNumber"); foreach(XElement phone in empPhones) { Console.WriteLine(phone.Value); } } } }
增加节点以及操作XML
我们可以使用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的方法。
使用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); } }
节点的其他类型
XComment
XML注释由记号间的文本组成。记号间的文本会被XML解析器忽略。我们可以使用XComment类向一个XML文档插入文本。如下面代码所示:
new XComment("This is a comment")
这段代码产生如下XML文档:
XDeclaration
XML文档从包含XML使用的版本号、字符编码类型以及文档是否依赖外部引用的一行开始。这是有关XML的信息,因此它其实是有关数据的元数据。这叫做XML声明,可以使用XDeclaration类来插入,如下代码给出了XDeclaration的示例:
new XDeclaration("1.0","uff-8","yes")
这段代码产生如下XML文档:
XProecssingInstruction
XML处理指令用于提供XML文档如何被使用和翻译的额外数据,最常见的就是把处理指令用于关联XML文档和一个样式表。
我们可以使用XProecssingInstruction构造函数来包含处理指令。它接受两个字符串参数:目标和数据串。如歌处理指令接受多个数据参数,这些参数必须包含在XProecssingInstruction构造函数的第二个字符串参数中,如下的构造函数代码所示。
new XProecssingInstruction("xml-stylesheet",@"href=""stories"",type=""text/css""")
这段代码产生如下XML文档:
例:
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 to XML的LINQ 查询
现在,我们可以把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查询能力。