2008年4月11日
真是太对不起自己了。
由于工作和生活都忙,还好不是一团乱。
等周会开完,公司的考核结束,我继续写LINQ。
继续我们LINQ的学习,昨天体验了LINQ to Object,今天轮到LINQ to XML的入门程序了。我之前基本上很少用到XML,但经常能从同事的口中听到 XML DOM 和 XQuery 之类的词,可见其普及型之高,不学不行。原来XML常用于各种应用间交换数据,存储配置信息,持久化临时数据,生成网页和报表,无所不能!
虽然应用如此广泛,但是至今为止多数的编程语言都没有生来就支持XML,而是通过API的形式对实现XML的操作,包括 XmlDocument, XmlReader, XPathNavigator, XslTransform for XSLT, SAX和XQuery实现等。最大的问题就是这些乱七八糟的API并没有很好地和编程语言进行集成,往往为了得到某个简单的结果需要编写很多又长又臭的代码。然后LINQ to XML出现了,它主要改善了以往DOM的使用体验,也避免了DOM的某些限制。还是要看看LINQ to XML和DOM的对比。前者以元素为中心,声明式模型,代码有着和XML相类的层次结构,集成编程语言的查询,支持流,代码短小精悍;相比之下后者以文档为中心,命令式模型,代码和文档结构毫不相干,无集成编程语言,全部载入内存,代码冗长。尽管LINQ to XML的灵感源于XSLT, XPath和XQuery,但是LINQ的使用范围还是它们不太一样,功能自然就无法对比,不过LINQ支持和它们的组合使用。
下面是书本上那个简单的例子。
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Text;
5
using System.Xml;
6
using System.Xml.Linq;
7
8
namespace HelloLinqToXml
9

{
10
/**//// <summary>
11
/// Book Class used for Linq query on Objects
12
/// </summary>
13
class Book
14
{
15
public string Publisher
{ get; set; }
16
public string Title
{ get; set; }
17
public int Year
{ get; set; }
18
19
/**//// <summary>
20
/// Contructor for Book Class
21
/// </summary>
22
/// <param name="publisher">Publisher of the book, Type of string</param>
23
/// <param name="title">Title of the book, Type of string</param>
24
/// <param name="year">Publish year of the book, Type of int</param>
25
public Book(string publisher, string title, int year)
26
{
27
Publisher = publisher;
28
Title = title;
29
Year = year;
30
}
31
}
32
class Program
33
{
34
static void Main(string[] args)
35
{
36
//Initialize the object data for Linq query
37
Book[] books = new Book[]
{
38
new Book("Ajax in Action","Manning",2005),
39
new Book("Windows Forms in Action","Manning",2006),
40
new Book("RSS and Atom in Action","Manning",2006)
41
};
42
43
//Contruct a peice of XML fragment
44
XElement xml = new XElement("books",
45
from book in books
46
where book.Year == 2006 //query from object data
47
select new XElement("book",
48
new XAttribute("title", book.Title),
49
new XElement("publisher", book.Publisher)
50
)//add XML Elements and Attibutes
51
);
52
53
Console.WriteLine(xml);
54
Console.ReadLine();
55
}
56
}
57
}
58
看得出来
LINQ to XML在对XML的处理上以元素为中心,因而不必完整地构建一个XML文档,更多的时候XML的片段就够了,就像上面这个HelloWorld的程序,就把内存中某部分数据通过查询后写出XML片段,我们会惊喜地发现用LINQ操作内存对象和操作XML基本相似。我习惯上用的是C#,但书本中给出了VB 9的代码,其声明的方式和ASP相仿,表现得更接近XML本身的文档层次结构。
在展示这段简单的代码之前,书上特意提到了LINQ所需的编译和运行环境要求。大家都知道,LINQ是.NET 3.5中自带的一组升级功能,其实指的是编译器和类库(.NET FX),而不是运行环境(.NET CLR),这就意味着我们用LINQ编写的项目经过编译后,能正常地在.NET 2.0上运行。后来在脚注下标出来说,LINQ to SQL至少要运行在.NET 2.0 SP1之上。
废话说完,开始经典HelloWorld的代码。
1
namespace HelloWorld
2

