手机
当前位置:查字典教程网 >编程开发 >asp.net教程 >用 Asp.Net 建立一个在线 RSS 新闻聚合器的方法
用 Asp.Net 建立一个在线 RSS 新闻聚合器的方法
摘要:随着办公室和家庭上网在线时间的延长,以及Web站点和可访问的互联网应用程序呈持续爆炸性增长,应用程序之间能数据共享变得越来越重要。在异构平台...

随着办公室和家庭上网在线时间的延长,以及Web站点和可访问的互联网应用程序呈持续爆炸性增长,应用程序之间能数据共享变得越来越重要。在异构平台之间共享数据需要一种平台中立的数据格式,这种数据格式要求能易于通过标准的互联网协议来传输,而这正是XML的用武之地。因为XML文件本质上只是一个文本文件,其编码格式众所周知,而且现有的XML解析器能为所有主流编程语言所用,所以XML数据能被任何平台轻松使用。

Web网站聚合就是一种使用XML来共享数据的范例,在新闻站点和网志中经常可以看到。采用Web网站聚合技术,网站能以XML格式的Web可访问的聚合文件来发布最新内容。网站使用的聚合格式有很多种,其中最流行的一种格式就是RSS2.0。(RSS2.0规范被发布在HarvardLaw网站的技术栏目上)。此外,MSDN杂志有一个聚合文件:MSDN杂志:本期刊物,其中列出了最新一期MSDN杂志上的文章,包括到在线版本文章的链接。

一旦Web站点有了公开发布聚合文件,那么不同的客户端就可以消费它。消费聚合文件的方式有很多种,比如,某个提供.NET技术资源的站点可能希望在网站中添加最新的MSDN杂志文章标题。聚合文件还常常被新闻聚合器程序所用,这种程序被专门设计用来获取和显示不同来源的聚合文件。

随着人们越来越注重使用XML数据,在ASP.NET页面中处理XML数据的能力变得比以往更关键。既然Web站点聚合如此重要,本文我们就来创建一个Web站点聚合文件生成程序和一个在线新闻聚合器。在建立这两个微型程序的过程中,我们将讲述如何访问和显示XML数据,不论这些数据是来自远端的Web服务器还是本地的文件系统。我们将演示如何多种不同的方法显示XML数据,比如:用Repeater控件以及用ASP.NETXMLWeb控件。

使用RSS2.0规范的聚合内容

本文我们将要创建的第一个微型程序是一个聚合文件生成器。针对这个迷你程序,假设你是一个大型新闻网站(如MSNBC.com)的Web开发者,所有的新闻内容都保存在MicrosoftSQLServer2000数据库中。具体地说,这些文章是都保存在一个名为Articles的表中,表中以下字段与我们的程序密切相关:

ArticleID—主键,自增长的整型字段,用来唯一标识每一篇文章;

Title—指定标题,字段数据类型:varchar(50);

Author—指定作者,字段数据类型:varchar(50);

Description—新闻内容描述,字段数据类型:varchar(2000);

DatePublished—新闻发布日期,字段数据类型:datetime

请注意,Articles表中可能还有其它字段,上面所列的只是我们在创建聚合文件的时候所要用到的字段。而且,这只是一个非常简单的数据模型,在是应用的数据库环境中,你可能会使用更加标准化的数据库模型,比如具备一个单独的authors(作者)表,有一个建立作者和文章之间多对多关系的表等等。

下一步,我们将创建一个ASP.NET页面,用格式化好的RSS2.0XML文件显示一个最新的新闻列表。在讲述如何在ASP.NET页面中完成这种转换之前,我们要先介绍一下RSS2.0规范的内容。我们应该记住,在整个规范中,RSS是被设计用来为聚合内容提供一个数据模型。那么毫无疑问,它会有一系列的XML元素,用来描述Web站点要聚合的内容信息,以及一系列用来描述某一特定新闻项的XML元素。最后,不要忘记RSS聚合文件是一个XML格式文件,必须符合XML格式化的准则,也就是:

所有XML元素必须正确嵌套;

所有的属性值要用引号包含起来;

