Playing Chicken With Common Sense

Every site you browse now-a-days has RSS feeds.  Using site content from other sites via RSS feeds, helps keep your content fresh.  This means that you are leveraging other’s time and knowledge to build your site’s value. My partner and I wanted to leverage our blogging effort in our corporate website, to display the latest blog entries (as shown above) for visitors to see, as well as making them aware that we have a blog. However we ran into a problem our blog is on another domain.  image

We discovered that JavaScript cannot read cross domains.  This means that JavaScript can only read xml files from the same domain as the html file it resides in.

I needed a server-side proxy to retrieve the RSS XML from the site on the other domain.  In the process. 

Based on my findings, I have developed an JavaScript RSS Reader for viewing RSS Feeds from any domain you provide it.

image

This reader demonstrates the methodology that we used to integrate the RSS feed from our blog into our corporate website. This solutions consists of 3 files – reader.html, rss.js, proxy.ashx

reader.html

The reader.html is the presentation layer or user interface for the RSS Reader. It manages the feed selection and the html layout that will be used to format the RSS feed once it has been retrieved.

       1: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
       2:         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       3: <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
       4: <head>
       5:     <meta http-equiv="content-type" content="text/html; charset=utf-8" />
       6:     <title>RSS Reader</title>    
       7:     <link rel="stylesheet" type="text/css" href="cs/reader.css" />
       8:     <script src="js/rss.js" type="text/javascript"></script>
       1:  
       2:     <script type="text/javascript">
       3:         function getRssFeedFromSelection() {
       4:             // get Selected Feed                  
       5:             feeds = document.getElementById("feeds");
       6:             var myindex = feeds.selectedIndex;
       7:             var SelValue = feeds.options[myindex].value;
       8:             
       9:             getRssFeed(SelValue);
      10:         }
      11:         function getRssFeedFromUrl() {
      12:             // get Url from textBox
      13:             txtRssUrl = document.getElementById("txtRSSFeedUrl");
      14:             var rssUrl = txtRssUrl.value;
      15:  
      16:             getRssFeed(rssUrl);
      17:         }
      18:         function getRssFeed(rssUrl) {
      19:             // get Item Count
      20:             txtItemCount = document.getElementById("txtItemCount");
      21:             var itemCount = txtItemCount.value;       
      22:             
      23:             var entryHtmlFormat = ""; 
      24:             entryHtmlFormat += "<div class=\"entry\"><h2 class=\"postTitle\">[[TITLE]]<\/h2>";
      25:             entryHtmlFormat += "<em class=\"date\">[[PUBDATE]] | [[AUTHOR]]</em>";
      26:             entryHtmlFormat += "<p class=\"description\">[[DESCRIPTION]]</p>";
      27:             entryHtmlFormat += "<a href=\"[[LINK]]\" target=\"_blank\">Read More >><\/a><\/div>";
      28:                         
      29:             // Use the proxy to retrieve the RSS feed's xml
      30:             ReadRSS('proxy.ashx?url=' + rssUrl, entryHtmlFormat, "rssContent", itemCount);            
      31:         };    
      32:     
    </script>
       9: </head>
      10: <body>
      11: <div id="container">    
      12:     <div id="ui">
      13:         <br />
      14:         <img src="http://www.wijix.com/themes/illacrimo Modified/images/LogoIcon.png" width="20%" />
      15:         <h1>RSS Feed Reader</h1>
      16:         <form id="selectParser" action="">
      17:             <table border="0" style="width:100%;">
      18:                 <tr>
      19:                     <td  style="width:100px;"><label>Select a feed:</label></td>
      20:                     <td>        
      21:                         <select id="feeds" style="width:98%;">
      22:                             <option value="">Select</option>
      23:                             <option value="http://www.wijix.com/syndication.axd">Wijix</option>
      24:                             <option value="http://feeds.feedburner.com/dotnetkicks">DotNetKicks</option>
      25:                             <option value="http://www.asp.net/news/rss.ashx/">ASP.NET News</option>
      26:                                <option value="http://feeds.digg.com/digg/container/technology/popular.rss">Digg - Technology</option>
      27:                                <option value="http://rss.slashdot.org/Slashdot/slashdot">SlashDot</option>
      28:                             <option value="http://online.wsj.com/xml/rss/3_7014.xml">Wall Street Journal - Business</option>
      29:                             <option value="http://online.wsj.com/xml/rss/3_7455.xml">Wall Street Journal - Technology</option>
      30:                         </select>        
      31:                     </td>
      32:                     <td  style="width:75px;">
      33:                         <input id="btnGetFeedSelection" type="button" value="Retrieve" onclick="getRssFeedFromSelection();" />
      34:                     </td>
      35:                 </tr>
      36:                 <tr>
      37:                     <td><label>Enter RSS url:</label></td>
      38:                     <td align="left"><input id="txtRSSFeedUrl" type="text" style="width:98%;"/></td>
      39:                     <td><input id="btnGetFeedfromUrl" type="button" value="Retrieve" onclick="getRssFeedFromUrl();" /></td>
      40:                 </tr>
      41:                 <tr>
      42:                     <td><label>Items to Display:</label></td>
      43:                     <td><input id="txtItemCount" type="text" value="5"  style="width:50px;"/></td>
      44:                     <td></td>
      45:                 </tr>
      46:             </table>       
      47:         </form>
      48:     </div>
      49:     <div id="rssContent">
      50:         &nbsp;
      51:     </div>
      52: </div>
      53: </body>
      54: </html>

