首先,簡(jiǎn)單的分析一下需求,分析過(guò)程忽略,主要的需求和要解決的問(wèn)題大概有以下幾個(gè)方面: 1.RSS源提供的RSS顯示格式和顯示內(nèi)容統(tǒng)一性的問(wèn)題 2.Ajax支持以及Ajax支持下的跨域訪問(wèn)的問(wèn)題 3.RSS源xml文件的編碼問(wèn)題 4.前端顯示方式和留給用戶操作的易用性問(wèn)題 5.要記住用戶個(gè)性化的RSS定制方案 對(duì)于問(wèn)題1,各大RSS 內(nèi)容提供很好的遵循了所謂的業(yè)界規(guī)范,如新浪NBA的RSS結(jié)構(gòu)大致如下:
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[蘇群每周評(píng):綠衫軍雄霸天下 火箭雄鹿如患難兄弟]]> </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日)各隊(duì)實(shí)力排行榜:
1.凱爾特人 22-3 2
-1 1 -
主場(chǎng)輸給活塞隊(duì),但周末最后一戰(zhàn)對(duì)魔術(shù)時(shí)又以103比91取勝,仍然是東部主場(chǎng)戰(zhàn)績(jī)最強(qiáng)隊(duì)伍。目前凱爾特人保持聯(lián)盟防守第一,最近12場(chǎng)比賽中,.]]> </description> </item> <item> 結(jié)構(gòu)同上一個(gè)item,此處省略 </item> </channel> </rss> 可以看出,首先是一些關(guān)于RSS內(nèi)容自身的描述性信息,如語(yǔ)言、鏈接地址、版權(quán)信息等等,然后是若干個(gè)以<item></item>并列的真正的內(nèi)容區(qū)域,內(nèi)容一般包括標(biāo)題、摘要、發(fā)布時(shí)間、所屬分類(lèi)、評(píng)論等等信息,這樣的目錄結(jié)構(gòu)在業(yè)界遵循RDF(即資源描述)的規(guī)范,因此,其他RSS內(nèi)容提供商所提供的RSS也是這種標(biāo)準(zhǔn)結(jié)構(gòu)的,這使得我們可以放心的訂閱任何符合規(guī)范的網(wǎng)站RSS內(nèi)容。但也不是萬(wàn)事大吉了,可以看到,提供的內(nèi)容太多,而我們想顯示給用戶的無(wú)非就是一個(gè)新聞標(biāo)題,一個(gè)日期和一個(gè)摘要,特別是一些內(nèi)容提供網(wǎng)站如搜狐,經(jīng)常在其摘要中加入圖片,如果我們?cè)獠粍?dòng)的讓其顯示出來(lái),有可能會(huì)影響到統(tǒng)一性和美觀,想到這里,我們接下來(lái)要做的事情就很明確了,就是有選擇的在自己的RSS訂閱顯示區(qū)域只顯示最重要和最感興趣的內(nèi)容,而不是全部?jī)?nèi)容。這就引出了另外一項(xiàng)需要掌握的技術(shù):xslt,它是專門(mén)用來(lái)轉(zhuǎn)換承載了RSS內(nèi)容的xml文檔的,有一系列自己語(yǔ)法和特點(diǎn),這里不細(xì)講,可以參考:http://www.baidu.com,它提供了一套較為全面的教程。在我這里,最終需要的xslt文件內(nèi)容如下:
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規(guī)定了從源RSS里面選取前5條內(nèi)容的標(biāo)題,發(fā)布時(shí)間和摘要信息,并按照我們自己規(guī)定的格式予以顯示 還有一個(gè)問(wèn)題是,我們現(xiàn)在雖然控制了要選取和現(xiàn)實(shí)的項(xiàng),但是項(xiàng)的內(nèi)容我們還沒(méi)有進(jìn)行處理,而恰恰其中的圖片和一些js腳本是我們不想要的,所以務(wù)必過(guò)濾一下,一方面減少網(wǎng)絡(luò)字節(jié)傳輸,另一方面符合了我們想要的內(nèi)容。過(guò)濾主要用到了正則表達(dá)式,可以在服務(wù)端(C#.net)和客戶端(javascript)中進(jìn)行,如在后臺(tái)過(guò)濾js腳本,可以這樣來(lái)進(jìn)行: string regexstr = @"<script.*</script>"; str = Regex.Replace(str, regexstr, string.Empty, RegexOptions.IgnoreCase); 當(dāng)然別忘了引用 System.Text.RegularExpressions 命名空間在javascript中過(guò)濾圖片信息可以這樣來(lái)進(jìn)行: var reg =/<img.*?>/ig; str=str.replace(reg,""); 在客戶端進(jìn)行的代價(jià)是那些代表圖片的html代碼字節(jié)已經(jīng)傳送到了客戶端,會(huì)稍稍影響下載速度吧,但畢竟<img />標(biāo)簽不像js那樣可能會(huì)大段大段的,所以這個(gè)影響是可以忽略的。
至此,第一個(gè)問(wèn)題的各個(gè)方面都有了一個(gè)比較好的解決接下來(lái)我們來(lái)看第二個(gè)問(wèn)題,ajax支持和ajax跨越的問(wèn)題,現(xiàn)在主流瀏覽器都支持ajax,要使用ajax支持,無(wú)非是寫(xiě)一些構(gòu)造ajax過(guò)程的js代碼,當(dāng)然也可以用成熟的js框架,如jquery,重點(diǎn)是第二個(gè)問(wèn)題,為了保證安全性,ajax是不允許跨越的(這個(gè)問(wèn)題百度一下,一堆一堆的),我們要做的讓它可以“跨域”,當(dāng)然,這里的跨域是打上了引號(hào)的,作為引用,這里將采用的不過(guò)是一種曲線方案,而讓用戶覺(jué)察不到。 我選取的方案是利用.net強(qiáng)大而完善的功能來(lái)先借助服務(wù)器下載各個(gè)不同域上的RSS內(nèi)容文件,解析處理后發(fā)送至請(qǐng)求的客戶端,在這里我們主要用到了.net的HttpWebRequest和HttpWebResponse類(lèi),它們位于System.Net命名空間下,利用它們可以請(qǐng)求RSS內(nèi)容提供商URL上的RSS文件,當(dāng)然,獲取該文件后我們要做一系列的處理,這些處理包括將返回的數(shù)據(jù)流格式轉(zhuǎn)化成字符串格式,利用前面講到的xslt來(lái)獲取我們想要的RSS選項(xiàng),過(guò)濾其中的js代碼,最后推送到客戶端等等,核心代碼如下:
Code XmlDocument doc = new XmlDocument(); string reqUrl = Request.Params["url"].ToString();//請(qǐng)求的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命名空間
至此,跨域請(qǐng)求RSS的問(wèn)題和在服務(wù)器端對(duì)RSS進(jìn)行處理的工作已經(jīng)完成,在客戶端的ajax請(qǐng)求獲取從后臺(tái)發(fā)送過(guò)去的RSS內(nèi)容之后,只要在客戶端按照預(yù)想的格式進(jìn)行解析和DOM封裝,便可以正確的顯示RSS內(nèi)容了。
問(wèn)題三:RSS源xml文件的編碼問(wèn)題,一般說(shuō)來(lái)標(biāo)準(zhǔn)的RSS文件編碼都是utf-8的,顯示不會(huì)有問(wèn)題,但個(gè)別站點(diǎn)提供的可能是gb2312類(lèi)型的編碼,這類(lèi)RSS文件容易顯示成亂碼,對(duì)于這個(gè)問(wèn)題,我目前還沒(méi)有找到比較優(yōu)雅的辦法,在這里先征集一下方案吧,呵呵
問(wèn)題4.前端顯示方式和留給用戶操作的易用性問(wèn)題 前端顯示方面,在這里選取了時(shí)下比較流行的tab方式,占據(jù)頁(yè)面空間小,切換方便,前面說(shuō)過(guò)可以考慮jquery那樣的框架,的確,jquery是一個(gè)很好的框架,除了有很多可以簡(jiǎn)化
開(kāi)發(fā)的功能外,它的第三方插件也是非常豐富的,這里就直接選用了一個(gè)基于jquery的tab插件,當(dāng)然,都是一些基于jquery的js代碼,你完全可以根據(jù)自己的需要對(duì)其進(jìn)行改進(jìn),以適合特定的需求。該插件的調(diào)用方式如下:先引用jquery.js,然后是tab插件相關(guān)的ui.tabs.css、ui.tabs.js,在頁(yè)面里添加如下html代碼 <div id="RssContainer" style=" float:left; width:100%"> <ul> </ul> </div> 初始化時(shí)這樣調(diào)用: $('#RssContainer ul').tabs({ fxSlide: true, fxFade: true, fxSpeed: 'normal',event: 'mouseover' }); 大致意思是以正常速度和鼠標(biāo)經(jīng)過(guò)事件處理tab的切換,還另外加上了滑動(dòng)和消隱效果
接下來(lái)是用戶操作的問(wèn)題,也就是要提供一種方式來(lái)讓用戶訂閱和管理自己的RSS,在這里用戶可以從推薦的列表中選擇RSS,也可以自己手動(dòng)添加互聯(lián)網(wǎng)上的任意RSS地址,而對(duì)于
已經(jīng)訂閱的RSS,也可以實(shí)施簡(jiǎn)單的管理,如取消訂閱等。管理區(qū)域的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">手動(dòng)添加</span></p> <div class="floatDivLine"> </div> <p id="exsitRssList"> <input name="exsitRss" type="checkbox" value="Fun-娛樂(lè)~~http://rss.yule.sohu.com/rss/yuletoutiao.xml" />搜狐-娛樂(lè)<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="關(guān)閉" /></p> </div> <div id="manageRss" style="display: none; clear: both;"> <p style="clear: both;"> 已經(jīng)訂閱的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="關(guān)閉" /></p> </div> </div> 相關(guān)的js代碼在闡述完第五個(gè)問(wèn)題后一起給出
問(wèn)題五:要記住用戶個(gè)性化的RSS定制方案,記住有兩重含義,在服務(wù)端數(shù)據(jù)庫(kù)里為每個(gè)用戶記錄其定制方案,或者在客戶端的cookie里記錄,前者消耗服務(wù)器資源,而且需要用戶登錄才知道用戶是誰(shuí),后者嘛,也有問(wèn)題,客戶端禁用緩存或者刪除cookie時(shí)會(huì)失效,至于cookie有效期的問(wèn)題,我們可以設(shè)置為永不過(guò)期。當(dāng)然客戶端的方案還有一個(gè)問(wèn)題就是一個(gè)客戶端原則上只有一個(gè)用戶的記錄,除非你裝了多個(gè)不同內(nèi)核的瀏覽器。在這里,我選擇了客戶端的方案,為此要引入cookie.js 寫(xiě)到這里發(fā)現(xiàn)代碼實(shí)在有些多,論壇又不像cnblogs有專門(mén)處理代碼的功能,因此就不全貼出來(lái)了,最后完整的例子在附件中給出。
|