|
概要
本文講解了如何使用 XML Web 控件獲取遠程XML數據并在 ASP.NET 頁(yè)面顯示這些XML數據,以及使用Repeater控件發(fā)布數據庫中的XML數據。在過(guò)去的幾年間,隨著(zhù) 異構平臺間共享數據的需求不斷增長(cháng),XML的使用也呈爆炸性增長(cháng)。意識到這種趨勢,微軟在整個(gè).NET框架中對 XML 提供了健壯的支持。這意味著(zhù),對于 ASP.NET 開(kāi)發(fā)者來(lái)說(shuō),在Web頁(yè)面 中顯示和處理 XML 數據從來(lái)沒(méi)有這么容易過(guò)。本文將通過(guò)生成一個(gè) RSS2.0 聚合引擎和在線(xiàn)新聞聚合器來(lái)學(xué)習 XML 和 ASP.NET 技術(shù)。 本文假設讀者熟悉 ASP.NET 和 XML。 隨著(zhù)辦公室和家庭上網(wǎng)在線(xiàn)時(shí)間的延長(cháng),以及 Web 站點(diǎn)和可訪(fǎng)問(wèn)的互聯(lián)網(wǎng)應用程序呈持續爆炸性增長(cháng),應用程序之間能數據共享變得越來(lái)越重要。在 異構平臺之間共享數據需要一種平臺中立的數據格式,這種數據格式要求能易于通過(guò)標準的互聯(lián)網(wǎng)協(xié)議來(lái)傳輸,而這正是XML的用武之地。因為XML文件本質(zhì)上 只是一個(gè)文本文件,其編碼格式眾所周知,而且現有的XML解析器能為所有主流編程語(yǔ)言所用,所以XML數據能被任何平臺輕松使用。 Web 網(wǎng)站聚合就是一種使用 XML 來(lái)共享數據的范例,在新聞?wù)军c(diǎn)和網(wǎng)志中經(jīng)??梢钥吹?。采用 Web 網(wǎng)站聚合技術(shù),網(wǎng)站能以 XML 格式的 Web 可訪(fǎng)問(wèn)的聚合文件來(lái)發(fā)布最新內容。網(wǎng)站使用 的聚合格式有很多種,其中最流行的一種格式就是 RSS2.0。( RSS2.0 規范被發(fā)布在 Harvard Law 網(wǎng)站 的技術(shù)欄目上)。此外,MSDN 雜志有一個(gè)聚合文件:MSDN雜志:本期刊物, 其中列出了最新一期 MSDN 雜志上的文章,包括到在線(xiàn)版本文章的鏈接。 一旦 Web 站點(diǎn)有了公開(kāi)發(fā)布聚合文件,那么不同的客戶(hù)端就可以消費它。消費聚合文件的方式有很多種,比如,某個(gè)提供 .NET 技術(shù)資源的站點(diǎn)可能希望在網(wǎng)站中 添加最新的 MSDN 雜志文章標題。聚合文件還常常被新聞聚合器程序所用,這種程序被專(zhuān)門(mén)設計用來(lái)獲取和顯示不同來(lái)源的聚合文件。 隨著(zhù)人們越來(lái)越注重使用 XML 數據,在 ASP.NET 頁(yè)面中處理 XML 數據的能力變得比以往更關(guān)鍵。既然 Web 站點(diǎn)聚合如此重要, 本文我們就來(lái)創(chuàng )建一個(gè) Web 站點(diǎn)聚合文件生成程序和一個(gè)在線(xiàn)新聞聚合器。在建立這兩個(gè)微型程序的過(guò)程中,我們將講述如何訪(fǎng)問(wèn)和顯示XML數據,不論這些數據是來(lái)自遠端的Web服務(wù)器還是本地的文件系統。我們將演示如 何多種不同的方法顯示XML數據,比如:用 Repeater 控件以及用 ASP.NET XML Web控件。 使用 RSS 2.0 規范的聚合內容 本文我們將要創(chuàng )建的第一個(gè)微型程序是一個(gè)聚合文件生成器。針對這個(gè)迷你程序,假設你是一個(gè)大型新聞網(wǎng)站(如 MSNBC.com)的 Web 開(kāi)發(fā)者,所有的新聞內容都保存在 Microsoft SQL Server 2000 數據庫中。具體地說(shuō),這些文章是 都保存在一個(gè)名為 Articles 的表中,表中以下字段與我們的程序密切相關(guān): ·ArticleID—主鍵,自增長(cháng)的整型字段,用來(lái)唯一標識每一篇文章; ·Title— 指定標題,字段數據類(lèi)型: varchar(50); ·Author—指定作者,字段數據類(lèi)型: varchar(50); ·Description—新聞內容描述,字段數據類(lèi)型: varchar(2000); ·DatePublished—新聞發(fā)布日期,字段數據類(lèi)型:datetime 請注意,Articles 表中可能還有其它字段,上面所列的只是我們在創(chuàng )建聚合文件的時(shí)候所要用到的字段。而且,這只是一個(gè)非常簡(jiǎn)單的數據模型,在 是應用的數據庫環(huán)境中,你可能會(huì )使用更加標準化的數據庫模型,比如具備一個(gè)單獨的 authors (作者)表,有一個(gè)建立作者和文章之間多對多關(guān)系的表等等。 下一步,我們將創(chuàng )建一個(gè)ASP.NET頁(yè)面,用格式化好的 RSS2.0 XML 文件顯示一個(gè)最新的新聞列表。在講述如何在 ASP.NET 頁(yè)面 中完成這種轉換之前,我們要先介紹一下 RSS2.0 規范的內容。我們應該記住,在整個(gè)規范中,RSS 是被設計用來(lái)為聚合內容提供一個(gè)數據模型。那么 毫無(wú)疑問(wèn),它會(huì )有一系列的 XML 元素,用來(lái)描述 Web 站點(diǎn)要聚合的內容信息,以及一系列用來(lái)描述某一特定新聞項的 XML 元素。最后,不要忘記 RSS 聚合文件是一個(gè) XML 格式文件,必須符合 XML 格式化的準則, 也就是: ·所有 XML元素必須正確嵌套; ·所有的屬性值要用引號包含起來(lái); ·<, >, &, "和’’符號要相應地替換為 <,>, &, " 和 '; 而且,XML格式是大小寫(xiě)敏感的,這就意味著(zhù),XML元素的起始和終止標簽必須匹配,拼寫(xiě)和大小寫(xiě)都必須一致。 RSS2.0 的根元素是<rss>元素,這個(gè)元素可以有一個(gè)版本號的屬性,例如: <rss version="2.0"> ?。紃ss>元素只有一個(gè)子元素<channel>,用來(lái)描述聚合的內容。在<channel>元素里面有三個(gè)必需的子元素,用來(lái)描述 Web 站點(diǎn)的信息。這三個(gè)元素是: ·title—定義聚合文件的名稱(chēng),一般來(lái)說(shuō),還會(huì )包括Web站點(diǎn)的名稱(chēng); ·link—Web站點(diǎn)的URL; ·description—Web站點(diǎn)的一段簡(jiǎn)短的描述。 除此之外,還有一些可選元素來(lái)描述站點(diǎn)信息。這些元素的更多信息請參見(jiàn) RSS2.0規范。 每一個(gè)新聞項目放在一個(gè)單獨的<item>元素中。<channel>元素可以有任意數量的<item>元素。每個(gè)<item>元素可以有多種的子元素,唯一的要求是最少必須包含<title>元素和<description>元素其中一個(gè)作為子元素。以下列出了一些相關(guān)的<item> 子元素: ·title—新聞項目的標題; ·link—新聞項目的URL; ·description—新聞項目的大綱; ·author—新聞項目的作者; ·pubDate—新聞項目的發(fā)布日期 下面是一個(gè)非常簡(jiǎn)單的 RSS2.0 聚合文件。你可以從 RSS generated by Radio UserLand 看到其他的RSS2.0文件的例子。 <rss version="2.0">
通過(guò) ASP.NET 頁(yè)面輸出聚合內容 現在,我們已經(jīng)知道了如何按照 RSS2.0 規范存儲我們的新聞項,我們已經(jīng)就緒創(chuàng )建一個(gè) ASP.NET 頁(yè)面,當用戶(hù)發(fā)出請求時(shí),就會(huì )返回網(wǎng)站聚合 的內容。更確切地說(shuō),我們將建立一個(gè)名字叫 rss.aspx 的 ASP.NET 頁(yè)面,這個(gè)頁(yè)面會(huì )按照 RSS2.0 規范的格式返回 Articles 數據庫表中的最新的 5 個(gè)新聞項 。 可以有幾種方法來(lái)完成這件事,稍后將會(huì )講到。但是現在,我們首先要完成一件事,那就是先要從數據庫中獲得最新的5個(gè)新聞項。這可以用下面的 SQL 查詢(xún)語(yǔ)句獲得: SELECT TOP 5 ArticleID,Title,Author,Description,DatePublished FROM Articles ORDER BY DatePublished DESC 獲得了這些信息以后,我們需要把這些信息轉換成相應的 RSS2.0 格式聚合文件。要把數據庫的數據顯示為XML數據最簡(jiǎn)單、快速的方法就是使用 Repeater 控件。準確地說(shuō),Repeater 控件 將在 HeaderTemplate 和 FooterTemplate 模版里顯示<rss>元素、<channel>元素以及站點(diǎn)相關(guān)的 元素標簽,在 ItemTemplate 模版里面顯示 <item> 元素。下面是我們這個(gè) ASP.NET 頁(yè)面(.aspx文件)的 HTML 部分 : <%@ Page language="c#" ContentType="text/xml" Codebehind="rss.aspx.cs" <ItemTemplate> <FooterTemplate> 首先要注意的是:上面這段代碼例子只包括 Repeater 控件,沒(méi)有其它的 HTML 標記或 Web 控件。這是因為我們希望頁(yè)面只輸出 XML 格式的數據。實(shí)際上,觀(guān)察一下 @Page 指令,你就會(huì )發(fā)現 ContentType 被設置為XML MIME 類(lèi)型(text/xml)。其次要注意的是:在 ItemTemplate 模版里,當 在 XML 輸出中添加數據庫字段Title、Description 和 Author 時(shí),我們調用了輔助函數 FormatForXML()。我們 很快就會(huì )看到,該函數被定義在后臺編碼的類(lèi)中,其作用只是將非法的 xml 字符替換為它們對應的合法的轉義字符。最后我們應該注意,在 <pubDate> 元素里面的數據庫字段 DatePublished 是用 String.Format 來(lái)格式化的。標準的格式描述符“R”對 DatePublished 的值進(jìn)行相應的格式化 。 此 Web 頁(yè)面的后臺編碼類(lèi)代碼并不復雜。Page_Load 事件處理函數只是將數據庫查詢(xún)結果綁定到 Repeater控件,FormatForXML()函數根據需要做一些簡(jiǎn)單的字符串替換。為 簡(jiǎn)單起見(jiàn),下面的例子只列出了這兩個(gè)函數的代碼: 在瀏覽器中訪(fǎng)問(wèn) rss.aspx 頁(yè)面的截圖參見(jiàn)圖一。 ![]() 圖一 通過(guò)瀏覽器訪(fǎng)問(wèn) Rss.aspx 頁(yè)面 在我們生成在線(xiàn)新聞聚合器之前,讓我談?wù)勥@個(gè)聚合引擎一些可能的增強功能。首先,每一次訪(fǎng)問(wèn) rss.aspx 頁(yè)面的時(shí)候,都要訪(fǎng)問(wèn)一次數據庫。如果預期可能有大量的人頻繁地訪(fǎng)問(wèn) rss.aspx 頁(yè)面,使用輸出緩存是很有價(jià)值的。其次,通常新聞網(wǎng)站會(huì )將聚合的內容分為不同的類(lèi)別。例如:News.com 有一些專(zhuān)門(mén)的聚合內容區, 比如針對企業(yè)計算、電子商務(wù)、通信的內容等等。在數據庫表 Articles 中加入表示類(lèi)別的 Category 字段就可以很容易地提供這種支持。這樣 一來(lái),在 rss.aspx 頁(yè)面中,可以接收一個(gè)表示顯示分類(lèi)的查詢(xún)參數,然后只搜索指定的新聞項分類(lèi)即可。
在 ASP.NET 頁(yè)面中使用聚合摘要
為了測試我們剛建立的聚合引擎,我們將創(chuàng )建一個(gè)在線(xiàn)新聞聚合器,允許采集任意數量的聚合內容摘要。聚合器的界面很簡(jiǎn)單,參見(jiàn)圖二。它包括三個(gè)框架頁(yè)面。左邊框架以列表形式列出了不同的聚合內容摘要。右上部框架顯示所選的聚合內容摘要包含的新聞項以及查看該新聞項的鏈接。最后,在右下部框架則顯示選中的新聞項標題和內容。順便提及一下,這樣的界面基本上是各種類(lèi)型的聚合器的一個(gè)事實(shí)上的標準界面,包括新聞聚合器、email客戶(hù)端軟件和新聞組閱讀器都是這樣的界面。
![]() 圖二 新聞聚合器用戶(hù)界面的截圖 第一步是創(chuàng )建一個(gè)html頁(yè)面來(lái)建立框架用戶(hù)界面。幸運的是,在Visual Studio.NET 2003 中,這一過(guò)程非常容易。只需要在Web應用程序解決方案中添加一個(gè)新 的項目,選擇新項目類(lèi)型為 Frameset。(我在我的工程中將這個(gè)新文件命名為 NewsAggregator.htm。我之所以將它設置為 html 文件而不是 asp.net 頁(yè)面, 是因為這個(gè)頁(yè)面只包括建立框架的 html 代碼。每一個(gè)單獨的框架會(huì )顯示一個(gè) asp.net 頁(yè)面)。下一步,參見(jiàn)圖三,Frameset 模版向導會(huì )啟動(dòng),簡(jiǎn)單地選擇選項“Nested Hierarchy”,然后按ok按鈕就可以了。
![]() 圖三 VS2003 中 Frameset 模版向導畫(huà)面 然后 Frameset 模版向導會(huì )創(chuàng )建一個(gè)HTML頁(yè)面,里面已經(jīng)加入了框架的源代碼。 只要將左邊框架的src屬性設置為 DisplayFeeds.aspx,它是列表顯示聚合摘要 asp.net 頁(yè)面的 url。至此 NewsAggreator.htm 頁(yè)面就完成了。
以下三個(gè)部分,我們將講述如何創(chuàng )建在線(xiàn)新聞聚合器的三個(gè)組件,它們分別是顯示聚合摘要列表的 DisplayFeeds.aspx;顯示特定聚合摘要新聞項 的 DisplayNewsItems.aspx;以及顯示指定聚合摘要特定新聞項具體內容的 DisplayItem.aspx。
顯示聚合摘要列表
現在我們需要創(chuàng )建 DisplayFeeds.aspx 頁(yè)面。該頁(yè)面要顯示訂閱的聚合摘要列表。作為示范,我將這些聚合摘要放在一個(gè)叫 Feeds 的數據庫表中。當然你也可以將它們放在一個(gè)XML文件中。表 Feeds 有如下四個(gè)字段:
·FeedID—主鍵,自增長(cháng)整數類(lèi)型,唯一標示一個(gè)摘要
·Title—摘要名稱(chēng),數據庫字段類(lèi)型:varchar(50)
·URL—RSS 摘要的 URL,數據庫字段類(lèi)型:varchar(150)
·UpdateInterval—摘要更新頻率(分鐘),數據庫字段類(lèi)型:int
DisplayFeeds.aspx 頁(yè)面使用一個(gè) DataGrid 控件顯示聚合摘要的列表。這個(gè) DataGrid 只有一個(gè) HyperLinkColumn 列,顯示 Title 字段的內容并且鏈接到 DisplayNewsItems.aspx 頁(yè)面, 在查詢(xún)字符串中 要傳遞 FeedID 字段的值。以下是 DataGrid 控件的聲明,為簡(jiǎn)單起見(jiàn),省略了一些無(wú)關(guān)的部分):
<asp:DataGrid id="dgFeeds" runat="server"
AutoGenerateColumns="False" ...> ... <Columns> <asp:HyperLinkColumn Target="rtop" DataNavigateUrlField="FeedID" DataNavigateUrlFormatString="DisplayNewsItems.aspx?FeedID={0}" DataTextField="Title" HeaderText="RSS Feeds"> </asp:HyperLinkColumn> </Columns> </asp:DataGrid> 這里要注意的關(guān)鍵是 HyperLinkColumn 列的定義。它的 Target 屬性設置為右上部分框架的名稱(chēng),這樣當用戶(hù)點(diǎn)擊的時(shí)候,DisplayNewsItems.aspx 頁(yè)面就會(huì )顯示在右上部分的框架中。另外, 屬性 DataNavigateUrlField、DataNavigateUrlFormatString 和 DataTextField 也做了相應的設置, 以便超鏈接顯示摘要的標題,并且當點(diǎn)擊它時(shí),就會(huì )將用戶(hù)帶到 DisplayNewsItems.aspx 頁(yè)面,并在查詢(xún)串中將 FeedID 字段的內容傳 過(guò)來(lái)。(該頁(yè)面的后臺代碼類(lèi)只訪(fǎng)問(wèn)來(lái)自 Feeds 表的摘要清單,按照 Title 字段的字母順序返回,接著(zhù)將查詢(xún)結果綁定到 DataGrid 控件。 由于篇幅所限,本文在此不列出代碼。)
顯示特定聚合摘要的新聞項
我們面臨的下一個(gè)任務(wù)是創(chuàng )建 DisplayNewsItems.aspx 頁(yè)面。這個(gè)頁(yè)面會(huì )以鏈接的形式顯示所選聚合摘要的新聞項標題,當點(diǎn)擊標題時(shí),新聞的內容就會(huì )顯示在右下部分的框架中。要完成這一任務(wù),我們會(huì )面臨以下兩個(gè)主要的挑戰:
·通過(guò)指定的 URL 訪(fǎng)問(wèn) RSS 聚合摘要;
·將接收到的 XML 數據轉換為相應的 HTML;
幸運的是,在.NET 框架中,要實(shí)現這兩個(gè)任務(wù)都不是很難。對于第一個(gè)任務(wù),只需要兩行代碼,我們就可以將遠程的xml數據裝載到一個(gè)XmlDocument對象中。而第二個(gè)任務(wù)呢, 借助 ASP.NET XML Web 控件在A(yíng)SP.NET 頁(yè)面中顯示XML數據也比較容易。
XML Web 控件被設計用于在 Web 頁(yè)面中顯示原始或者轉換過(guò)的 XML 數據。使用 XML Web 控件的第一步是定義XML數據源,通過(guò) 定義一系列的屬性,用許多方法都可以完成這一工作。使用 Document屬性,你可以指定一個(gè) XmlDocument 實(shí)例作為 XML Web 控件的 XML 數據源。如果XML數據存在于 Web 服務(wù)器文件系統的一個(gè)文件中,可以用 DocumentSource 屬性,只要提供該 XML 文件的相對或者絕對路徑就可以了。最后,如果你 的 XML數據是一個(gè)字符串,那么你可以將這個(gè)字符串的內容賦給控件的 DocumentContent 屬性。這三種辦法都可以將 XML 數據與 XML 控件聯(lián)系起來(lái)。
通常,在將 XML 數據顯示到 Web 頁(yè)面之前,我們會(huì )以某種方式轉換 XML 數據。XML Web 控件允許我們指定一個(gè) XSLT 樣式表來(lái)做這個(gè)轉換工作。與 XML 數據相似,XSLT 樣式表可以通過(guò) 兩個(gè)屬性之一,以?xún)煞N不同的方式中的一種來(lái)設置,一是 Transform 屬性可被賦值給 XslTransform 實(shí)例,二是將本地 Web 服務(wù)器上 XSLT文件的 相對或絕對路徑賦予 TransformSource 屬性。
現在我們來(lái)創(chuàng )建 DisplayNewsItems.aspx 頁(yè)面。在添加 XML Web 控件以及編寫(xiě)后臺代碼類(lèi)之前,我們需要在 HTML 部分加入一小段客戶(hù)端 JavaScript 代碼。準確地說(shuō),是在 html 部分的 <head> 標簽里面 添加如下的<script>代碼塊:
<script language="javascript">
// display a blank page in the bottom frame when the news items loads parent.rbottom.location.href = "about:blank"; </script> 每當 DisplayNewsItems.aspx 頁(yè)面裝載的時(shí)候,這段客戶(hù)端 JavaScript 代碼會(huì )在右下角的框架中顯示一個(gè)空白頁(yè)。為了理解為什么要加入這段代碼,我們來(lái)看看省略這段代碼,我們會(huì )碰到什么情況:
·用戶(hù)在左邊的框架中點(diǎn)擊聚合摘要,瀏覽器會(huì )在右上部的框架中裝載摘要新聞項;
·用戶(hù)在右上部框架中點(diǎn)擊某個(gè)新聞項,瀏覽器會(huì )在右下部框架中裝載這個(gè)新聞項 的詳細內容;
現在用戶(hù)在左邊的框架中點(diǎn)擊其它的聚合摘要,瀏覽器會(huì )在右上部分的框架中裝載新的摘要新聞項;
前一個(gè)新聞項的詳細內容還顯示在右下部的框架中!通過(guò)上面的客戶(hù)端 Javascript 代碼,每次點(diǎn)擊左面框架的摘要便可以清除右下部框架 的內容,以消除這一瑕疵。
在我們處理了客戶(hù)端代碼的問(wèn)題之后,讓我們把注意力轉到添加 XML Web 控件。一旦加入 XML Web 控件,將其 ID 屬性設置為 xsltNewsItems,TransformSourc 屬性設置為 NewsItems.xslt(我們將要創(chuàng )建的 XSLT 樣式表文件的名稱(chēng))?,F在,在 Page_Load 事件處理函數中,我們需要 在某個(gè) XmlDocument 實(shí)例中獲取遠程 RSS 聚合文件,然后將該 XML Web 控件的 Document 屬性賦給該 XmlDocument 實(shí)例。
在 Page_Load 事件處理函數中,與我們要實(shí)現的任務(wù)有密切關(guān)系的代碼是最后三行代碼。這三行代碼創(chuàng )建一個(gè)新的 XmlDocument 對象, 加載遠程 RSS 摘要內容,然后將這個(gè) XmlDocument 對象賦給 XML Web 控件的 Document 屬性。訪(fǎng)問(wèn)遠程 XML 數據并 將它們顯示在 ASP.NET 頁(yè)面中就是這么簡(jiǎn)單,難道給你留下的印象不深嗎?
剩下我們要做的一件事就是創(chuàng )建 XSLT 樣式表,NewsItems.aspx。下面是樣式表的第一版的草稿:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="<xsl:output method="html" omit-xml-declaration="yes" /> <xsl:template match="/rss/channel">
<b><xsl:value-of select="title" disable-output-escaping="yes" /></b> <xsl:for-each select="item"> <li> <a> <xsl:attribute name="href"> DisplayItem.aspx?ID=<xsl:number value="position()" /> </xsl:attribute> <xsl:attribute name="target">rbottom</xsl:attribute> <xsl:value-of select="title" disable-output-escaping="yes" /> </a> (<xsl:value-of select="pubDate" />) </li> </xsl:for-each> </xsl:template> </xsl:stylesheet> 這個(gè)XSLT樣式表只有一個(gè)模版,用于匹配“/rss/channel”XPath表達式。這個(gè)模版先是以粗體顯示<title>元素的內容。然后,循環(huán)獲取每一個(gè)<item>元素,對于每一個(gè)元素,顯示一個(gè)到 DisplayItem.aspx 頁(yè)面的超鏈接,在查詢(xún)字符串中傳遞<item>元素的位置屬性。要留意超鏈接的 target 屬性設置為 rbottom,右下部框架的名稱(chēng)。最后,顯示每一個(gè)新聞項的標題和<pubDate>元素。
該 XSLT 樣式表中有兩個(gè)項目,并不是每個(gè)人都熟悉。首先是 <xsl:value-of> 元素中的 disable-output-escaping="yes" 屬性。從本質(zhì)上講,這個(gè)屬性的設置通知 XSLT 引擎不要轉義那些非法的 XML 字符,比如:&, < , >, " 和 ’’。為了理解這個(gè)設置的意義,就要知道,如果不設置該屬性(也就是設置為默認值"no"),那么如果標題包含一個(gè)轉義的&字符&,那么輸出的 html 文件中也會(huì )有一個(gè)&,而不單單是一個(gè)字符&。如果你再仔細想一想,你會(huì )發(fā)現這種情況會(huì )導致很多問(wèn)題。例如,假設一個(gè)聚合文件的標題是“Matt’’s <i>Cool</i> Blog”,如果輸出轉義沒(méi)有被禁止,那么輸出就會(huì )保留 “Matt’’s <i>Cool</i> Blog”,在 Web 頁(yè)面就會(huì )顯示為 "Matt’’s <i>Cool</i> Blog"。當用 disable-output-escaping="yes"設置禁止輸出轉義時(shí),輸出就不會(huì )被轉義,上面的內容就會(huì )被當作“Matt’’s <i>Cool</i> Blog”,顯示在頁(yè)面上就是我們想要的“Matt’’s Cool Blog”。
另一個(gè)要注意的是元素<a>。這個(gè)奇怪的語(yǔ)法會(huì )生成下面的輸出內容:
<a href="DisplayItem.aspx?ID=position">news item title</a>
之所以要使用這種語(yǔ)法,是因為要給 XSLT 樣式表中某個(gè)你要創(chuàng )建的元素添加一個(gè)屬性,然后在該元素的標簽里使用 <xsl:attribute> 語(yǔ)法 。有關(guān)該語(yǔ)法的一些例子可在 W3Schools 網(wǎng)站上找到:The <xsl:attribute> Element。
最后要注意的是,超鏈接的ID查詢(xún)字符串的值是來(lái)自于 <xsl:number> 元素,從 position() 函數中返回的值。<xsl:number> 元素僅僅是輸出一個(gè)數值。position()函數是一個(gè) XPath 函數,用來(lái)返回 XML 文檔中當前節點(diǎn)的順序位置。這意味著(zhù)對于第一個(gè)新聞項,position() 函數返回 1,第二個(gè) 新聞項,position函數返回 2,以此類(lèi)推。我們需要記錄這個(gè)值并將它通過(guò)查詢(xún)字符串傳遞出去。這樣當 DisplayItem.asp 頁(yè)面被訪(fǎng)問(wèn)時(shí),就可以知道顯示 RSS 聚合摘要的什么項目了。
聰明的讀者可能已經(jīng)注意到,我們的 XSLT 樣式表沒(méi)有全部完成,因為 FeedID 參數沒(méi)有通過(guò)查詢(xún)字符串傳遞到 DisplayItem.aspx 頁(yè)面。要明白 這是為什么,我們回顧一下在 ID 查詢(xún)串參數中所傳遞的是用戶(hù)擬察看詳細信息的<item>元素順序號。也就是說(shuō),如果用戶(hù)點(diǎn)擊第四條新聞項,頁(yè)面 DisplayItem.aspx?ID=4 就會(huì )被 加載到右下部分的框架中。問(wèn)題在于 DisplayItem.aspx 頁(yè)面無(wú)法確定用戶(hù)希望查看哪一個(gè)摘要。有兩個(gè)不同的方法可以解決這個(gè)問(wèn)題,比如可以在右下部框架中用客戶(hù)端 Javascript 代碼讀取右上部框架的 URL,然后確定FeedID 的值。在我看來(lái),更簡(jiǎn)單的辦法是和 ID 參數一起將 FeedID 的值通過(guò)查詢(xún)字符串傳遞 。
這樣的話(huà),有一個(gè)難題是 XSLT 樣式表操縱的 RSS XML 數據中并沒(méi)有 FeedID 值。但是 DisplayNewsItems.aspx 頁(yè)面知道 FeedID 值,需要一種方法讓 XSLT 樣式表也知道這個(gè)值。通過(guò)使用 XSLT參數可以 實(shí)現完成。
XSLT 參數的使用是非常簡(jiǎn)單。在 XSLT 樣式表中,你需要在 <xsl:template> 元素中加入一個(gè)<xsl:param> 元素, 該元素提供參數的名稱(chēng)。下面的代碼將這個(gè)參數命名為 FeedID:
<xsl:stylesheet version="1.0" xmlns:xsl="
<xsl:template match="/rss/channel">
<xsl:param name="FeedID" /> ...
</xsl:template> </xsl:stylesheet> 現在,就可以用下面的語(yǔ)法在<xsl:value-of>元素中使用這個(gè)參數了:
<xsl:value-of select="$parameterName" />
最后,在我們的 XSLT 樣式表中加入下面的代碼,我們就可以把 FeedID 查詢(xún)字符串參數加到超鏈接中了:
<a>
<xsl:attribute name="href">DisplayItem.aspx?ID=<xsl:number value="position()" />&FeedID=<xsl:value-of select="$FeedID" /></xsl:attribute> 注意在ID查詢(xún)字符串參數后面我們加了一個(gè)&字符(轉義&),這樣我們就可以傳遞 FeedID 參數的值到查詢(xún)字符串的 FeedID 參數中了。 這就是我們要在 XSLT 樣式表中添加的內容。 剩下的工作是在 DisplayNewsItems.aspx 頁(yè)面的 Page_Load 事件處理函數中設置這個(gè)參數的值。通過(guò)使用 XsltArgumentList 類(lèi)可以完成這一工作。這個(gè)類(lèi)有一個(gè) AddParameter() 方法。一旦我們創(chuàng )建了這個(gè)類(lèi)的一個(gè)實(shí)例,加入了相應的參數,就可以將這個(gè) 實(shí)例賦給 XML Web 控件的 TransformArgumentList 參數了。下面的代碼顯示了更新后的 DisplayNewsItems.aspx 頁(yè)面 Page_Load 事件處理函數:
顯示特定新聞項的詳細內容
還剩下最后一件需要做的事情是顯示用戶(hù)選擇的特定新聞項的詳細內容。這些詳細內容將顯示在右下部的框架中,而且將會(huì )顯示新聞項的標題,描述和新聞項的鏈接等信息。和 DisplayNewsItem.aspx 頁(yè)面 類(lèi)似,DisplayItem.aspx 頁(yè)面首先將根據傳入的 FeedID 查詢(xún)字符串參數獲取遠程的 RSS 聚合摘要,然后它會(huì )用 XML Web 控件顯示這些詳細內容。實(shí)際上,DisplayItem.aspx 頁(yè)面的 Page_Load 事件處理函數和DisplayNewsItem.aspx 頁(yè)面的 該函數幾乎一樣,只有以下兩個(gè)小小的區別:
·DisplayItem.aspx 頁(yè)面需要讀取ID查詢(xún)字符串參數的值;
·DisplayItem.aspx 頁(yè)面使用一個(gè) XSLT 參數,但是這個(gè)參數與 DisplayNewsItem.aspx 頁(yè)面用的參數是不一樣的;
DisplayNewsItem.aspx 和 DisplayItem.aspx 頁(yè)面一樣都需要在參數中傳遞一個(gè) XSLT 樣式表。DisplayNewsItem.aspx 頁(yè)面傳遞的是 參數 FeedID,而 DisplayItem.aspx 還需要傳入 ID 參數,它表示 XSLT 樣式表應該顯示那個(gè)新聞項。這個(gè)細小的差別在以下代碼中以粗體顯示,以下 代碼省略了與 DisplayNewsItems.aspx 頁(yè)面相同的部分:
以下是轉換 XML 數據的 XSLT 樣式表:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="<xsl:output method="html" omit-xml-declaration="yes" /> <xsl:param name="ID" /> <xsl:template match="/rss/channel">
<b><xsl:value-of select="item[$ID]/title" disable-output-escaping="yes" /></b> <p> <xsl:value-of select="item[$ID]/description" disable-output-escaping="yes" /> </p> <a> <xsl:attribute name="href"><xsl:value-of select="item[$ID]/link" /></xsl:attribute> <xsl:attribute name="target">_blank</xsl:attribute> Read More... </a> </xsl:template> </xsl:stylesheet> 注意 <xsl:param> 元素被用于聲明 ID XSLT 參數。然后,在幾個(gè)不同的 <xsl:value-of> 元素中,ID 參數 被用來(lái)從 <item> 元素列表中抓取特定的 <item> 元素。在 XPath 的語(yǔ)法中,elementName[i]意思是根據相應元素名 存取第i個(gè)元素。例如,item[1]將只獲取第一個(gè)<item>元素,item[2]則獲取第二個(gè)元素。所以 item[$ID]是獲取由 XSLT 參數 ID 定義的 特定 <item> 元素。
最后,值得注意的還有在樣式表靠近末尾部分的超鏈接 Read More…,它的target屬性設為空,這樣的話(huà)當用戶(hù)點(diǎn)擊 Read More… 鏈接的時(shí)候,瀏覽器會(huì )打開(kāi)一個(gè)新的窗口。
未來(lái)的擴展和當前程序的缺點(diǎn)
本文講述的代碼中有一個(gè)明顯的缺點(diǎn)就是每次用戶(hù)點(diǎn)擊左邊框架的某個(gè)聚合摘要或者在右上部框架點(diǎn)擊某個(gè)新聞項時(shí),遠程聚合摘要都會(huì )被裝載和解析。每次用戶(hù)點(diǎn)擊遠程聚合 摘要時(shí),所有的項都被加載,這樣的效率無(wú)疑是很差的。每次用戶(hù)點(diǎn)擊一個(gè)新聞項標題就重新裝載整個(gè)遠程聚合摘要也是很浪費資源的。這樣的方法不僅沒(méi)有效率,對提供發(fā)布服務(wù)的個(gè)人或者公司也是不禮貌的,因為這些 連續的、不沒(méi)必要的請求占用了他們的 Web 服務(wù)器的負載資源。
這個(gè)缺點(diǎn)在本文附帶的源代碼中已經(jīng)得到解決。具體來(lái)說(shuō),.NET數據緩存可以用來(lái)存放不同摘要的 XmlDocument 對象。緩存間隔設置為數據表 Feeds 中 UpdateInterval 字段定義的值。(當然,由于某些原因,摘要的 XmlDocument 對象有可能會(huì )被提前清除出緩存)
這個(gè)系統的另外一個(gè)缺點(diǎn)是在右上部框架和右下部框架之間沒(méi)有狀態(tài)的保存。為了說(shuō)明這樣會(huì )引起什么問(wèn)題,考慮以下的動(dòng)作:
·用戶(hù)點(diǎn)擊左邊框架的某個(gè)聚合摘要鏈接,在右上部框架中裝載這個(gè)摘要的新聞項目。假設這個(gè)摘要的UpdateInterval 的值是30,則表示這些內容在30分鐘之 后會(huì )過(guò)期;
·裝載右上部框架的新聞項的同時(shí),這些內容被緩存起來(lái);
·用戶(hù)離開(kāi)去吃午飯;
·發(fā)布聚合內容的網(wǎng)站增加了一條新的新聞項;
·我們的用戶(hù)一個(gè)小時(shí)午飯后回來(lái)了,這個(gè) 摘要的 XmlDocument 的緩存已經(jīng)過(guò)期;
·用戶(hù)點(diǎn)擊右上部框架的第一條新聞項,將會(huì )在右下部分框架中裝載 DisplayItem.aspx,傳入 ID 參數值1;
·DisplayItem.aspx 頁(yè)面在緩存中沒(méi)找到 XmlDocument 對象,只好重新獲取遠程摘要。這樣就會(huì )獲得新的數據了(別忘了,步驟 4 已經(jīng)加了一個(gè)新的新聞項),然后此頁(yè)面會(huì )顯示第一條新聞項目(因為ID參數的值為1) ;
·用戶(hù)看到了新的新聞項,但是內容會(huì )令他感到有點(diǎn)困惑,因為已經(jīng)不是他所點(diǎn)擊的那一條新聞了,而且右上部也沒(méi)有顯示那條新的新聞。
之所以出現這樣的問(wèn)題,是因為 ID 參數沒(méi)有唯一地標識一個(gè)新聞項,它只是一個(gè)特定時(shí)間點(diǎn)上新聞項列表中的一個(gè)偏移量。解決這個(gè)問(wèn)題的一個(gè)好的方法是不要用數據緩存來(lái)保存聚合 摘要,而是使用數據庫或者持久介質(zhì)的其它方式(比如 Web 服務(wù)器本地文件系統的 XML 文件)。如果使用數據庫,每一個(gè)新聞項都可以擁有一個(gè)唯一的標識號,可以用來(lái)傳遞到右下角的框架中。這種方法可以保證解決上面提到的問(wèn)題。當然也會(huì )增加系統的復雜性,比如需要決定何時(shí)從數據庫中清除掉舊的新聞項 。
本文現有的應用程序還缺少異常處理,而這肯定是應該加上的。尤其是當從遠程 RSS 聚合摘要文件獲取數據并加載到 XmlDocument 對象時(shí),應該加上異常處理。因為遠程的文件可能不存在或者格式不正確。
還有很多增強功能可以輕松地加入到這個(gè)在線(xiàn)新聞聚合器。一個(gè)明顯的功能是需要一個(gè)管理頁(yè)面來(lái)允許用戶(hù)添加,刪除和編輯他們現在的聚合摘要。還有,如果能允許用戶(hù)自定義分類(lèi) ,將他們的聚合摘要按類(lèi)別放在一起就更好了。另外,現在的用戶(hù)界面還是比較粗糙的,但是通過(guò)增加一些 XSLT 樣式表生成的 HTML 代碼或者在幾個(gè)框架里面增加一些樣式表就可以很容易地美化一下界面。最后,在html標簽里面加一些<meta>元素,可以讓右上部框架定時(shí)地去刷新,使得用戶(hù)不用自己手工去刷新頁(yè)面就可以看到最新的新聞項目。
注解 (2003年8月4日): 在這篇文章發(fā)布以后,一些讀者用 Email 告訴通知我在顯示特定 RSS 聚合項的 <description> 元素時(shí),有兩個(gè)潛在的問(wèn)題:
1、Disable-output-encoding 屬性,這個(gè)屬性用在 <xsl:value-of> 元素中,但是并不是所有的 XSLT解析器都實(shí)現了這個(gè)功能。.NET XSLT 解析器支持 disable-output-encoding,但是還是要 注意一下,因為讀者可能試圖將這個(gè)應用程序移植到其它平臺。
2、<description> 元素的 HTML 內容是被原封不動(dòng)地輸出的。但是,這些 HTML 內容可能包含惡意代碼,比如 <script> 或者 <embed> 代碼塊。理想情況下,這些代碼應該被剔除掉。為了清除掉這些有潛在危險的代碼,可能需要用到一些擴展函數(參見(jiàn) Extending XSLT with JScript, C#, and Visual Basic .NET)。想查看從 RSS 聚合 摘要剔除 HTML 內容的更多信息,可以參見(jiàn)’’Dive Into Mark’’ 日志.
總結
在本文中,我們不僅講到如何創(chuàng )建一個(gè)聚合引擎,還創(chuàng )建了一個(gè)在線(xiàn)新聞聚合器。在建立這兩個(gè)應用程序時(shí),我們都采用了在 ASP.NET 頁(yè)面顯示 XML 數據的技術(shù)。在聚合引擎里面,我們使用了 Repeater 控件以 XML格式來(lái)顯示數據庫中的數據。而在新聞聚合器里面,我們使用了 XML Web 控件和 XSLT 樣式表。
我邀請你下載本文的在線(xiàn)新聞聚合器,然后根據你的需要來(lái)增強它。如果有任何關(guān)于這個(gè)應用程序或者這篇文章討論的概念方面的問(wèn)題,隨時(shí)恭候你的 EMail。我的 EMail mitchell@4guysfromrolla.com.
|
聯(lián)系客服