首先,簡單的分析一下需求,分析過程忽略,主要的需求和要解決的問題大概有以下幾個方面: 1.RSS源提供的RSS顯示格式和顯示內容統一性的問題 2.Ajax支持以及Ajax支持下的跨域訪問的問題 3.RSS源xml文件的編碼問題 4.前端顯示方式和留給用戶操作的易用性問題 5.要記住用戶個性化的RSS定制方案 對于問題1,各大RSS 內容提供很好的遵循了所謂的業界規范,如新浪NBA的RSS結構大致如下:
Code <rss version="2.0"> <channel> <title> <![CDATA[籃球-NBA新聞]]> </title> <image> <title> <![CDATA[體育-籃球]]> </title> <link>http://sports.sina.com.cn/basketball</link>
<url>/technology/UploadFiles_4116/200803/20080323130522110.gif</url> </image> <description> <![CDATA[籃球-NBA新聞]]> </description> <link>http://sports.sina.com.cn/basketball/index.shtml</link> <language>zh-cn</language> <generator>WWW.SINA.COM.CN</generator> <ttl>5</ttl> <copyright> <![CDATA[Copyright 1996 - 2007 SINA Inc. All Rights Reserved]]> </copyright> <pubDate>Mon, 24 Dec 2007 06:41:43 GMT</pubDate> <category> <![CDATA[]]> </category> <item> <title> <![CDATA[蘇群每周評:綠衫軍雄霸天下 火箭雄鹿如患難兄弟]]> </title> <link>http://sports.sina.com.cn/k/2007-12-24/14353379491.shtml</link>
<author>WWW.SINA.COM.CN</author> <guid>http://sports.sina.com.cn/k/2007-12-24/14353379491.shtml</guid>
<category> <![CDATA[籃球-NBA新聞]]> </category> <pubDate>Mon, 24 Dec 2007 06:35:16 GMT</pubDate> <comments></comments> <description> <![CDATA[ 以下為新浪體育特約專欄作者蘇群排出的0708賽季NBA第八周(12月18日-12月24日)各隊實力排行榜:
1.凱爾特人 22-3 2
-1 1 -
主場輸給活塞隊,但周末最后一戰對魔術時又以103比91取勝,仍然是東部主場戰績最強隊伍。目前凱爾特人保持聯盟防守第一,最近12場比賽中,.]]> </description> </item> <item> 結構同上一個item,此處省略 </item> </channel> </rss> 可以看出,首先是一些關于RSS內容自身的描述性信息,如語言、鏈接地址、版權信息等等,然后是若干個以<item></item>并列的真正的內容區域,內容一般包括標題、摘要、發布時間、所屬分類、評論等等信息,這樣的目錄結構在業界遵循RDF(即資源描述)的規范,因此,其他RSS內容提供商所提供的RSS也是這種標準結構的,這使得我們可以放心的訂閱任何符合規范的網站RSS內容。但也不是萬事大吉了,可以看到,提供的內容太多,而我們想顯示給用戶的無非就是一個新聞標題,一個日期和一個摘要,特別是一些內容提供網站如搜狐,經常在其摘要中加入圖片,如果我們原封不動的讓其顯示出來,有可能會影響到統一性和美觀,想到這里,我們接下來要做的事情就很明確了,就是有選擇的在自己的RSS訂閱顯示區域只顯示最重要和最感興趣的內容,而不是全部內容。這就引出了另外一項需要掌握的技術:xslt,它是專門用來轉換承載了RSS內容的xml文檔的,有一系列自己語法和特點,這里不細講,可以參考:http://www.baidu.com,它提供了一套較為全面的教程。在我這里,最終需要的xslt文件內容如下:
Code <?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet xmlns:xsl=" <xsl:output method="html"/> <xsl:template match="/"> <xsl:for-each select="/rss/channel/item [position() <= 5]"> <div class="item"> <a href="{./link}" style="font-size:14px; margin-right:10px; color:#42835B;" target="_blank"> <xsl:value-of select="./title"/> </a> <span style="font-size:11px; color:red;"> <xsl:value-of select="substring(./pubDate,6,20)"/> </span> <div class="content" id="content" style="line-height:22px; margin:4px 0px 4px 0px; text-indent:24px;"> <xsl:value-of select="./description" disable-output-escaping="yes"/> <xsl:if test="system-property('xsl:vendor')='Transformiix'"> <script type="text/javascript"> var element = document.getElementById("content"); element.innerHTML = el.textContent; </script> </xsl:if> </div> </div> </xsl:for-each> </xsl:template> </xsl:stylesheet> 以上的xslt規定了從源RSS里面選取前5條內容的標題,發布時間和摘要信息,并按照我們自己規定的格式予以顯示 還有一個問題是,我們現在雖然控制了要選取和現實的項,但是項的內容我們還沒有進行處理,而恰恰其中的圖片和一些js腳本是我們不想要的,所以務必過濾一下,一方面減少網絡字節傳輸,另一方面符合了我們想要的內容。過濾主要用到了正則表達式,可以在服務端(C#.net)和客戶端(javascript)中進行,如在后臺過濾js腳本,可以這樣來進行: string regexstr = @"<script.*</script>"; str = Regex.Replace(str, regexstr, string.Empty, RegexOptions.IgnoreCase); 當然別忘了引用 System.Text.RegularExpressions 命名空間在javascript中過濾圖片信息可以這樣來進行: var reg =/<img.*?>/ig; str=str.replace(reg,""); 在客戶端進行的代價是那些代表圖片的html代碼字節已經傳送到了客戶端,會稍稍影響下載速度吧,但畢竟<img />標簽不像js那樣可能會大段大段的,所以這個影響是可以忽略的。
至此,第一個問題的各個方面都有了一個比較好的解決接下來我們來看第二個問題,ajax支持和ajax跨越的問題,現在主流瀏覽器都支持ajax,要使用ajax支持,無非是寫一些構造ajax過程的js代碼,當然也可以用成熟的js框架,如jquery,重點是第二個問題,為了保證安全性,ajax是不允許跨越的(這個問題百度一下,一堆一堆的),我們要做的讓它可以“跨域”,當然,這里的跨域是打上了引號的,作為引用,這里將采用的不過是一種曲線方案,而讓用戶覺察不到。 我選取的方案是利用.net強大而完善的功能來先借助服務器下載各個不同域上的RSS內容文件,解析處理后發送至請求的客戶端,在這里我們主要用到了.net的HttpWebRequest和HttpWebResponse類,它們位于System.Net命名空間下,利用它們可以請求RSS內容提供商URL上的RSS文件,當然,獲取該文件后我們要做一系列的處理,這些處理包括將返回的數據流格式轉化成字符串格式,利用前面講到的xslt來獲取我們想要的RSS選項,過濾其中的js代碼,最后推送到客戶端等等,核心代碼如下:
Code XmlDocument doc = new XmlDocument(); string reqUrl = Request.Params["url"].ToString();//請求的RSS地址 HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(reqUrl); HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse(); Stream receiveStream = myHttpWebResponse.GetResponseStream(); Encoding encode = System.Text.Encoding.GetEncoding("utf-8"); StreamReader readStream = new StreamReader(receiveStream,encode); Char[] read = new Char[256]; int count = readStream.Read(read, 0, 256); String str = String.Empty; while (count > 0) { str += new String(read, 0, count); count = readStream.Read(read, 0, 256); } myHttpWebResponse.Close(); readStream.Close(); string regexstr = @"<script.*</script>"; str = Regex.Replace(str, regexstr, string.Empty, RegexOptions.IgnoreCase); str = str.Replace(" ", string.Empty); doc.LoadXml(str); XslCompiledTransform transformer = new XslCompiledTransform(); transformer.Load(Server.MapPath("xml.xslt")); System.Text.StringBuilder SB = new System.Text.StringBuilder(); transformer.Transform(doc, null, new System.IO.StringWriter(SB)); Response.Write(SB.ToString()); Response.Flush(); 這里主要用到了System.IO、System.Text、System.Xml、System.Xml.Xsl、System.Net和System.Text.RegularExpressions命名空間
至此,跨域請求RSS的問題和在服務器端對RSS進行處理的工作已經完成,在客戶端的ajax請求獲取從后臺發送過去的RSS內容之后,只要在客戶端按照預想的格式進行解析和DOM封裝,便可以正確的顯示RSS內容了。
問題三:RSS源xml文件的編碼問題,一般說來標準的RSS文件編碼都是utf-8的,顯示不會有問題,但個別站點提供的可能是gb2312類型的編碼,這類RSS文件容易顯示成亂碼,對于這個問題,我目前還沒有找到比較優雅的辦法,在這里先征集一下方案吧,呵呵
問題4.前端顯示方式和留給用戶操作的易用性問題 前端顯示方面,在這里選取了時下比較流行的tab方式,占據頁面空間小,切換方便,前面說過可以考慮jquery那樣的框架,的確,jquery是一個很好的框架,除了有很多可以簡化
開發的功能外,它的第三方插件也是非常豐富的,這里就直接選用了一個基于jquery的tab插件,當然,都是一些基于jquery的js代碼,你完全可以根據自己的需要對其進行改進,以適合特定的需求。該插件的調用方式如下:先引用jquery.js,然后是tab插件相關的ui.tabs.css、ui.tabs.js,在頁面里添加如下html代碼 <div id="RssContainer" style=" float:left; width:100%"> <ul> </ul> </div> 初始化時這樣調用: $('#RssContainer ul').tabs({ fxSlide: true, fxFade: true, fxSpeed: 'normal',event: 'mouseover' }); 大致意思是以正常速度和鼠標經過事件處理tab的切換,還另外加上了滑動和消隱效果
接下來是用戶操作的問題,也就是要提供一種方式來讓用戶訂閱和管理自己的RSS,在這里用戶可以從推薦的列表中選擇RSS,也可以自己手動添加互聯網上的任意RSS地址,而對于
已經訂閱的RSS,也可以實施簡單的管理,如取消訂閱等。管理區域的html代碼如下:
Code <div id="manageRssArea" class="floatWindow"> <div style="float: right; clear: both; height: 25px; width: 100%; background: url(images/floatDivbg.gif) no-repeat;"> <div id="manageRssShow"> 管理RSS</div> <div id="addRssShow" class="tabStyle"> 添加RSS</div> </div> <div id="addRssArea" style="clear: both;"> <p style="margin: 5px 0px 0px 0px;"> <input id="fromChoosed" name="addWay" type="radio" checked="checked" /><span class="rssFont">從推薦中選擇</span> <input id="addByHand" name="addWay" type="radio" /><span class="rssFont">手動添加</span></p> <div class="floatDivLine"> </div> <p id="exsitRssList"> <input name="exsitRss" type="checkbox" value="Fun-娛樂~~http://rss.yule.sohu.com/rss/yuletoutiao.xml" />搜狐-娛樂<input name="exsitRss" value="star-星座~~http://astro.women.sohu.com/rss/xingzuoxinwen.xml" type="checkbox" />搜狐-星座</p> <div id="rssItem" style="display: none; margin-top: 20px;"> <p> <span>名稱:</span><input class="textBoxStyle" style="width: 100px;" id="rssName" type="text" /></p> <p> <span>地址:</span><input class="textBoxStyle" style="width: 250px;" id="rssUrl" type="text" /></p> </div> <p> <input id="subBookRss" class="btnStyle rssFont" type="button" value="提交" /> <input class="btnStyle rssFont" onclick="$('#manageRssArea').css('display','none');" type="button" value="關閉" /></p> </div> <div id="manageRss" style="display: none; clear: both;"> <p style="clear: both;"> 已經訂閱的RSS列表,去掉勾選可以取消訂閱</p> <ul> </ul> <p style="clear: both;"> <input id="modifyBook" class="btnStyle rssFont" type="button" value="提交" /> <input class="btnStyle rssFont" onclick="$('#manageRssArea').css('display','none')" type="button" value="關閉" /></p> </div> </div> 相關的js代碼在闡述完第五個問題后一起給出
問題五:要記住用戶個性化的RSS定制方案,記住有兩重含義,在服務端數據庫里為每個用戶記錄其定制方案,或者在客戶端的cookie里記錄,前者消耗服務器資源,而且需要用戶登錄才知道用戶是誰,后者嘛,也有問題,客戶端禁用緩存或者刪除cookie時會失效,至于cookie有效期的問題,我們可以設置為永不過期。當然客戶端的方案還有一個問題就是一個客戶端原則上只有一個用戶的記錄,除非你裝了多個不同內核的瀏覽器。在這里,我選擇了客戶端的方案,為此要引入cookie.js 寫到這里發現代碼實在有些多,論壇又不像cnblogs有專門處理代碼的功能,因此就不全貼出來了,最后完整的例子在附件中給出。
|