<,>,&,"和''符号要相应地替换为<,>,&,"和';

而且,XML格式是大小写敏感的,这就意味着,XML元素的起始和终止标签必须匹配,拼写和大小写都必须一致。

RSS2.0的根元素是<rss>元素,这个元素可以有一个版本号的属性,例如:

<rssversion="2.0">

...

</rss>

<rss>元素只有一个子元素<channel>,用来描述聚合的内容。在<channel>元素里面有三个必需的子元素,用来描述Web站点的信息。这三个元素是:

title—定义聚合文件的名称,一般来说,还会包括Web站点的名称;

link—Web站点的URL;

description—Web站点的一段简短的描述。

除此之外,还有一些可选元素来描述站点信息。这些元素的更多信息请参见RSS2.0规范。

每一个新闻项目放在一个单独的<item>元素中。<channel>元素可以有任意数量的<item>元素。每个<item>元素可以有多种的子元素,唯一的要求是最少必须包含<title>元素和<description>元素其中一个作为子元素。以下列出了一些相关的<item>子元素:

title—新闻项目的标题;

link—新闻项目的URL;

description—新闻项目的大纲;

author—新闻项目的作者;

pubDate—新闻项目的发布日期

下面是一个非常简单的RSS2.0聚合文件。你可以从RSSgeneratedbyRadioUserLand看到其他的RSS2.0文件的例子。

<rssversion="2.0">

<channel>

<title>LatestDataWebControls.comFAQs</title>

<link>http://datawebcontrols.com</link>

<description>

ThisisthesyndicationfeedfortheFAQs

atDataWebControls.com

</description>

<item>

<title>WorkingwiththeDataGrid</title>

<link>http://datawebcontrols.com/faqs/DataGrid.aspx</link>

<pubDate>Mon,07Jul200321:00:00GMT</pubDate>

</item>

<item>

<title>WorkingwiththeRepeater</title>

<description>

ThisarticleexamineshowtoworkwiththeRepeater

control.

</description>

<link>http://datawebcontrols.com/faqs/Repeater.aspx</link>

<pubDate>Tue08Jul200312:00:00GMT</pubDate>

</item>

</channel>

</rss>

关于<pubDate>元素的格式有一点特别重要,再此要讲一下。RSS要求日期必须按照RFC822日期和时间规范进行格式化,此格式要求:开头是一个可选的3字母星期缩写加一个逗号,接着必须是日加上3字母缩写的月份和年份,最后是一个带时区名的时间。另外,要注意<description>子元素是可选的:上述文件第一个新闻没有<description>元素,而第二个新闻就有一个。

通过ASP.NET页面输出聚合内容

现在,我们已经知道了如何按照RSS2.0规范存储我们的新闻项,我们已经就绪创建一个ASP.NET页面,当用户发出请求时,就会返回网站聚合的内容。更确切地说,我们将建立一个名字叫rss.aspx的ASP.NET页面,这个页面会按照RSS2.0规范的格式返回Articles数据库表中的最新的5个新闻项。

可以有几种方法来完成这件事,稍后将会讲到。但是现在,我们首先要完成一件事,那就是先要从数据库中获得最新的5个新闻项。这可以用下面的SQL查询语句获得:

SELECTTOP5ArticleID,Title,Author,Description,DatePublishedFROMArticlesORDERBYDatePublishedDESC

获得了这些信息以后,我们需要把这些信息转换成相应的RSS2.0格式聚合文件。要把数据库的数据显示为XML数据最简单、快速的方法就是使用Repeater控件。准确地说,Repeater控件将在HeaderTemplate和FooterTemplate模版里显示<rss>元素、<channel>元素以及站点相关的元素标签,在ItemTemplate模版里面显示<item>元素。下面是我们这个ASP.NET页面(.aspx文件)的HTML部分:

<%@Pagelanguage="c#"ContentType="text/xml"Codebehind="rss.aspx.cs"

AutoEventWireup="false"Inherits="SyndicationDemo.rss"%>

<asp:Repeaterid="rptRSS"runat="server">

<HeaderTemplate>

<rssversion="2.0">

<channel>

