asp.net|rss|線上
概要
本文講解了如何使用 XML Web 控制項擷取遠程XML資料並在 ASP.NET 頁面顯示這些XML資料,以及使用Repeater控制項發行集資料庫中的XML資料。在過去的幾年間,隨著 異構平台間共用資料的需求不斷增長,XML的使用也呈爆炸性增長。意識到這種趨勢,微軟在整個.NET架構中對 XML 提供了健壯的支援。這意味著,對於 ASP.NET 開發人員來說,在Web頁面 中顯示和處理 XML 資料從來沒有這麼容易過。本文將通過產生一個 RSS2.0 彙總引擎和線上新聞彙總器來學習 XML 和 ASP.NET 技術。 本文假設讀者熟悉 ASP.NET 和 XML。
簡介
隨著辦公室和家庭上網線上時間的延長,以及 Web 網站和可訪問的互連網應用程式呈持續爆炸性增長,應用程式之間能資料共用變得越來越重要。在 異構平台之間共用資料需要一種平台中立的資料格式,這種資料格式要求能易於通過標準的互連網協議來傳輸,而這正是XML的用武之地。因為XML檔案本質上 只是一個文字檔,其編碼格式眾所周知,而且現有的XML解析器能為所有主流程式設計語言所用,所以XML資料能被任何平台便於使用。
Web 網站彙總就是一種使用 XML 來共用資料的範例,在新聞網站和網誌中經常可以看到。採用 Web 網站彙總技術,網站能以 XML 格式的 Web 可訪問的彙總檔案來發布最新內容。網站使用 的彙總格式有很多種,其中最流行的一種格式就是 RSS2.0。( RSS2.0 規範被發布在 Harvard Law 網站 的技術欄目上)。此外,MSDN 雜誌有一個彙總檔案:MSDN雜誌:本期刊物, 其中列出了最新一期 MSDN 雜誌上的文章,包括到線上版本文章的連結。
一旦 Web 網站有了公開發布彙總檔案,那麼不同的用戶端就可以消費它。消費彙總檔案的方式有很多種,比如,某個提供 .NET 技術資源的網站可能希望在網站中 添加最新的 MSDN 雜誌文章標題。彙總檔案還常常被新聞彙總器程式所用,這種程式被專門設計用來擷取和顯示不同來源的彙總檔案。
隨著人們越來越注重使用 XML 資料,在 ASP.NET 頁面中處理 XML 資料的能力變得比以往更關鍵。既然 Web 網站彙總如此重要, 本文我們就來建立一個 Web 網站彙總檔案產生程式和一個線上新聞彙總器。在建立這兩個微型程式的過程中,我們將講述如何訪問和顯示XML資料,不論這些資料是來自遠端的Web伺服器還是本地的檔案系統。我們將示範如 何多種不同的方法顯示XML資料,比如:用 重複器控制項以及用 ASP.NET XML Web控制項。
使用 RSS 2.0 規範的彙總內容
本文我們將要建立的第一個微型程式是一個彙總檔案產生器。針對這個迷你程式,假設你是一個大型新聞網站(如 MSNBC.com)的 Web 開發人員,所有的新聞內容都儲存在 Microsoft SQL Server 2000 資料庫中。具體地說,這些文章是 都儲存在一個名為 Articles 的表中,表中以下欄位與我們的程式密切相關:
·ArticleID—主鍵,自增長的整型欄位,用來唯一標識每一篇文章;
·Title— 指定標題,欄位資料類型: varchar(50);
·Author—指定作者,欄位資料類型: varchar(50);
·Description—新聞內容描述,欄位資料類型: varchar(2000);
·DatePublished—新聞發布日期,欄位資料類型:datetime
請注意,Articles 表中可能還有其它欄位,上面所列的只是我們在建立彙總檔案的時候所要用到的欄位。而且,這隻是一個非常簡單的資料模型,在 是應用的資料庫環境中,你可能會使用更加標準化的資料庫模型,比如具備一個單獨的 authors (作者)表,有一個建立作者和文章之間多對多關係的表等等。
下一步,我們將建立一個ASP.NET頁面,用格式化好的 RSS2.0 XML 檔案顯示一個最新的新聞列表。在講述如何在 ASP.NET 頁面 中完成這種轉換之前,我們要先介紹一下 RSS2.0 規範的內容。我們應該記住,在整個規範中,RSS 是被設計用來為彙總內容提供一個資料模型。那麼 毫無疑問,它會有一系列的 XML 元素,用來描述 Web 網站要彙總的內容資訊,以及一系列用來描述某一特定新聞項的 XML 元素。最後,不要忘記 RSS 彙總檔案是一個 XML 格式檔案,必須符合 XML 格式化的準則, 也就是:
·所有 XML元素必須正確嵌套;
·所有的屬性值要用引號包含起來;
·<, >, &, "和’’符號要相應地替換為 <,>, &, " 和 ';
而且,XML格式是大小寫敏感的,這就意味著,XML元素的起始和終止標籤必須匹配,拼字和大小寫都必須一致。
RSS2.0 的根項目是<rss>元素,這個元素可以有一個版本號碼的屬性,例如:
<rss version="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 彙總檔案。你可以從 RSS generated by Radio UserLand 看到其他的RSS2.0檔案的例子。
<rss version="2.0"> <channel> <title>Latest DataWebControls.com FAQs</title> <link>http://datawebcontrols.com</link> <description> This is the syndication feed for the FAQs at DataWebControls.com </description> <item> <title>Working with the DataGrid</title> <link>http://datawebcontrols.com/faqs/DataGrid.aspx</link> <pubDate>Mon, 07 Jul 2003 21:00:00 GMT</pubDate> </item> <item> <title>Working with the Repeater</title> <description> This article examines how to work with the Repeater control. </description> <link>http://datawebcontrols.com/faqs/Repeater.aspx</link> <pubDate>Tue 08 Jul 2003 12:00:00 GMT</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 查詢語句獲得:
SELECT TOP 5 ArticleID,Title,Author,Description,DatePublished FROM Articles ORDER BY DatePublished DESC |
獲得了這些資訊以後,我們需要把這些資訊轉換成相應的 RSS2.0 格式彙總檔案。要把資料庫的資料顯示為XML資料最簡單、快速的方法就是使用 重複器控制項。準確地說,重複器控制項 將在 HeaderTemplate 和 FooterTemplate 模版裡顯示<rss>元素、<channel>元素以及網站相關的 元素標籤,在 ItemTemplate 模版裡面顯示 <item> 元素。下面是我們這個 ASP.NET 頁面(.aspx檔案)的 HTML 部分 :
<%@ Page language="c#" ContentType="text/xml" Codebehind="rss.aspx.cs" AutoEventWireup="false" Inherits="SyndicationDemo.rss" %> <asp:Repeater id="rptRSS" runat="server"> <HeaderTemplate> <rss version="2.0"> <channel> <title>ASP.NET News!</title> <link>http://www.ASPNETNews.com/Headlines/</link> <description> This is the syndication feed for ASPNETNews.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> |
首先要注意的是:上面這段代碼例子只包括 重複器控制項,沒有其它的 HTML 標籤或 Web 控制項。這是因為我們希望頁面只輸出 XML 格式的資料。實際上,觀察一下 @Page 指令,你就會發現 ContentType 被設定為XML MIME 類型(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 頁面,使用輸出緩衝是很有價值的。其次,通常新聞網站會將彙總的內容分為不同的類別。例如:News.com 有一些專門的彙總內容區, 比如針對企業計算、電子商務、通訊的內容等等。在資料庫表 Articles 中加入表示類別的 Category 欄位就可以很容易地提供這種支援。這樣 一來,在 rss.aspx 頁面中,可以接收一個表示顯示分類的查詢參數,然後只搜尋指定的新聞項分類即可。
在 ASP.NET 頁面中使用彙總摘要
為了測試我們剛建立的彙總引擎,我們將建立一個線上新聞彙總器,允許採集任意數量的彙總內容摘要。彙總器的介面很簡單,參見圖二。它包括三個架構頁面。左邊架構以列表形式列出了不同的彙總內容摘要。右上部架構顯示所選的彙總內容摘要包含的新聞項以及查看該新聞項的連結。最後,在右下部架構則顯示選中的新聞項標題和內容。順便提及一下,這樣的介面基本上是各種類型的彙總器的一個事實上的標準介面,包括新聞彙總器、email用戶端軟體和新聞群組閱讀器都是這樣的介面。
第一步是建立一個html頁面來建立架構使用者介面。幸運的是,在Visual Studio.NET 2003 中,這一過程非常容易。只需要在Web應用程式解決方案中添加一個新 的項目,選擇新項目類型為 Frameset。(我在我的工程中將這個新檔案命名為 NewsAggregator.htm。我之所以將它設定為 html 檔案而不是 asp.net 頁面, 是因為這個頁面只包括建立架構的 html 代碼。每一個單獨的架構會顯示一個 asp.net 頁面)。下一步,參見圖三,Frameset 模版嚮導會啟動,簡單地選擇選項“Nested Hierarchy”,然後按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: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> |
這裡要注意的關鍵是 HyperLinkColumn 列的定義。它的 Target 屬性設定為右上部分架構的名稱,這樣當使用者點擊的時候,DisplayNewsItems.aspx 頁面就會顯示在右上部分的架構中。另外, 屬性 DataNavigateUrlField、DataNavigateUrlFormatString 和 DataTextField 也做了相應的設定, 以便超連結顯示摘要的標題,並且當點擊它時,就會將使用者帶到 DisplayNewsItems.aspx 頁面,並在查詢串中將 FeedID 欄位的內容傳 過來。(該頁面的後台代碼類只訪問來自 Feeds 表的摘要清單,按照 Title 欄位的字母順序返回,接著將查詢結果綁定到 DataGrid 控制項。 由於篇幅所限,本文在此不列出代碼。)
顯示特定彙總摘要的新聞項
我們面臨的下一個任務是建立 DisplayNewsItems.aspx 頁面。這個頁面會以連結的形式顯示所選彙總摘要的新聞項標題,當點擊標題時,新聞的內容就會顯示在右下部分的架構中。要完成這一任務,我們會面臨以下兩個主要的挑戰:
·通過指定的 URL 訪問 RSS 彙總摘要;
·將接收到的 XML 資料轉換為相應的 HTML;
幸運的是,在.NET 架構中,要實現這兩個任務都不是很難。對於第一個任務,只需要兩行代碼,我們就可以將遠端xml資料裝載到一個XmlDocument對象中。而第二個任務呢, 藉助 ASP.NET XML Web 控制項在ASP.NET 頁面中顯示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 屬性。
現在我們來建立 DisplayNewsItems.aspx 頁面。在添加 XML Web 控制項以及編寫後台代碼類之前,我們需要在 HTML 部分加入一小段用戶端 JavaScript 代碼。準確地說,是在 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 頁面裝載的時候,這段用戶端 JavaScript 代碼會在右下角的架構中顯示一個空白頁。為了理解為什麼要加入這段代碼,我們來看看省略這段代碼,我們會碰到什麼情況:
·使用者在左邊的架構中點擊彙總摘要,瀏覽器會在右上部的架構中裝載摘要新聞項;
·使用者在右上部架構中點擊某個新聞項,瀏覽器會在右下部架構中裝載這個新聞項 的詳細內容;
現在使用者在左邊的架構中點擊其它的彙總摘要,瀏覽器會在右上部分的架構中裝載新的摘要新聞項;
前一個新聞項的詳細內容還顯示在右下部的架構中!通過上面的用戶端 Javascript 代碼,每次點擊左面架構的摘要便可以清除右下部架構 的內容,以消除這一瑕疵。
在我們處理了用戶端代碼的問題之後,讓我們把注意力轉到添加 XML Web 控制項。一旦加入 XML Web 控制項,將其 ID 屬性設定為 xsltNewsItems,TransformSourc 屬性設定為 NewsItems.xslt(我們將要建立的 XSLT 樣式表檔案的名稱)。現在,在 Page_Load 事件處理函數中,我們需要 在某個 XmlDocument 執行個體中擷取遠程 RSS 彙總檔案,然後將該 XML Web 控制項的 Document 屬性賦給該 XmlDocument 執行個體。
在 Page_Load 事件處理函數中,與我們要實現的任務有密切關係的代碼是最後三行代碼。這三行代碼建立一個新的 XmlDocument 對象, 載入遠程 RSS 摘要內容,然後將這個 XmlDocument 對象賦給 XML Web 控制項的 Document 屬性。訪問遠程 XML 資料並 將它們顯示在 ASP.NET 頁面中就是這麼簡單,難道給你留下的印象不深嗎?
剩下我們要做的一件事就是建立 XSLT 樣式表,NewsItems.aspx。下面是樣式表的第一版的草稿:
<?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <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> |
這個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’’s Cool Blog”。
另一個要注意的是元素<a>。這個奇怪的文法會產生下面的輸出內容:
<a href="DisplayItem.aspx?ID=position">news item title</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 樣式表操縱的 RSS XML 資料中並沒有 FeedID 值。但是 DisplayNewsItems.aspx 頁面知道 FeedID 值,需要一種方法讓 XSLT 樣式表也知道這個值。通過使用 XSLT參數可以 實現完成。
XSLT 參數的使用是非常簡單。在 XSLT 樣式表中,你需要在 <xsl:template> 元素中加入一個<xsl:param> 元素, 該元素提供參數的名稱。下面的代碼將這個參數命名為 FeedID:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/rss/channel"> <xsl:param name="FeedID" />
... </xsl:template> </xsl:stylesheet> |
現在,就可以用下面的文法在<xsl:value-of>元素中使用這個參數了:
<xsl:value-of select="$parameterName" /> |
最後,在我們的 XSLT 樣式表中加入下面的代碼,我們就可以把 FeedID 查詢字串參數加到超連結中了:
<a> <xsl:attribute name="href">DisplayItem.aspx?ID=<xsl:number value="position()" />&FeedID=<xsl:value-of select="$FeedID" /></xsl:attribute> |
注意在ID查詢字串參數後面我們加了一個&字元(轉義&),這樣我們就可以傳遞 FeedID 參數的值到查詢字串的 FeedID 參數中了。 這就是我們要在 XSLT 樣式表中添加的內容。
剩下的工作是在 DisplayNewsItems.aspx 頁面的 Page_Load 事件處理函數中設定這個參數的值。通過使用 XsltArgumentList 類可以完成這一工作。這個類有一個 AddParameter() 方法。一旦我們建立了這個類的一個執行個體,加入了相應的參數,就可以將這個 執行個體賦給 XML Web 控制項的 TransformArgumentList 參數了。下面的代碼顯示了更新後的 DisplayNewsItems.aspx 頁面 Page_Load 事件處理函數:
顯示特定新聞項的詳細內容
還剩下最後一件需要做的事情是顯示使用者選擇的特定新聞項的詳細內容。這些詳細內容將顯示在右下部的架構中,而且將會顯示新聞項的標題,描述和新聞項的連結等資訊。和 DisplayNewsItem.aspx 頁面 類似,DisplayItem.aspx 頁面首先將根據傳入的 FeedID 查詢字串參數擷取遠端 RSS 彙總摘要,然後它會用 XML Web 控制項顯示這些詳細內容。實際上,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 樣式表:
<?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <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 參數。然後,在幾個不同的 <xsl:value-of> 元素中,ID 參數 被用來從 <item> 元素列表中抓取特定的 <item> 元素。在 XPath 的文法中,elementName[i]意思是根據相應元素名 存取第i個元素。例如,item[1]將只擷取第一個<item>元素,item[2]則擷取第二個元素。所以 item[$ID]是擷取由 XSLT 參數 ID 定義的 特定 <item> 元素。
最後,值得注意的還有在樣式表靠近末尾部分的超連結 Read More…,它的target屬性設為空白,這樣的話當使用者點擊 Read More… 連結的時候,瀏覽器會開啟一個新的視窗。
未來的擴充和當前程式的缺點
本文講述的代碼中有一個明顯的缺點就是每次使用者點擊左邊架構的某個彙總摘要或者在右上部架構點擊某個新聞項時,遠程彙總摘要都會被裝載和解析。每次使用者點擊遠程彙總 摘要時,所有的項都被載入,這樣的效率無疑是很差的。每次使用者點擊一個新聞項標題就重新裝載整個遠程彙總摘要也是很浪費資源的。這樣的方法不僅沒有效率,對提供發布服務的個人或者公司也是不禮貌的,因為這些 連續的、不沒必要的請求佔用了他們的 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解析器都實現了這個功能。.NET XSLT 解析器支援 disable-output-encoding,但是還是要 注意一下,因為讀者可能試圖將這個應用程式移植到其它平台。
2、<description> 元素的 HTML 內容是被原封不動地輸出的。但是,這些 HTML 內容可能包含惡意代碼,比如 <script> 或者 <embed> 代碼塊。理想情況下,這些代碼應該被剔除掉。為了清除掉這些有潛在危險的代碼,可能需要用到一些擴充函數(參見 Extending XSLT with JScript, C#, and Visual Basic .NET)。想查看從 RSS 彙總 摘要剔除 HTML 內容的更多資訊,可以參見’’Dive Into Mark’’ 日誌.
總結
在本文中,我們不僅講到如何建立一個彙總引擎,還建立了一個線上新聞彙總器。在建立這兩個應用程式時,我們都採用了在 ASP.NET 頁面顯示 XML 資料的技術。在彙總引擎裡面,我們使用了 重複器控制項以 XML格式來顯示資料庫中的資料。而在新聞彙總器裡面,我們使用了 XML Web 控制項和 XSLT 樣式表。
我邀請你下載本文的線上新聞彙總器,然後根據你的需要來增強它。如果有任何關於這個應用程式或者這篇文章討論的概念方面的問題,隨時恭候你的 EMail。我的 EMail mitchell@4guysfromrolla.com.