rss.js

The rss.js file simply takes the provided RssFeed Url, which has been converted to use the proxy, and formatted the RSS Feed XML using the provided format.

   1: /*    
   2: RSS Feed Reader v1.0
   3: Copyright (c) 2009 Wijix, LLC
   4: Written by Brad Merrell
   5: email: webmaster@wijix.com
   6: */
   7: function getNode(TagName, node)
   8: {
   9:     var currentNode = (node == null) ? xmlDoc.getElementsByTagName(TagName) : 
  10:                     items[node].getElementsByTagName(TagName);
  11:     if(currentNode.length > 0)
  12:         return currentNode[0].firstChild.nodeValue;
  13: }
  14:  
  15: function ReadRSS(rssFeed, htmlFormat, divName, itemCount) 
  16: {
  17:     divContent = document.getElementById(divName);    
  18:     
  19:     try
  20:     {
  21:         if (document.all)
  22:         {
  23:             var errorHappendHere = "Check Browser and security settings";
  24:             xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
  25:         }
  26:         else
  27:         {
  28:             var errorHappendHere = "Apparently one cant read remote xml via firefox, please copy the file to your server";
  29:             xmlDoc = document.implementation.createDocument("","",null);
  30:         }
  31:     
  32:         xmlDoc.async=false;
  33:         xmlDoc.load(rssFeed);
  34:     
  35:         items=xmlDoc.getElementsByTagName('item');
  36:         SetRSSTemplates(divContent, htmlFormat, itemCount);
  37:     }
  38:     
  39:     catch(e)
  40:     {
  41:         divContent.innerHTML = 'Error occured. <br/>Thrown Error:' + e.message + "<br/>Note: " + errorHappendHere;
  42:     }
  43: }
  44:  
  45: function SetRSSTemplates(divContent, htmlFormat, itemCount)
  46: {
  47:     var itemCnt = itemCount;
  48:     if (items.length < itemCnt)
  49:     {
  50:         itemCnt = items.length;
  51:     }
  52:  
  53:     var buffer = "";
  54:     for(var i=0; i< itemCnt; i++) 
  55:     {
  56:         var output = htmlFormat;
  57:         output = output.replace('[[LINK]]',getNode('link',i));
  58:         output = output.replace('[[TITLE]]', getNode('title', i));
  59:         output = output.replace('[[PUBDATE]]',getNode('pubDate',i));        
  60:         output = output.replace('[[DESCRIPTION]]', getNode('description', i));
  61:         output = (getNode('author', i) == null) ? output.replace('[[AUTHOR]]', '') : 
  62:                     output.replace('[[AUTHOR]]', getNode('author', i));
  63:         buffer += output;
  64:     }
  65:     divContent.innerHTML = buffer;
  66:     
  67: }

    proxy.ashx