<title>ASP.NETNews!</title>

<link>http://www.ASPNETNews.com/Headlines/</link>

<description>

ThisisthesyndicationfeedforASPNETNews.com.

</description>

</HeaderTemplate>

<ItemTemplate>

<item>

<title><%#FormatForXML(DataBinder.Eval(Container.DataItem,

"Title"))%></title>

<description>

<%#FormatForXML(DataBinder.Eval(Container.DataItem,

"Description"))%>

</description>

<link>

http://www.ASPNETNews.com/Story.aspx?ID=<%#

DataBinder.Eval(Container.DataItem,"ArticleID")%>

</link>

<author><%#FormatForXML(DataBinder.Eval(Container.DataItem,

"Author"))%></author>

<pubDate>

<%#String.Format("{0:R}",

DataBinder.Eval(Container.DataItem,

"DatePublished"))%>

</pubDate>

</item>

</ItemTemplate>

<FooterTemplate>

</channel>

</rss>

</FooterTemplate>

</asp:Repeater>

首先要注意的是:上面这段代码例子只包括Repeater控件,没有其它的HTML标记或Web控件。这是因为我们希望页面只输出XML格式的数据。实际上,观察一下@Page指令,你就会发现ContentType被设置为XMLMIME类型(text/xml)。其次要注意的是:在ItemTemplate模版里,当在XML输出中添加数据库字段Title、Description和Author时,我们调用了辅助函数FormatForXML()。我们很快就会看到,该函数被定义在后台编码的类中,其作用只是将非法的xml字符替换为它们对应的合法的转义字符。最后我们应该注意,在<pubDate>元素里面的数据库字段DatePublished是用String.Format来格式化的。标准的格式描述符“R”对DatePublished的值进行相应的格式化。

此Web页面的后台编码类代码并不复杂。Page_Load事件处理函数只是将数据库查询结果绑定到Repeater控件,FormatForXML()函数根据需要做一些简单的字符串替换。为简单起见,下面的例子只列出了这两个函数的代码:

在浏览器中访问rss.aspx页面的截图参见图一。

图一通过浏览器访问Rss.aspx页面

在我们生成在线新闻聚合器之前,让我谈谈这个聚合引擎一些可能的增强功能。首先,每一次访问rss.aspx页面的时候,都要访问一次数据库。如果预期可能有大量的人频繁地访问rss.aspx页面,使用输出缓存是很有价值的。其次,通常新闻网站会将聚合的内容分为不同的类别。例如:News.com有一些专门的聚合内容区,比如针对企业计算、电子商务、通信的内容等等。在数据库表Articles中加入表示类别的Category字段就可以很容易地提供这种支持。这样一来,在rss.aspx页面中,可以接收一个表示显示分类的查询参数,然后只搜索指定的新闻项分类即可。

在ASP.NET页面中使用聚合摘要

为了测试我们刚建立的聚合引擎,我们将创建一个在线新闻聚合器,允许采集任意数量的聚合内容摘要。聚合器的界面很简单,参见图二。它包括三个框架页面。左边框架以列表形式列出了不同的聚合内容摘要。右上部框架显示所选的聚合内容摘要包含的新闻项以及查看该新闻项的链接。最后,在右下部框架则显示选中的新闻项标题和内容。顺便提及一下,这样的界面基本上是各种类型的聚合器的一个事实上的标准界面,包括新闻聚合器、email客户端软件和新闻组阅读器都是这样的界面。

图二新闻聚合器用户界面的截图

第一步是创建一个html页面来建立框架用户界面。幸运的是,在VisualStudio.NET2003中,这一过程非常容易。只需要在Web应用程序解决方案中添加一个新的项目,选择新项目类型为Frameset。(我在我的工程中将这个新文件命名为NewsAggregator.htm。我之所以将它设置为html文件而不是asp.net页面,是因为这个页面只包括建立框架的html代码。每一个单独的框架会显示一个asp.net页面)。下一步,参见图三,Frameset模版向导会启动,简单地选择选项“NestedHierarchy”,然后按ok按钮就可以了。

图三VS2003中Frameset模版向导画面

