概要
本文講解了如何使用 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
From:http://tw.wingwit.com/Article/program/net/201311/12765.html