The server-side proxy, which retrieves the specified RSS Feed XML from the cross domain or local domain site.  This proxy is used to trick the JavaScript into thinking that the RSS Feed is coming from a local domain, when in actuality the RSS Feed XML is being retrieved from a cross domain site by the server side proxy, which masked the true location of the RSS feed.

Many of the proxy examples that I found were written in PHP, so for the sake of showing something different, my server-side proxy was written in ASP.NET/C#.

       1: <%@ WebHandler Language="C#" Class="proxy" %>
       2:  
       3: using System;
       4: using System.Web;
       5: using System.Net;
       6:  
       7: public class proxy : IHttpHandler
       8: {
       9:     private HttpContext _context;
      10:  
      11:     public HttpContext Context
      12:     {
      13:         get { return _context; }
      14:     }
      15:  
      16:     public HttpResponse Response
      17:     {
      18:         get
      19:         {
      20:             return Context.Response; 
      21:         }
      22:     }
      23:  
      24:     public HttpRequest Request
      25:     {
      26:         get
      27:         {
      28:             return Context.Request;
      29:         }
      30:     }
      31:  
      32:     public void ProcessRequest(HttpContext context)
      33:     {
      34:         this._context = context;
      35:         
      36:         string url = Request.QueryString["url"];
      37:         
      38:         if (String.IsNullOrEmpty(url))
      39:         {
      40:             Response.StatusCode = (int)HttpStatusCode.NotFound;
      41:             return;
      42:         }
      43:         
      44:         try
      45:         {
      46:             WebRequest request = WebRequest.Create(url);
      47:             HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse();
      48:             
      49:             if (!String.IsNullOrEmpty(webResponse.ContentEncoding))
      50:             {
      51:                 try
      52:                 {
      53:                     Response.ContentEncoding = System.Text.Encoding.GetEncoding(webResponse.ContentEncoding);
      54:                 }
      55:                 catch (ArgumentException ex)
      56:                 {
      57:                     System.Diagnostics.Trace.WriteLine(ex.ToString());
      58:                 }
      59:             }
      60:             Response.ContentType = webResponse.ContentType;
      61:             Response.StatusCode = (int)webResponse.StatusCode;
      62:             Response.StatusDescription = webResponse.StatusDescription;
      63:             
      64:             byte[] buffer = new byte[4096];
      65:             System.IO.Stream stream = webResponse.GetResponseStream();
      66:  
      67:             for (; ; )
      68:             {
      69:                 int read = stream.Read(buffer, 0, buffer.Length);
      70:  
      71:                 if (read == 0)
      72:                     break;
      73:  
      74:                 if (read > 0)
      75:                     Response.OutputStream.Write(buffer, 0, read);
      76:             }
      77:         }
      78:         catch (ArgumentNullException ex)
      79:         {
      80:             Response.StatusCode = (int)HttpStatusCode.NotFound;
      81:             System.Diagnostics.Trace.WriteLine(ex.ToString());
      82:         }
      83:         catch (System.Security.SecurityException ex)
      84:         {
      85:             Response.StatusCode = (int)HttpStatusCode.Forbidden;
      86:             System.Diagnostics.Trace.WriteLine(ex.ToString());
      87:         }
      88:         catch (UriFormatException ex)
      89:         {
      90:             Response.StatusCode = (int)HttpStatusCode.BadRequest;
      91:             System.Diagnostics.Trace.WriteLine(ex.ToString());
      92:         }
      93:         catch (Exception ex)
      94:         {
      95:             Response.StatusCode = (int)HttpStatusCode.InternalServerError;
      96:             System.Diagnostics.Trace.WriteLine(ex.ToString());
      97:         }
      98:     }
      99:  
     100:     public bool IsReusable
     101:     {
     102:         get
     103:         {
     104:             return false;
     105:         }
     106:     }
     107: }
    In a nutshell, RSS feeds can be easily added to an html web site, if you know how.

Demo: JavaScript RSS Reader                    Download: WijixRssReader.zip

Actual Implementation in our corporate site can be seen on wijix.net.  Simply scroll to the bottom of the page.

  • 0 Comments
  • E-mail
  • Kick it!
  • Shout it
  • Bookmark and Share

Control panel

RecentComments

Comment RSS