然后Frameset模版向导会创建一个HTML页面,里面已经加入了框架的源代码。只要将左边框架的src属性设置为DisplayFeeds.aspx,它是列表显示聚合摘要asp.net页面的url。至此NewsAggreator.htm页面就完成了。

以下三个部分,我们将讲述如何创建在线新闻聚合器的三个组件,它们分别是显示聚合摘要列表的DisplayFeeds.aspx;显示特定聚合摘要新闻项的DisplayNewsItems.aspx;以及显示指定聚合摘要特定新闻项具体内容的DisplayItem.aspx。

显示聚合摘要列表

现在我们需要创建DisplayFeeds.aspx页面。该页面要显示订阅的聚合摘要列表。作为示范,我将这些聚合摘要放在一个叫Feeds的数据库表中。当然你也可以将它们放在一个XML文件中。表Feeds有如下四个字段:

FeedID—主键,自增长整数类型,唯一标示一个摘要

Title—摘要名称,数据库字段类型:varchar(50)

URL—RSS摘要的URL,数据库字段类型:varchar(150)

UpdateInterval—摘要更新频率(分钟),数据库字段类型:int

DisplayFeeds.aspx页面使用一个DataGrid控件显示聚合摘要的列表。这个DataGrid只有一个HyperLinkColumn列,显示Title字段的内容并且链接到DisplayNewsItems.aspx页面,在查询字符串中要传递FeedID字段的值。以下是DataGrid控件的声明,为简单起见,省略了一些无关的部分):

<asp:DataGridid="dgFeeds"runat="server"

AutoGenerateColumns="False"...>

...

<Columns>

<asp:HyperLinkColumnTarget="rtop"

DataNavigateUrlField="FeedID"

DataNavigateUrlFormatString="DisplayNewsItems.aspx?FeedID={0}"

DataTextField="Title"HeaderText="RSSFeeds">

</asp:HyperLinkColumn>

</Columns>

</asp:DataGrid>

这里要注意的关键是HyperLinkColumn列的定义。它的Target属性设置为右上部分框架的名称,这样当用户点击的时候,DisplayNewsItems.aspx页面就会显示在右上部分的框架中。另外,属性DataNavigateUrlField、DataNavigateUrlFormatString和DataTextField也做了相应的设置,以便超链接显示摘要的标题,并且当点击它时,就会将用户带到DisplayNewsItems.aspx页面,并在查询串中将FeedID字段的内容传过来。(该页面的后台代码类只访问来自Feeds表的摘要清单,按照Title字段的字母顺序返回,接着将查询结果绑定到DataGrid控件。由于篇幅所限,本文在此不列出代码。)

显示特定聚合摘要的新闻项

我们面临的下一个任务是创建DisplayNewsItems.aspx页面。这个页面会以链接的形式显示所选聚合摘要的新闻项标题,当点击标题时,新闻的内容就会显示在右下部分的框架中。要完成这一任务,我们会面临以下两个主要的挑战:

通过指定的URL访问RSS聚合摘要;

将接收到的XML数据转换为相应的HTML;

幸运的是,在.NET框架中,要实现这两个任务都不是很难。对于第一个任务,只需要两行代码,我们就可以将远程的xml数据装载到一个XmlDocument对象中。而第二个任务呢,借助ASP.NETXMLWeb控件在ASP.NET页面中显示XML数据也比较容易。

XMLWeb控件被设计用于在Web页面中显示原始或者转换过的XML数据。使用XMLWeb控件的第一步是定义XML数据源,通过定义一系列的属性,用许多方法都可以完成这一工作。使用Document属性,你可以指定一个XmlDocument实例作为XMLWeb控件的XML数据源。如果XML数据存在于Web服务器文件系统的一个文件中,可以用DocumentSource属性,只要提供该XML文件的相对或者绝对路径就可以了。最后,如果你的XML数据是一个字符串,那么你可以将这个字符串的内容赋给控件的DocumentContent属性。这三种办法都可以将XML数据与XML控件联系起来。