{
3
class Program
4
{
5
static void Main(string[] args)
6
{
7
string[] words =
{ "Hello", "Wonderful", "Linq", "Beautiful", "World" };
8
9
var groups =
10
from word in words
11
orderby word ascending
12
group word by word.Length into lengthGroups
13
orderby lengthGroups.Key descending
14
select new
{ Length=lengthGroups.Key, Words=lengthGroups};
15
16
foreach (var group in groups)
17
{
18
Console.WriteLine("Words of Length " + group.Length);
19
foreach (var word in group.Words)
20
Console.WriteLine(" " + word);
21
}
22
23
Console.ReadLine();
24
}
25
}
26
}
入门的代码都不难,那我还需要说什么呢?是我从这段代码中看到了使用LINQ强大的灵活性和可扩展性。
其实在这之前还有一个更简单的例子,只是选择了数组中长度小于等于5的单词并输出。但是做过项目的同事就很清楚,客户往往有一些诡异和变幻莫测的需求,他现在不满足于只看到“hello linq world”,而是要想看到所有长度下对应的每一个单词,有可能某个长度的单词集合的个数大于1,他又希望这些单词按字母表顺序罗列,甚至他在考GRE,发自内心地想先看到比较长的单词,所以对于长度的分组要从大到小排列。
要是用以往传统的C#实现,这个需求变更并不太难,大不了先把所有长度找到,再按字母表顺序输出相应的单词。等我们好不容易改好,交给客户,他又不满意了。他说,老罗教我们必须按字母表顺序背单词,但是同一字母开头的单词还是需要先背长的,你给我重新输出个词表吧。这个时候,用传统C#实现的你,肯定会觉得要疯了,因为这次需求变更造成的代码增量应该不小,甚至原来的业务逻辑相当于重新来过,这客户咋这样?没办法,他是上帝,那就再改咯。
不过如果是用LINQ实现,问题的解决方案就变得简单得多得多,只需稍稍改写那句SQL(结构不变,仅调换几个变量的位置和逻辑即可),显示的逻辑基本上都可以不变,代码复用度和效率都大大提高。贴上需求变更后的代码,仅供大家参考,可能还有更好的方案。
1
using System;
2
using System.Collections.Generic;
3
using System.Text;
4
using System.Linq;
5
6
namespace HelloWorld
7

{
8
class Program
9
{
10
static void Main(string[] args)
11
{
12
string[] words =
{ "Hello", "Wonderful", "Linq", "Beautiful", "World" };
13
14
var groups =
15
from word in words
16
orderby word.Length descending
17
group word by word.Substring(0,1) into lengthGroups
18
orderby lengthGroups.Key ascending
19
select new
{ Cap = lengthGroups.Key, Words = lengthGroups };
20
21
foreach (var group in groups)
22
{
23
24
foreach (var word in group.Words)
25
Console.WriteLine(" " + word);
26
}
27
28
Console.ReadLine();
29
}
30
}
31
}
32
虽然这只是一个简单的入门例子,我们已经能感觉到LINQ的强大了,因为LINQ有着类似SQL语句强大的查询功能,再结合简单易控的.NET代码,就像一股积蓄已久的力量喷薄而出,看来MS还是蛮啥的。我相信,用好LINQ,基于.NET的敏捷开发会越来越更快的。
聪聪过生日,赶去聚会了,明天继续。
其实书上讲了一大堆的对比,说传统的数据和对象的访问方法怎么怎么不好,事实上目前大多数的程序员仍然采用以前的套路,只是在个人不同的风格习惯上,会用类似NHibernate之类的工具提高效率,关于这些估计大家都深有体会。但是,LINQ究竟有什么好,我们为什么要使用它?知道这个还是蛮重要的。
书上粗略提了两点:整合使用多重数据类型和数据源,还有就是强类型支持。前者为跨数据源提供了统一的查询语法和数据处理模型,后者则为SQL语句的编译时检查和智能感知的增强提供基础。
LINQ这个东东并不是一天建成的,它是从MS Research好几年的若干项目演化合并而成。最开始就是C-Omega项目,它主要作为数据类型扩展增强C#对XML和数据库之间的操作;接着是ObjectSpaces,它最初就是一套数据访问的API,使数据对象化,实现对象内数据查询功能,不过这个项目由于WinFS的延迟而夭折;最后是Xquery的实现,这部分功能在.NET FX 2.0的第一个预览版出现,但最终却放弃了,因为它完全又是一种附加语言。然后MS就停止了这三个项目,并在PDC 2005上公布了LINQ项目的开始。
既然LINQ主要整合的是内存对象、关系数据库和XML的数据访问,自然可以分成LINQ to Objects,LINQ to SQL 和 LINQ to XML了。下一步就是入门的代码,期待中。一上午的会,累呀。