本文配套源码
最近博客园讨论气氛热烈,有价值的评论也层出不穷。有时候我们会很希望订阅某篇文章的评论RSS ,只可惜博客园目前没有这个功能。对于注册用户来说,我们可以通过点击评论框下方的“订阅回 复”链接,这样就会在出现新评论的时候收到邮件。可惜匿名用户,只得不断刷新才能关注最近讨 论到什么地方了。不过我们是什么人?我们是程序员,这点障碍对我们来说应该是在简单不过的小事了 。自己搭一个站点,获取页面数据,分析HTML,输出为RSS,就这么简单。
老赵为此作了一个最 最简单的示例,可以订阅http://jeffreyzhao.cnblogs.com上任意一篇文章的评论。由于只是简单的个 人工具程序,所以完全不考虑性能、伸缩性、扩展性,容错性,也抛弃任何的单元测试,依赖注入等 “最佳实践”。总之一句话,怎么容易怎么来。
这个示例由两部分组成,第一部分是 个静态HTML页面,根据文章URL生成并转向至其RSS链接。寥寥数行HTML和JavaScript:
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>博客园RSS</title>
<script language="javascript" type="text/javascript">
function goToCommentRss(url) {
window.location = "CommentRss.ashx? url=" + encodeURIComponent(url);
}
</script>
</head>
<body>
<textarea id="url" cols="50" rows="10"></textarea><br />
<input type="button" value="Comment RSS"
onclick="goToCommentRss(document.getElementById('url').value)" />
</body>
</html>
CommentRss.ashx将为我们输出评论的RSS。它的 代码如下:
public class CommentRss : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string url = context.Request.QueryString["url"];
WebClient webClient = new WebClient();
webClient.Encoding = Encoding.UTF8;
string html = webClient.DownloadString(url);
context.Response.ContentType = "text/xml";
context.Response.ContentEncoding = Encoding.UTF8;
SyndicationFeed feed = GetRssFeed(url, html);
Rss20FeedFormatter rssFormatter = new Rss20FeedFormatter(feed);
XmlWriter rssWriter = XmlWriter.Create(context.Response.Output);
rssFormatter.WriteTo(rssWriter);
rssWriter.Close();
}
private static SyndicationFeed GetRssFeed(string url, string html)
{
...
}
public bool IsReusable { get { return false; } }
}
其实.NET框架已经为我们准备了太多太多有用的工具,我们只需要将它们拼 接起来即可。例如有了WebClient类,三行代码便可下载到页面的HTML。然后我们通过GetRssFeed方法来 获得一个SyndicationFeed对象,再通过Rss20FeedFormatter输出。SyndicationFeed和 Rss20FeedFormatter都是.NET 3.5中自带的类库,放在System.ServiceModel.dll程序集中的 System.ServiceModel.Syndication命名空间里,可以方便读取或生成Atom 1.0或RSS 2.0格式的XML为我 们所用。更多信息可以参考InfoQ中文站的这篇报道:WCF的Web编程模型资源。
GetRssReed的关 键在于分析HTML字符串,老赵在这里使用了正则表达式匹配出每条评论的标题、URL、时间、用户和内容 。然后构造出一个SyndicationFeed对象就再简单不过了。可惜的是,博客园不同模板的HTML不同,因此 老赵的这个示例只支持现在用的这个模板。您可以自己改造,例如为CommentRss.ashx增加一个新的参数 ,用于指名HTML的解析方式,便可以用于多个模板了。