通常,在将XML数据显示到Web页面之前,我们会以某种方式转换XML数据。XMLWeb控件允许我们指定一个XSLT样式表来做这个转换工作。与XML数据相似,XSLT样式表可以通过两个属性之一,以两种不同的方式中的一种来设置,一是Transform属性可被赋值给XslTransform实例,二是将本地Web服务器上XSLT文件的相对或绝对路径赋予TransformSource属性。

现在我们来创建DisplayNewsItems.aspx页面。在添加XMLWeb控件以及编写后台代码类之前,我们需要在HTML部分加入一小段客户端JavaScript代码。准确地说,是在html部分的<head>标签里面添加如下的<script>代码块:

<scriptlanguage="javascript">

//displayablankpageinthebottomframewhenthenewsitemsloads

parent.rbottom.location.href="about:blank";

</script>

每当DisplayNewsItems.aspx页面装载的时候,这段客户端JavaScript代码会在右下角的框架中显示一个空白页。为了理解为什么要加入这段代码,我们来看看省略这段代码,我们会碰到什么情况:

用户在左边的框架中点击聚合摘要,浏览器会在右上部的框架中装载摘要新闻项;

用户在右上部框架中点击某个新闻项,浏览器会在右下部框架中装载这个新闻项的详细内容;

现在用户在左边的框架中点击其它的聚合摘要,浏览器会在右上部分的框架中装载新的摘要新闻项;

现在,前一个新闻项的详细内容还显示在右下部的框架中!通过上面的客户端Javascript代码,每次点击左面框架的摘要便可以清除右下部框架的内容,以消除这一瑕疵。

现在我们处理了客户端代码的问题之后,让我们把注意力转到添加XMLWeb控件。一旦加入XMLWeb控件,将其ID属性设置为xsltNewsItems,TransformSourc属性设置为NewsItems.xslt(我们将要创建的XSLT样式表文件的名称)。现在,在Page_Load事件处理函数中,我们需要在某个XmlDocument实例中获取远程RSS聚合文件,然后将该XMLWeb控件的Document属性赋给该XmlDocument实例。

在Page_Load事件处理函数中,与我们要实现的任务有密切关系的代码是最后三行代码。这三行代码创建一个新的XmlDocument对象,加载远程RSS摘要内容,然后将这个XmlDocument对象赋给XMLWeb控件的Document属性。访问远程XML数据并将它们显示在ASP.NET页面中就是这么简单,难道给你留下的印象不深吗?

剩下我们要做的一件事就是创建XSLT样式表,NewsItems.aspx。下面是样式表的第一版的草稿:

<?xmlversion="1.0"encoding="UTF-8"?>

<xsl:stylesheetversion="1.0"

xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:outputmethod="html"omit-xml-declaration="yes"/>

<xsl:templatematch="/rss/channel">

<b><xsl:value-ofselect="title"

disable-output-escaping="yes"/></b>

<xsl:for-eachselect="item">

<li>

<a>

<xsl:attributename="href">

DisplayItem.aspx?ID=<xsl:numbervalue="position()"/>

</xsl:attribute>

<xsl:attributename="target">rbottom</xsl:attribute>

<xsl:value-ofselect="title"

disable-output-escaping="yes"/>

</a>

(<xsl:value-ofselect="pubDate"/>)

</li>

</xsl:for-each>

</xsl:template>

</xsl:stylesheet>

这个XSLT样式表只有一个模版,用于匹配“/rss/channel”XPath表达式。这个模版先是以粗体显示<title>元素的内容。然后,循环获取每一个<item>元素,对于每一个元素,显示一个到DisplayItem.aspx页面的超链接,在查询字符串中传递<item>元素的位置属性。要留意超链接的target属性设置为rbottom,右下部框架的名称。最后,显示每一个新闻项的标题和<pubDate>元素。

