Jumony(三)第一个公开预览版,在.NET里玩转jQuery选择器!
首先是兑现诺言,上一篇文章中曾经说到源代码会随下一篇文章的发布一同发布。其实我早已打包好了,现在提供下载地址:
http://files.cnblogs.com/Ivony/Jumony_CTP(20100802)_Source.rar
有人说里面漏了HtmlAgilityPack和Ivony.Fluent的源代码。这是因为这两个项目不是Jumony的一部分。HtmlAgilityPack是一个老外的开源项目,而Ivony.Fluent则是一些通用的扩展方法来辅助流畅体验的。不过为了方便大家,也提供这两个项目对应的源代码下载:
Ivony.Fluent的:
http://files.cnblogs.com/Ivony/Ivony.Fluent(ver.62).rar
HtmlAgilityPack的:
http://files.cnblogs.com/Ivony/HtmlAgilityPack(ver.62).rar
ver.62是SVN的内部版本号。
建议大家下载HtmlAgility最新的版本,也许修正了很多Bug,除非HtmlAgilityAdapter与其不兼容。
http://htmlagilitypack.codeplex.com/
其实也有计划做MSHTML的Adapter,但文档翻得眼睛花,暂时作罢。
这个CTP中其实还存在很多的问题,其中已知的问题都已经被修复,将不会在下一个CTP版本中看到,这些包括但不限于:
这是Jumony系列中一篇比较短的文章,与大家一起来探讨Jumony的一些好玩的应用。上一篇文章有很多人留言说下载了Jumony的CTP,但我不知道到底大家有没有真正去玩。这个框架我是一边写,一边玩,玩的过程中产生了大量的需求,然后一一实现。废话不多说,先来看一个截图:
嗯,很明显,这是老赵的博客,似乎没什么奇怪的。但是等等,老赵啥时候写过这些文章?!
没错,这些文章都是博客园首页的!
当然这是一件很简单的事情,从博客园的首页摘取文章内容,再把它填到老赵的博客里面去。说起来似乎很容易,但真正做起来恐怕不是那么简单的事情吧。
那么我们来看看Jumony能够怎样帮助我们解决这种问题?
public void ProcessRequest( HttpContext context )
{
var client = new WebClient();
client.Encoding = System.Text.Encoding.UTF8;
var parser = new JumonyParser();
var cnblogs = parser.Parse( client.DownloadString( "http://www.cnblogs.com/" ) );
var zhaojie = parser.Parse( client.DownloadString( "http://blog.zhaojie.me/" ) );
var baseElement = cnblogs.GetNodeFactory().CreateElement( "base" );
baseElement.SetAttribute( "href" ).Value( "http://blog.zhaojie.me/" );
zhaojie.FindSingle( "head" ).InsertCopy( 0, baseElement );
zhaojie.Find( ".post" ).BindFrom( cnblogs.Find( ".post_item" ), ( cb, zj ) =>
{
zj.FindSingle( "h2 a" ).SetAttribute( "href" ).Value( cb.FindSingle( "h3 a" ).Attribute( "href" ).Value() );
zj.FindSingle( "h2 a" ).InnerText( cb.FindSingle( "h3 a" ).InnerText() );
zj.FindSingle( ".entry strong" ).NextNode().ReplaceCopy( cb.FindSingle( ".post_item_summary" ).Nodes().Last() );
zj.FindSingle( ".icon_comment a" ).SetAttribute( "href" ).Value( cb.FindSingle( ".article_comment a" ).Attribute( "href" ).Value() );
zj.FindSingle( ".icon_comment a" ).InnerText( cb.FindSingle( ".article_comment a span" ).InnerText() + " Comments" );
} );
context.Response.Write( zhaojie );
}
真正干活的其实就五行代码,分别是,把文章的标题、标题连接、文章摘要、回复数量、回复量的链接复制过去。
注意,这段代码用现在发布的这个CTP版本是无法通过编译的,因为现在的这个CTP版本尚不支持InnerText这样的对文档进行修改的方法。
从这个例子我们也能看到C# 3.0的一些不足,如果我们用函数式的语言来写这段代码,就没有这么多乱七八糟的括号,语义也将更加流畅。
而如果用动态语言,我们甚至可以写成:
zj.FindSingle( "h2 a" ).href = cb.FindSingle( "h3 a" ).href;
zj.FindSingle( "h2 a" ).text = cb.FindSingle( "h3 a" ).text;
zj.FindSingle( ".entry strong" ).next = cb.FindSingle( ".post_item_summary" ).nodes.last;
zj.FindSingle( ".icon_comment a" ).href = cb.FindSingle( ".article_comment a" ).href;
zj.FindSingle( ".icon_comment a" ).text = cb.FindSingle( ".article_comment a span" ).text + " Comments";
这并不是痴人说梦,而是Jumony正在努力的方向。
借助CSS选择器,Jumony可以轻易地将HTML文档的表现形式和包含数据完全分离。
在这个例子里,我们可以看到这种流畅的感受,加载博客园的首页,将数据抽出,再加载老赵的博客,将数据填入。一气呵成,比XSLT的语法更为简洁。
当然,我们之所以可以轻易地做到这一点,也与语义网的普及密不可分,由于HTML越来越语义化,我们从中抽取数据的过程便越来越简单。但这并不代表对于脏乱的HTML我们就没有办法抽取,事实上只是麻烦一点而已。
其实,我们有什么必要去做模板呢?
如果你要高兴我的博客长得和老赵的一个样,用Jumony几行代码就搞定了。