概要
本文讲解了如何使用 XML Web 控件获取远程XML数据并在 ASPNET 页面显示这些XML数据以及使用Repeater控件发布数据库中的XML数据在过去的几年间随着 异构平台间共享数据的需求不断增长XML的使用也呈爆炸性增长意识到这种趋势微软在整个NET框架中对 XML 提供了健壮的支持这意味着对于 ASPNET 开发者来说在Web页面 中显示和处理 XML 数据从来没有这么容易过本文将通过生成一个 RSS 聚合引擎和在线新闻聚合器来学习 XML 和 ASPNET 技术 本文假设读者熟悉 ASPNET 和 XML
简介
随着办公室和家庭上网在线时间的延长以及 Web 站点和可访问的互联网应用程序呈持续爆炸性增长应用程序之间能数据共享变得越来越重要在 异构平台之间共享数据需要一种平台中立的数据格式这种数据格式要求能易于通过标准的互联网协议来传输而这正是XML的用武之地因为XML文件本质上 只是一个文本文件其编码格式众所周知而且现有的XML解析器能为所有主流编程语言所用所以XML数据能被任何平台轻松使用
Web 网站聚合就是一种使用 XML 来共享数据的范例在新闻站点和网志中经常可以看到采用 Web 网站聚合技术网站能以 XML 格式的 Web 可访问的聚合文件来发布最新内容网站使用 的聚合格式有很多种其中最流行的一种格式就是 RSS( RSS 规范被发布在 Harvard Law 网站 的技术栏目上)此外MSDN 杂志有一个聚合文件MSDN杂志本期刊物 其中列出了最新一期 MSDN 杂志上的文章包括到在线版本文章的链接
一旦 Web 站点有了公开发布聚合文件那么不同的客户端就可以消费它消费聚合文件的方式有很多种比如某个提供 NET 技术资源的站点可能希望在网站中 添加最新的 MSDN 杂志文章标题聚合文件还常常被新闻聚合器程序所用这种程序被专门设计用来获取和显示不同来源的聚合文件
随着人们越来越注重使用 XML 数据在 ASPNET 页面中处理 XML 数据的能力变得比以往更关键既然 Web 站点聚合如此重要 本文我们就来创建一个 Web 站点聚合文件生成程序和一个在线新闻聚合器在建立这两个微型程序的过程中我们将讲述如何访问和显示XML数据不论这些数据是来自远端的Web服务器还是本地的文件系统我们将演示如 何多种不同的方法显示XML数据比如用 Repeater 控件以及用 ASPNET XML Web控件
使用 RSS 规范的聚合内容
本文我们将要创建的第一个微型程序是一个聚合文件生成器针对这个迷你程序假设你是一个大型新闻网站(如 )的 Web 开发者所有的新闻内容都保存在 Microsoft SQL Server 数据库中具体地说这些文章是 都保存在一个名为 Articles 的表中表中以下字段与我们的程序密切相关
ArticleID—主键自增长的整型字段用来唯一标识每一篇文章
Title— 指定标题字段数据类型 varchar()
Author—指定作者字段数据类型 varchar()
Description—新闻内容描述字段数据类型 varchar()
DatePublished—新闻发布日期字段数据类型datetime
请注意Articles 表中可能还有其它字段上面所列的只是我们在创建聚合文件的时候所要用到的字段而且这只是一个非常简单的数据模型在 是应用的数据库环境中你可能会使用更加标准化的数据库模型比如具备一个单独的 authors (作者)表有一个建立作者和文章之间多对多关系的表等等
下一步我们将创建一个ASPNET页面用格式化好的 RSS XML 文件显示一个最新的新闻列表在讲述如何在 ASPNET 页面 中完成这种转换之前我们要先介绍一下 RSS 规范的内容我们应该记住在整个规范中RSS 是被设计用来为聚合内容提供一个数据模型那么 毫无疑问它会有一系列的 XML 元素用来描述 Web 站点要聚合的内容信息以及一系列用来描述某一特定新闻项的 XML 元素最后不要忘记 RSS 聚合文件是一个 XML 格式文件必须符合 XML 格式化的准则 也就是
所有 XML元素必须正确嵌套
所有的属性值要用引号包含起来
< > & 和符号要相应地替换为 <> & 和 &apos
而且XML格式是大小写敏感的这就意味着XML元素的起始和终止标签必须匹配拼写和大小写都必须一致
RSS 的根元素是<rss>元素这个元素可以有一个版本号的属性例如
<rss version=>……
</rss>
<rss>元素只有一个子元素<channel>用来描述聚合的内容在<channel>元素里面有三个必需的子元素用来描述 Web 站点的信息这三个元素是
title—定义聚合文件的名称一般来说还会包括Web站点的名称
link—Web站点的URL
description—Web站点的一段简短的描述
除此之外还有一些可选元素来描述站点信息这些元素的更多信息请参见 RSS规范
每一个新闻项目放在一个单独的<item>元素中<channel>元素可以有任意数量的<item>元素每个<item>元素可以有多种的子元素唯一的要求是最少必须包含<title>元素和<description>元素其中一个作为子元素以下列出了一些相关的<item> 子元素
title—新闻项目的标题
link—新闻项目的URL
description—新闻项目的大纲
author—新闻项目的作者
pubDate—新闻项目的发布日期
下面是一个非常简单的 RSS 聚合文件你可以从 RSS generated by Radio UserLand 看到其他的RSS文件的例子
<rss version=><channel><title>Latest FAQs</title><link></link><description>This is the syndication feed for the FAQs at </description><item><title>Working with the DataGrid</title><link>x</link><pubDate>Mon Jul GMT</pubDate></item><item><title>Working with the Repeater</title><description>This article examines how to work with the Repeater control</description><link>x</link><pubDate>Tue Jul GMT</pubDate></item></channel></rss>
关于<pubDate>元素的格式有一点特别重要再此要讲一下RSS 要求日期必须按照 RFC 日期和时间规范 进行格式化此格式要求开头是一个可选的字母星期缩写加一个逗号接着必须是日加上字母缩写的月份和年份最后是一个带时区名的时间另外要注意 <description> 子元素是可选的上 述文件第一个新闻没有 <description> 元素而第二个新闻就有一个
通过ASPNET 页面输出聚合内容
现在我们已经知道了如何按照 RSS 规范存储我们的新闻项我们已经就绪创建一个 ASPNET 页面当用户发出请求时就会返回网站聚合 的内容更确切地说我们将建立一个名字叫 rssaspx 的 ASPNET 页面这个页面会按照 RSS 规范的格式返回 Articles 数据库表中的最新的 个新闻项
可以有几种方法来完成这件事稍后将会讲到但是现在我们首先要完成一件事那就是先要从数据库中获得最新的个新闻项这可以用下面的 SQL 查询语句获得
SELECT TOP ArticleIDTitleAuthorDescriptionDatePublished FROM Articles ORDER BY DatePublished DESC
获得了这些信息以后我们需要把这些信息转换成相应的 RSS 格式聚合文件要把数据库的数据显示为XML数据最简单快速的方法就是使用 Repeater 控件准确地说Repeater 控件 将在 HeaderTemplate 和 FooterTemplate 模版里显示<rss>元素<channel>元素以及站点相关的 元素标签在 ItemTemplate 模版里面显示 <item> 元素下面是我们这个 ASPNET 页面(aspx文件)的 HTML 部分
<%@ Page language=c# ContentType=text/xml Codebehind=rssaspxcs AutoEventWireup=false Inherits=SyndicationDemorss %><aspRepeater id=rptRSS runat=server><HeaderTemplate><rss version=><channel><title>ASPNET News!</title><link></link><description>This is the syndication feed for </description></HeaderTemplate>
<ItemTemplate><item><title><%# FormatForXML(DataBinderEval(ContainerDataItemTitle)) %></title><description><%# FormatForXML(DataBinderEval(ContainerDataItemDescription)) %></description><link>x?ID=<%# DataBinderEval(ContainerDataItem ArticleID) %></link><author><%# FormatForXML(DataBinderEval(ContainerDataItemAuthor)) %></author><pubDate><%# StringFormat({R}DataBinderEval(ContainerDataItemDatePublished)) %></pubDate></item></ItemTemplate>
<FooterTemplate></channel></rss></FooterTemplate></aspRepeater>
首先要注意的是上面这段代码例子只包括 Repeater 控件没有其它的 HTML 标记或 Web 控件这是因为我们希望页面只输出 XML 格式的数据实际上观察一下 @Page 指令你就会发现 ContentType 被设置为XML MIME 类型(text/xml)其次要注意的是在 ItemTemplate 模版里当 在 XML 输出中添加数据库字段TitleDescription 和 Author 时我们调用了辅助函数 FormatForXML()我们 很快就会看到该函数被定义在后台编码的类中其作用只是将非法的 xml 字符替换为它们对应的合法的转义字符最后我们应该注意在 <pubDate> 元素里面的数据库字段 DatePublished 是用 StringFormat 来格式化的标准的格式描述符R对 DatePublished 的值进行相应的格式化
此 Web 页面的后台编码类代码并不复杂Page_Load 事件处理函数只是将数据库查询结果绑定到 Repeater控件FormatForXML()函数根据需要做一些简单的字符串替换为 简单起见下面的例子只列出了这两个函数的代码
在浏览器中访问 rssaspx 页面的截图参见图一
图一 通过浏览器访问 Rssaspx 页面
在我们生成在线新闻聚合器之前让我谈谈这个聚合引擎一些可能的增强功能首先每一次访问 rssaspx 页面的时候都要访问一次数据库如果预期可能有大量的人频繁地访问 rssaspx 页面使用输出缓存是很有价值的其次通常新闻网站会将聚合的内容分为不同的类别例如 有一些专门的聚合内容区 比如针对企业计算电子商务通信的内容等等在数据库表 Articles 中加入表示类别的 Category 字段就可以很容易地提供这种支持这样 一来在 rssaspx 页面中可以接收一个表示显示分类的查询参数然后只搜索指定的新闻项分类即可
在ASPNET 页面中使用聚合摘要
为了测试我们刚建立的聚合引擎我们将创建一个在线新闻聚合器允许采集任意数量的聚合内容摘要聚合器的界面很简单参见图二它包括三个框架页面左边框架以列表形式列出了不同的聚合内容摘要右上部框架显示所选的聚合内容摘要包含的新闻项以及查看该新闻项的链接最后在右下部框架则显示选中的新闻项标题和内容顺便提及一下这样的界面基本上是各种类型的聚合器的一个事实上的标准界面包括新闻聚合器email客户端软件和新闻组阅读器都是这样的界面
图二 新闻聚合器用户界面的截图
第一步是创建一个html页面来建立框架用户界面幸运的是在Visual StudioNET 中这一过程非常容易只需要在Web应用程序解决方案中添加一个新 的项目选择新项目类型为 Frameset(我在我的工程中将这个新文件命名为 我之所以将它设置为 html 文件而不是 页面 是因为这个页面只包括建立框架的 html 代码每一个单独的框架会显示一个 页面)下一步参见图三Frameset 模版向导会启动简单地选择选项Nested Hierarchy然后按ok按钮就可以了
图三 VS 中 Frameset 模版向导画面
然后 Frameset 模版向导会创建一个HTML页面里面已经加入了框架的源代码 只要将左边框架的src属性设置为 DisplayFeedsaspx它是列表显示聚合摘要 页面的 url至此 页面就完成了
以下三个部分我们将讲述如何创建在线新闻聚合器的三个组件它们分别是显示聚合摘要列表的 DisplayFeedsaspx显示特定聚合摘要新闻项 的 DisplayNewsItemsaspx以及显示指定聚合摘要特定新闻项具体内容的 DisplayItemaspx显示聚合摘要列表现在我们需要创建 DisplayFeedsaspx 页面该页面要显示订阅的聚合摘要列表作为示范我将这些聚合摘要放在一个叫 Feeds 的数据库表中当然你也可以将它们放在一个XML文件中表 Feeds 有如下四个字段FeedID—主键自增长整数类型唯一标示一个摘要Title—摘要名称数据库字段类型varchar()URL—RSS 摘要的 URL数据库字段类型varchar()UpdateInterval—摘要更新频率(分钟)数据库字段类型int DisplayFeedsaspx 页面使用一个 DataGrid 控件显示聚合摘要的列表这个 DataGrid 只有一个 HyperLinkColumn 列显示 Title 字段的内容并且链接到 DisplayNewsItemsaspx 页面 在查询字符串中 要传递 FeedID 字段的值以下是 DataGrid 控件的声明为简单起见省略了一些无关的部分)<aspDataGrid id=dgFeeds runat=server AutoGenerateColumns=False ……>……
<Columns><aspHyperLinkColumn Target=rtop DataNavigateUrlField=FeedID DataNavigateUrlFormatString=DisplayNewsItemsaspx?FeedID={} DataTextField=Title HeaderText=RSS Feeds></aspHyperLinkColumn></Columns></aspDataGrid>这里要注意的关键是 HyperLinkColumn 列的定义它的 Target 属性设置为右上部分框架的名称这样当用户点击的时候DisplayNewsItemsaspx 页面就会显示在右上部分的框架中另外 属性 DataNavigateUrlFieldDataNavigateUrlFormatString 和 DataTextField 也做了相应的设置 以便超链接显示摘要的标题并且当点击它时就会将用户带到 DisplayNewsItemsaspx 页面并在查询串中将 FeedID 字段的内容传 过来(该页面的后台代码类只访问来自 Feeds 表的摘要清单按照 Title 字段的字母顺序返回接着将查询结果绑定到 DataGrid 控件 由于篇幅所限本文在此不列出代码)
显示特定聚合摘要的新闻项我们面临的下一个任务是创建 DisplayNewsItemsaspx 页面这个页面会以链接的形式显示所选聚合摘要的新闻项标题当点击标题时新闻的内容就会显示在右下部分的框架中要完成这一任务我们会面临以下两个主要的挑战通过指定的 URL 访问 RSS 聚合摘要将接收到的 XML 数据转换为相应的 HTML幸运的是在NET 框架中要实现这两个任务都不是很难对于第一个任务只需要两行代码我们就可以将远程的xml数据装载到一个XmlDocument对象中而第二个任务呢 借助 ASPNET XML Web 控件在ASPNET 页面中显示XML数据也比较容易
XML Web 控件被设计用于在 Web 页面中显示原始或者转换过的 XML 数据使用 XML Web 控件的第一步是定义XML数据源通过 定义一系列的属性用许多方法都可以完成这一工作使用 Document属性你可以指定一个 XmlDocument 实例作为 XML Web 控件的 XML 数据源如果XML数据存在于 Web 服务器文件系统的一个文件中可以用 DocumentSource 属性只要提供该 XML 文件的相对或者绝对路径就可以了最后如果你 的 XML数据是一个字符串那么你可以将这个字符串的内容赋给控件的 DocumentContent 属性这三种办法都可以将 XML 数据与 XML 控件联系起来
通常在将 XML 数据显示到 Web 页面之前我们会以某种方式转换 XML 数据XML Web 控件允许我们指定一个 XSLT 样式表来做这个转换工作与 XML 数据相似XSLT 样式表可以通过 两个属性之一以两种不同的方式中的一种来设置一是 Transform 属性可被赋值给 XslTransform 实例二是将本地 Web 服务器上 XSLT文件的 相对或绝对路径赋予 TransformSource 属性
现在我们来创建 DisplayNewsItemsaspx 页面在添加 XML Web 控件以及编写后台代码类之前我们需要在 HTML 部分加入一小段客户端 JavaScript 代码准确地说是在 html 部分的 <head> 标签里面 添加如下的<script>代码块<script language=javascript>// display a blank page in the bottom frame when the news items loads parentrbottomlocationhref = aboutblank</script>每当 DisplayNewsItemsaspx 页面装载的时候这段客户端 JavaScript 代码会在右下角的框架中显示一个空白页为了理解为什么要加入这段代码我们来看看省略这段代码我们会碰到什么情况用户在左边的框架中点击聚合摘要浏览器会在右上部的框架中装载摘要新闻项用户在右上部框架中点击某个新闻项浏览器会在右下部框架中装载这个新闻项 的详细内容现在用户在左边的框架中点击其它的聚合摘要浏览器会在右上部分的框架中装载新的摘要新闻项前一个新闻项的详细内容还显示在右下部的框架中!通过上面的客户端 Javascript 代码每次点击左面框架的摘要便可以清除右下部框架 的内容以消除这一瑕疵
在我们处理了客户端代码的问题之后让我们把注意力转到添加 XML Web 控件一旦加入 XML Web 控件将其 ID 属性设置为 xsltNewsItemsTransformSourc 属性设置为 NewsItemsxslt(我们将要创建的 XSLT 样式表文件的名称)现在在 Page_Load 事件处理函数中我们需要 在某个 XmlDocument 实例中获取远程 RSS 聚合文件然后将该 XML Web 控件的 Document 属性赋给该 XmlDocument 实例
在 Page_Load 事件处理函数中与我们要实现的任务有密切关系的代码是最后三行代码这三行代码创建一个新的 XmlDocument 对象 加载远程 RSS 摘要内容然后将这个 XmlDocument 对象赋给 XML Web 控件的 Document 属性访问远程 XML 数据并 将它们显示在 ASPNET 页面中就是这么简单难道给你留下的印象不深吗?
剩下我们要做的一件事就是创建 XSLT 样式表NewsItemsaspx下面是样式表的第一版的草稿<?xml version= encoding=UTF ?><xslstylesheet version= xmlnsxsl=><xsloutput method=html omitxmldeclaration=yes /><xsltemplate match=/rss/channel><b><xslvalueof select=title disableoutputescaping=yes /></b><xslforeach select=item><li><a><xslattribute name=href>DisplayItemaspx?ID=<xslnumber value=position() /></xslattribute><xslattribute name=target>rbottom</xslattribute><xslvalueof select=title disableoutputescaping=yes /></a>(<xslvalueof select=pubDate />)
</li></xslforeach></xsltemplate></xslstylesheet>这个XSLT样式表只有一个模版用于匹配/rss/channelXPath表达式这个模版先是以粗体显示<title>元素的内容然后循环获取每一个<item>元素对于每一个元素显示一个到 DisplayItemaspx 页面的超链接在查询字符串中传递<item>元素的位置属性要留意超链接的 target 属性设置为 rbottom右下部框架的名称最后显示每一个新闻项的标题和<pubDate>元素
该 XSLT 样式表中有两个项目并不是每个人都熟悉首先是 <xslvalueof> 元素中的 disableoutputescaping=yes 属性从本质上讲这个属性的设置通知 XSLT 引擎不要转义那些非法的 XML 字符比如& < > 和 为了理解这个设置的意义就要知道如果不设置该属性(也就是设置为默认值no)那么如果标题包含一个转义的&字符&那么输出的 html 文件中也会有一个&而不单单是一个字符&如果你再仔细想一想你会发现这种情况会导致很多问题例如假设一个聚合文件的标题是Matts <i>Cool</i> Blog如果输出转义没有被禁止那么输出就会保留 Matts <i>Cool</i> Blog在 Web 页面就会显示为 Matts <i>Cool</i> Blog当用 disableoutputescaping=yes设置禁止输出转义时输出就不会被转义上面的内容就会被当作Matts <i>Cool</i> Blog显示在页面上就是我们想要的Matts Cool Blog
另一个要注意的是元素<a>这个奇怪的语法会生成下面的输出内容<a DisplayItemaspx?ID=position>news item title</a>之所以要使用这种语法是因为要给 XSLT 样式表中某个你要创建的元素添加一个属性然后在该元素的标签里使用 <xslattribute> 语法 有关该语法的一些例子可在 WSchools 网站上找到The <xslattribute> Element最后要注意的是超链接的ID查询字符串的值是来自于 <xslnumber> 元素从 position() 函数中返回的值<xslnumber> 元素仅仅是输出一个数值position()函数是一个 XPath 函数用来返回 XML 文档中当前节点的顺序位置这意味着对于第一个新闻项position() 函数返回 第二个 新闻项position函数返回 以此类推我们需要记录这个值并将它通过查询字符串传递出去这样当 DisplayItemasp 页面被访问时就可以知道显示 RSS 聚合摘要的什么项目了
聪明的读者可能已经注意到我们的 XSLT 样式表没有全部完成因为 FeedID 参数没有通过查询字符串传递到 DisplayItemaspx 页面要明白 这是为什么我们回顾一下在 ID 查询串参数中所传递的是用户拟察看详细信息的<item>元素顺序号也就是说如果用户点击第四条新闻项页面 DisplayItemaspx?ID= 就会被 加载到右下部分的框架中问题在于 DisplayItemaspx 页面无法确定用户希望查看哪一个摘要有两个不同的方法可以解决这个问题比如可以在右下部框架中用客户端 Javascript 代码读取右上部框架的 URL然后确定FeedID 的值在我看来更简单的办法是和 ID 参数一起将 FeedID 的值通过查询字符串传递 这样的话有一个难题是 XSLT 样式表操纵的 RSS XML 数据中并没有 FeedID 值但是 DisplayNewsItemsaspx 页面知道 FeedID 值需要一种方法让 XSLT 样式表也知道这个值通过使用 XSLT参数可以 实现完成
XSLT 参数的使用是非常简单在 XSLT 样式表中你需要在 <xsltemplate> 元素中加入一个<xslparam> 元素 该元素提供参数的名称下面的代码将这个参数命名为 FeedID<xslstylesheet version= xmlnsxsl=><xsltemplate match=/rss/channel><xslparam name=FeedID />……
</xsltemplate></xslstylesheet>现在就可以用下面的语法在<xslvalueof>元素中使用这个参数了<xslvalueof select=$parameterName />最后在我们的 XSLT 样式表中加入下面的代码我们就可以把 FeedID 查询字符串参数加到超链接中了<a><xslattribute name=href>DisplayItemaspx?ID=<xslnumber value=position() />&FeedID=<xslvalueof select=$FeedID /></xslattribute>
注意在ID查询字符串参数后面我们加了一个&字符(转义&)这样我们就可以传递 FeedID 参数的值到查询字符串的 FeedID 参数中了 这就是我们要在 XSLT 样式表中添加的内容
剩下的工作是在 DisplayNewsItemsaspx 页面的 Page_Load 事件处理函数中设置这个参数的值通过使用 XsltArgumentList 类可以完成这一工作这个类有一个 AddParameter() 方法一旦我们创建了这个类的一个实例加入了相应的参数就可以将这个 实例赋给 XML Web 控件的 TransformArgumentList 参数了下面的代码显示了更新后的 DisplayNewsItemsaspx 页面 Page_Load 事件处理函数显示特定新闻项的详细内容还剩下最后一件需要做的事情是显示用户选择的特定新闻项的详细内容这些详细内容将显示在右下部的框架中而且将会显示新闻项的标题描述和新闻项的链接等信息和 DisplayNewsItemaspx 页面 类似DisplayItemaspx 页面首先将根据传入的 FeedID 查询字符串参数获取远程的 RSS 聚合摘要然后它会用 XML Web 控件显示这些详细内容实际上DisplayItemaspx 页面的 Page_Load 事件处理函数和DisplayNewsItemaspx 页面的 该函数几乎一样只有以下两个小小的区别DisplayItemaspx 页面需要读取ID查询字符串参数的值DisplayItemaspx 页面使用一个 XSLT 参数但是这个参数与 DisplayNewsItemaspx 页面用的参数是不一样的DisplayNewsItemaspx 和 DisplayItemaspx 页面一样都需要在参数中传递一个 XSLT 样式表DisplayNewsItemaspx 页面传递的是 参数 FeedID而 DisplayItemaspx 还需要传入 ID 参数它表示 XSLT 样式表应该显示那个新闻项这个细小的差别在以下代码中以粗体显示以下 代码省略了与 DisplayNewsItemsaspx 页面相同的部分以下是转换 XML 数据的 XSLT 样式表<?xml version= encoding=UTF ?><xslstylesheet version= xmlnsxsl=><xsloutput method=html omitxmldeclaration=yes /><xslparam name=ID /><xsltemplate match=/rss/channel><b><xslvalueof select=item[$ID]/title disableoutputescaping=yes /></b><p><xslvalueof select=item[$ID]/description disableoutputescaping=yes /></p><a><xslattribute name=href><xslvalueof select=item[$ID]/link /></xslattribute><xslattribute name=target>_blank</xslattribute>Read More……
</a></xsltemplate></xslstylesheet>注意 <xslparam> 元素被用于声明 ID XSLT 参数然后在几个不同的 <xslvalueof> 元素中ID 参数 被用来从 <item> 元素列表中抓取特定的 <item> 元素在 XPath 的语法中elementName[i]意思是根据相应元素名 存取第i个元素例如item[]将只获取第一个<item>元素item[]则获取第二个元素所以 item[$ID]是获取由 XSLT 参数 ID 定义的 特定 <item> 元素
最后值得注意的还有在样式表靠近末尾部分的超链接 Read More…它的target属性设为空这样的话当用户点击 Read More… 链接的时候浏览器会打开一个新的窗口
未来的扩展和当前程序的缺点本文讲述的代码中有一个明显的缺点就是每次用户点击左边框架的某个聚合摘要或者在右上部框架点击某个新闻项时远程聚合摘要都会被装载和解析每次用户点击远程聚合 摘要时所有的项都被加载这样的效率无疑是很差的每次用户点击一个新闻项标题就重新装载整个远程聚合摘要也是很浪费资源的这样的方法不仅没有效率对提供发布服务的个人或者公司也是不礼貌的因为这些 连续的不没必要的请求占用了他们的 Web 服务器的负载资源
这个缺点在本文附带的源代码中已经得到解决具体来说NET数据缓存可以用来存放不同摘要的 XmlDocument 对象缓存间隔设置为数据表 Feeds 中 UpdateInterval 字段定义的值(当然由于某些原因摘要的 XmlDocument 对象有可能会被提前清除出缓存)
这个系统的另外一个缺点是在右上部框架和右下部框架之间没有状态的保存为了说明这样会引起什么问题考虑以下的动作用户点击左边框架的某个聚合摘要链接在右上部框架中装载这个摘要的新闻项目假设这个摘要的UpdateInterval 的值是则表示这些内容在分钟之 后会过期装载右上部框架的新闻项的同时这些内容被缓存起来用户离开去吃午饭发布聚合内容的网站增加了一条新的新闻项我们的用户一个小时午饭后回来了这个 摘要的 XmlDocument 的缓存已经过期用户点击右上部框架的第一条新闻项将会在右下部分框架中装载 DisplayItemaspx传入 ID 参数值DisplayItemaspx 页面在缓存中没找到 XmlDocument 对象只好重新获取远程摘要这样就会获得新的数据了(别忘了步骤 已经加了一个新的新闻项)然后此页面会显示第一条新闻项目(因为ID参数的值为) 用户看到了新的新闻项但是内容会令他感到有点困惑因为已经不是他所点击的那一条新闻了而且右上部也没有显示那条新的新闻
之所以出现这样的问题是因为 ID 参数没有唯一地标识一个新闻项它只是一个特定时间点上新闻项列表中的一个偏移量解决这个问题的一个好的方法是不要用数据缓存来保存聚合 摘要而是使用数据库或者持久介质的其它方式(比如 Web 服务器本地文件系统的 XML 文件)如果使用数据库每一个新闻项都可以拥有一个唯一的标识号可以用来传递到右下角的框架中这种方法可以保证解决上面提到的问题当然也会增加系统的复杂性比如需要决定何时从数据库中清除掉旧的新闻项 本文现有的应用程序还缺少异常处理而这肯定是应该加上的尤其是当从远程RSS聚合摘要文件获取数据并加载到XmlDocument对象时应该加上异常处理因为远程的文件可能不存在或者格式不正确
还有很多增强功能可以轻松地加入到这个在线新闻聚合器一个明显的功能是需要一个管理页面来允许用户添加删除和编辑他们现在的聚合摘要还有如果能允许用户自定义分类 将他们的聚合摘要按类别放在一起就更好了另外现在的用户界面还是比较粗糙的但是通过增加一些 XSLT 样式表生成的 HTML 代码或者在几个框架里面增加一些样式表就可以很容易地美化一下界面最后在html标签里面加一些<meta>元素可以让右上部框架定时地去刷新使得用户不用自己手工去刷新页面就可以看到最新的新闻项目
注解 (年月日) 在这篇文章发布以后一些读者用 Email 告诉通知我在显示特定 RSS 聚合项的 <description> 元素时有两个潜在的问题Disableoutputencoding 属性这个属性用在 <xslvalueof> 元素中但是并不是所有的 XSLT解析器都实现了这个功能NET XSLT 解析器支持 disableoutputencoding但是还是要 注意一下因为读者可能试图将这个应用程序移植到其它平台
<description> 元素的 HTML 内容是被原封不动地输出的但是这些 HTML 内容可能包含恶意代码比如 <script> 或者 <embed> 代码块理想情况下这些代码应该被剔除掉为了清除掉这些有潜在危险的代码可能需要用到一些扩展函数(参见 Extending XSLT with JScript C# and Visual Basic NET)想查看从 RSS 聚合 摘要剔除 HTML 内容的更多信息可以参见Dive Into Mark 日志
总结在本文中我们不仅讲到如何创建一个聚合引擎还创建了一个在线新闻聚合器在建立这两个应用程序时我们都采用了在 ASPNET 页面显示 XML 数据的技术在聚合引擎里面我们使用了 Repeater 控件以 XML格式来显示数据库中的数据而在新闻聚合器里面我们使用了 XML Web 控件和 XSLT 样式表
我邀请你下载本文的在线新闻聚合器然后根据你的需要来增强它如果有任何关于这个应用程序或者这篇文章讨论的概念方面的问题随时恭候你的 EMail我的 EMail mitchel