该XSLT样式表中有两个项目,并不是每个人都熟悉。首先是<xsl:value-of>元素中的disable-output-escaping="yes"属性。从本质上讲,这个属性的设置通知XSLT引擎不要转义那些非法的XML字符,比如:&,<,>,"和''。为了理解这个设置的意义,就要知道,如果不设置该属性(也就是设置为默认值"no"),那么如果标题包含一个转义的&字符&,那么输出的html文件中也会有一个&,而不单单是一个字符&。如果你再仔细想一想,你会发现这种情况会导致很多问题。例如,假设一个聚合文件的标题是“Matt''s<i>Cool</i>Blog”,如果输出转义没有被禁止,那么输出就会保留“Matt''s<i>Cool</i>Blog”,在Web页面就会显示为"Matt''s<i>Cool</i>Blog"。当用disable-output-escaping="yes"设置禁止输出转义时,输出就不会被转义,上面的内容就会被当作“Matt''s<i>Cool</i>Blog”,显示在页面上就是我们想要的“Matt''sCoolBlog”。

另一个要注意的是元素<a>。这个奇怪的语法会生成下面的输出内容:

<ahref="DisplayItem.aspx?ID=position">newsitemtitle</a>

之所以要使用这种语法,是因为要给XSLT样式表中某个你要创建的元素添加一个属性,然后在该元素的标签里使用<xsl:attribute>语法。有关该语法的一些例子可在W3Schools网站上找到:The<xsl:attribute>Element。

最后要注意的是,超链接的ID查询字符串的值是来自于<xsl:number>元素,从position()函数中返回的值。<xsl:number>元素仅仅是输出一个数值。position()函数是一个XPath函数,用来返回XML文档中当前节点的顺序位置。这意味着对于第一个新闻项,position()函数返回1,第二个新闻项,position函数返回2,以此类推。我们需要记录这个值并将它通过查询字符串传递出去。这样当DisplayItem.asp页面被访问时,就可以知道显示RSS聚合摘要的什么项目了。

聪明的读者可能已经注意到,我们的XSLT样式表没有全部完成,因为FeedID参数没有通过查询字符串传递到DisplayItem.aspx页面。要明白这是为什么,我们回顾一下在ID查询串参数中所传递的是用户拟察看详细信息的<item>元素顺序号。也就是说,如果用户点击第四条新闻项,页面DisplayItem.aspx?ID=4就会被加载到右下部分的框架中。问题在于DisplayItem.aspx页面无法确定用户希望查看哪一个摘要。有两个不同的方法可以解决这个问题,比如可以在右下部框架中用客户端Javascript代码读取右上部框架的URL,然后确定FeedID的值。在我看来,更简单的办法是和ID参数一起将FeedID的值通过查询字符串传递。

这样的话,有一个难题是XSLT样式表操纵的RSSXML数据中并没有FeedID值。但是DisplayNewsItems.aspx页面知道FeedID值,需要一种方法让XSLT样式表也知道这个值。通过使用XSLT参数可以实现完成。

XSLT参数的使用是非常简单。在XSLT样式表中,你需要在<xsl:template>元素中加入一个<xsl:param>元素,该元素提供参数的名称。下面的代码将这个参数命名为FeedID:

<xsl:stylesheetversion="1.0"

xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:templatematch="/rss/channel">

<xsl:paramname="FeedID"/>

...

</xsl:template>

</xsl:stylesheet>

现在,就可以用下面的语法在<xsl:value-of>元素中使用这个参数了:

<xsl:value-ofselect="$parameterName"/>

最后,在我们的XSLT样式表中加入下面的代码,我们就可以把FeedID查询字符串参数加到超链接中了:

<a>

<xsl:attributename="href">DisplayItem.aspx?ID=<xsl:number

value="position()"/>&FeedID=<xsl:value-ofselect="$FeedID"

/></xsl:attribute>

注意在ID查询字符串参数后面我们加了一个&字符(转义&),这样我们就可以传递FeedID参数的值到查询字符串的FeedID参数中了。这就是我们要在XSLT样式表中添加的内容。

剩下的工作是在DisplayNewsItems.aspx页面的Page_Load事件处理函数中设置这个参数的值。通过使用XsltArgumentList类可以完成这一工作。这个类有一个AddParameter()方法。一旦我们创建了这个类的一个实例,加入了相应的参数,就可以将这个实例赋给XMLWeb控件的TransformArgumentList参数了。下面的代码显示了更新后的DisplayNewsItems.aspx页面Page_Load事件处理函数:

显示特定新闻项的详细内容

还剩下最后一件需要做的事情是显示用户选择的特定新闻项的详细内容。这些详细内容将显示在右下部的框架中,而且将会显示新闻项的标题,描述和新闻项的链接等信息。和DisplayNewsItem.aspx页面类似,DisplayItem.aspx页面首先将根据传入的FeedID查询字符串参数获取远程的RSS聚合摘要,然后它会用XMLWeb控件显示这些详细内容。实际上,DisplayItem.aspx页面的Page_Load事件处理函数和DisplayNewsItem.aspx页面的该函数几乎一样,只有以下两个小小的区别:

DisplayItem.aspx页面需要读取ID查询字符串参数的值;

DisplayItem.aspx页面使用一个XSLT参数,但是这个参数与DisplayNewsItem.aspx页面用的参数是不一样的;

DisplayNewsItem.aspx和DisplayItem.aspx页面一样都需要在参数中传递一个XSLT样式表。DisplayNewsItem.aspx页面传递的是参数FeedID,而DisplayItem.aspx还需要传入ID参数,它表示XSLT样式表应该显示那个新闻项。这个细小的差别在以下代码中以粗体显示,以下代码省略了与DisplayNewsItems.aspx页面相同的部分:

以下是转换XML数据的XSLT样式表:

<?xmlversion="1.0"encoding="UTF-8"?>

<xsl:stylesheetversion="1.0"

xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:outputmethod="html"omit-xml-declaration="yes"/>

<xsl:paramname="ID"/>

<xsl:templatematch="/rss/channel">

<b><xsl:value-ofselect="item[$ID]/title"

disable-output-escaping="yes"/></b>

<p>

<xsl:value-ofselect="item[$ID]/description"

disable-output-escaping="yes"/>

</p>

<a>

<xsl:attributename="href"><xsl:value-of

select="item[$ID]/link"/></xsl:attribute>

<xsl:attributename="target">_blank</xsl:attribute>

ReadMore...

</a>

</xsl:template>

</xsl:stylesheet>

注意<xsl:param>元素被用于声明IDXSLT参数。然后,在几个不同的<xsl:value-of>元素中,ID参数被用来从<item>元素列表中抓取特定的<item>元素。在XPath的语法中,elementName[i]意思是根据相应元素名存取第i个元素。例如,item[1]将只获取第一个<item>元素,item[2]则获取第二个元素。所以item[$ID]是获取由XSLT参数ID定义的特定<item>元素。

最后,值得注意的还有在样式表靠近末尾部分的超链接ReadMore…,它的target属性设为空,这样的话当用户点击ReadMore…链接的时候,浏览器会打开一个新的窗口。

未来的扩展和当前程序的缺点

本文讲述的代码中有一个明显的缺点就是每次用户点击左边框架的某个聚合摘要或者在右上部框架点击某个新闻项时,远程聚合摘要都会被装载和解析。每次用户点击远程聚合摘要时,所有的项都被加载,这样的效率无疑是很差的。每次用户点击一个新闻项标题就重新装载整个远程聚合摘要也是很浪费资源的。这样的方法不仅没有效率,对提供发布服务的个人或者公司也是不礼貌的,因为这些连续的、不没必要的请求占用了他们的Web服务器的负载资源。

这个缺点在本文附带的源代码中已经得到解决。具体来说,.NET数据缓存可以用来存放不同摘要的XmlDocument对象。缓存间隔设置为数据表Feeds中UpdateInterval字段定义的值。(当然,由于某些原因,摘要的XmlDocument对象有可能会被提前清除出缓存)

这个系统的另外一个缺点是在右上部框架和右下部框架之间没有状态的保存。为了说明这样会引起什么问题,考虑以下的动作:

用户点击左边框架的某个聚合摘要链接,在右上部框架中装载这个摘要的新闻项目。假设这个摘要的UpdateInterval的值是30,则表示这些内容在30分钟之后会过期;

装载右上部框架的新闻项的同时,这些内容被缓存起来;

用户离开去吃午饭;

发布聚合内容的网站增加了一条新的新闻项;

我们的用户一个小时午饭后回来了,这个摘要的XmlDocument的缓存已经过期;

用户点击右上部框架的第一条新闻项,将会在右下部分框架中装载DisplayItem.aspx,传入ID参数值1;

DisplayItem.aspx页面在缓存中没找到XmlDocument对象,只好重新获取远程摘要。这样就会获得新的数据了(别忘了,步骤4已经加了一个新的新闻项),然后此页面会显示第一条新闻项目(因为ID参数的值为1);

用户看到了新的新闻项,但是内容会令他感到有点困惑,因为已经不是他所点击的那一条新闻了,而且右上部也没有显示那条新的新闻。

之所以出现这样的问题,是因为ID参数没有唯一地标识一个新闻项,它只是一个特定时间点上新闻项列表中的一个偏移量。解决这个问题的一个好的方法是不要用数据缓存来保存聚合摘要,而是使用数据库或者持久介质的其它方式(比如Web服务器本地文件系统的XML文件)。如果使用数据库,每一个新闻项都可以拥有一个唯一的标识号,可以用来传递到右下角的框架中。这种方法可以保证解决上面提到的问题。当然也会增加系统的复杂性,比如需要决定何时从数据库中清除掉旧的新闻项。

本文现有的应用程序还缺少异常处理,而这肯定是应该加上的。尤其是当从远程RSS聚合摘要文件获取数据并加载到XmlDocument对象时,应该加上异常处理。因为远程的文件可能不存在或者格式不正确。

还有很多增强功能可以轻松地加入到这个在线新闻聚合器。一个明显的功能是需要一个管理页面来允许用户添加,删除和编辑他们现在的聚合摘要。还有,如果能允许用户自定义分类,将他们的聚合摘要按类别放在一起就更好了。另外,现在的用户界面还是比较粗糙的,但是通过增加一些XSLT样式表生成的HTML代码或者在几个框架里面增加一些样式表就可以很容易地美化一下界面。最后,在html标签里面加一些<meta>元素,可以让右上部框架定时地去刷新,使得用户不用自己手工去刷新页面就可以看到最新的新闻项目。

注解(2003年8月4日):在这篇文章发布以后,一些读者用Email告诉通知我在显示特定RSS聚合项的<description>元素时,有两个潜在的问题:

1、Disable-output-encoding属性,这个属性用在<xsl:value-of>元素中,但是并不是所有的XSLT解析器都实现了这个功能。.NETXSLT解析器支持disable-output-encoding,但是还是要注意一下,因为读者可能试图将这个应用程序移植到其它平台。

2、<description>元素的HTML内容是被原封不动地输出的。但是,这些HTML内容可能包含恶意代码,比如<script>或者<embed>代码块。理想情况下,这些代码应该被剔除掉。为了清除掉这些有潜在危险的代码,可能需要用到一些扩展函数(参见ExtendingXSLTwithJScript,C#,andVisualBasic.NET)。想查看从RSS聚合摘要剔除HTML内容的更多信息,可以参见''DiveIntoMark''日志。

总结

在本文中,我们不仅讲到如何创建一个聚合引擎,还创建了一个在线新闻聚合器。在建立这两个应用程序时,我们都采用了在ASP.NET页面显示XML数据的技术。在聚合引擎里面,我们使用了Repeater控件以XML格式来显示数据库中的数据。而在新闻聚合器里面,我们使用了XMLWeb控件和XSLT样式表。

【用 Asp.Net 建立一个在线 RSS 新闻聚合器的方法】相关文章:

ASP.NET如何获取两个日期之间的天数

ASP.NET从客户端中检测到有潜在危险的request.form值的3种解决方法

将Asp.Net网站发布到IIS的四种方法

ASP.NET实现推送文件到浏览器的方法

asp.net验证一个字符串是否符合指定的正则表达式

asp.net 时间类 一周的周一和周末的日期

引用全局程序集缓存内的程序集的方法

ASP.Net防止刷新自动触发事件的解决方案

ASP.Net生成一个简单的图片

asp.net C#检查URL是否有效的方法

精品推荐
分类导航