Quantcast
Channel: XML – BCmoney MobileTV
Viewing all articles
Browse latest Browse all 16

RSS Reader in jQuery .vs. JavaScript (AJAX)

$
0
0
No Gravatar
RSS

Image via Wikipedia

Parsing RSS is a task that many developers have been faced with. jQuery makes this significantly easier on the client-side, but the good ol’ AJAX is not that bad either if you set things up functionally to minimize on-page code. Two versions of the same RSS Reader with parsing handled with and without the “write less, do more” JavaScript library follow.

DISCLAIMER:
I know I haven’t really captured the spirit of jQuery by using identical functions to straight JavaScript, however, I mainly wanted to show the similarities and differences between using one parser .vs. another.

FOREWARNING:
Thus, I fully accept that a jQuery whiz, which I am not yet, could clearly use the library to write a few lines of a jQuery RSS parser that would easily blow this one away in terms of efficiency and robustness, thus highlighting the advantages over using old-fashioned JavaScript.

JUSTIFICATION:
That’s just not the point of this article, which is merely a quick look at making an AJAX request and parsing XML in jQuery .vs. JavaScript.

Here’s a very basic RSS Reader in jQuery:

/**
 * parseAtom
 * 	Parse Feeds in Atompub (ATOM) feed format
 * @param feed XML Object
 */
function parseAtom(feed) {
	var feed = $(feed).find("feed");				//<feed>
	var feed_title = $(feed).find("title").first().text();			 //<title>
	var feed_subtitle = $(feed).find("subtitle").first().text();	   //<subtitle>	
	var feed_link = $(feed).find("link").first().text();			   //<link>
	var feed_description = $(feed).find("description").first().text(); //<description>
	var feed_updated = $(feed).find("updated").first().text(); 		   //<updated>
	var metadata = '<a href="'+feed_link+'">'+feed_title+'</a><br/>' + feed_description + ' | ' + feed_subtitle + '<br/>' + feed_updated + '<div style="clear:both;"> </div>'; //METADATA	
	var news = '';
	var entry = 0;
	$(feed).find("entry").each( function() {					//<entry>
		title =	$(this).find("title").text().replace(feed_title,'');	//<title>
		guid =	$(this).find("guid").text();					    //<guid>
			id = !empty(guid) ? guid : title.substring(0,12)+'-'+item;		//unique ID	
		image =	$(this).find("link[type='image/jpeg']").attr("href");	//<image>
		link = $(this).find("link").text();								//<link>
		desc = $(this).find("description").text();						//<description>
			description = desc.replace(/</gi,'<').replace(/>/gi,'>');
			if (typeof image==='undefined'||image===null||image==='') { image = 'http://www.canada.com/images/topic/logo_canada.com.gif'; } else { image = 'http://www.canada.com/'+image; }
		news += '<article><a href="#'+id+'" title="Click once for summary, twice to visit source..."><img class="icon" src="'+image+'" alt="'+title+'" /> '+title+'</a><div id="'+id+'" class="lb"><a href="'+link+'"><img src="'+image+'" alt="'+title+'" /></a><a href="#top" class="close"><img src="close.gif" alt="Close" /></a><div class="story">'+description+'</div></div></article>';
		entry++;
	});
	return news; // or metadata+news to show header above news list
}

/**
 * parseRSS
 * 	Parse Feeds in Really Simple Syndication (or RDF Site Summary) format
 * @param rss XML Object
 */
function parseRSS(rss) {
	var rss = $(rss).find("rss");			//<rss>
	var rss_channel = $(rss).find("channel");			//<channel>
	var rss_title = $(rss).find("title").first().text();			 //<title>
	var rss_link = $(rss).find("link").first().text();				 //<link>
	var rss_image = $(rss).find("image").first();			 		 //<image>
		var rss_image_url = rss_image.find("url").text();			 //<url>
		var rss_image_link = rss_image.find("link").text();			 //<link>
		var rss_image_title = rss_image.find("title").text();		 //<title>
	var rss_description = $(rss).find("description").first().text(); //<description>
	var rss_language = $(rss).find("language").text();		 //<language>
	var rss_lastBuildDate = $(rss).find("updated").first().text();   //<updated>
	var rss_copyright = $(rss).find("copyright").text();	 //<copyright>
	var rss_docs = $(rss).find("docs").text();	  		     //<docs>
	var rss_ttl = $(rss).find("ttl").text();				 //<ttl>
	var metadata = '<a href="'+rss_link+'"><img src="'+rss_image_url+'" title="'+rss_image_title+'": "'+rss_description+'" style="float:left; vertical-align:middle;"/></a><br/>' + rss_lastBuildDate + ' | ' + rss_copyright + '<br/>Following spec at: ' + rss_docs + ' | Cache for: ' + rss_ttl + ' | ' + rss_language + '<div style="clear:both;"> </div>'; //METADATA
	var news = '';
	var item = 0;
	$(rss).find("item").each( function() {						//<item>
		title =	$(this).find("title").text().replace(rss_title,'');	//<title>
		guid =	$(this).find("guid").text();					    //<guid>
			id = !empty(guid) ? guid : title.substring(0,12)+'-'+item;		//unique ID
		thumb =	$(this).find("media:thumbnail").attr("url");		//<image>
			image = !empty(thumb) ? thumb : 'rss.png';
		link =	$(this).find("link").text();					    //<link>
		desc =	$(this).find("description").text();					//<description>
			description = desc.replace(/</gi,'<').replace(/>/gi,'>');
		content = $(this).find("content").text(); 		  			//<content>
		news += '<article><a href="#'+id+'" title="Click once for summary, twice to visit source..."><img class="icon" src="'+image+'" alt="'+title+'" /> '+title+'</a><div id="'+id+'" class="lb"><a href="'+link+'"><img src="'+image+'" alt="'+title+'" /></a><a href="#top" class="close"><img src="close.gif" alt="Close" /></a><div class="story">'+description+'</div></div></article>';		
	});
	return news;	
}

function parseFeed(url, type) {
	contentType = type.toLowerCase();
	$.ajax({	
		url: 'proxy.php?url='+encodeURI(url)+'&path='+getPath(url)+'&f='+contentType+'&e=utf-8',
		success: function(data) {
			var news = '';
			if (contentType==='atom'||contentType==='feed') { 
				news = parseAtom(data); //use ATOM parser if feed type was set
			}
			else {
				news = parseRSS(data); //use RSS 2.0 parser if feed was  not set, or it was a value other than ATOM or FEED (i.e. RSS, mRSS, RSS1.0, RSS2.0, RDF, XML, etc...)
			}
			$('#content').html(news);
		},
		error: function(ex) {
			alert('Error loading feed: '+ex);
		}
	});
}


-or-

Here’s the same reader in JavaScript with the AJAX call handled by hand (and thus marginally less cross-browser than the jQuery one, but should work in IE down to 5.5):

/************************************************************/
/* AJAX cross-browser helper utilities */
function loadXMLDoc(docURL) {
	if (window.XMLHttpRequest) {		// FireFox, Opera, Chrome, Safari
		xhttp = new XMLHttpRequest();
	}
	else {								// Internet Explorer
		xhttp = new ActiveXObject("Microsoft.XMLHTTP");
	}
	xhttp.open("GET",docURL,false);
	xhttp.send();
	return xhttp.responseXML;
}

function loadXMLString(txt) {
	if (window.DOMParser) {		// FireFox, Opera, Chrome, Safari
		parser=new DOMParser();
		xmlDoc=parser.parseFromString(txt,"text/xml");
	}
	else { 						// Internet Explorer
		xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
		xmlDoc.async = "false";
		xmlDoc.loadXML(txt); 
	}
	return xmlDoc;
}
/************************************************************/	

function parseRSS(data) {
	var rss = data.getElementsByTagName("rss");		//<rss>
	  //Parse RSS Feed channel properties
	  channel = data.getElementsByTagName("channel");							//<channel>
	  title = data.getElementsByTagName("title")[0].childNodes[0].nodeValue;		//<title>
	  link = data.getElementsByTagName("link")[0].childNodes[0].nodeValue;		//<link>
	  description = data.getElementsByTagName("description")[0].childNodes[0].nodeValue; //<description>
	  image_url = 'rss.png', image_link = '#', image_html=title+' (RSS Feed)';
		image = data.getElementsByTagName("image")[0];					//<image> (optional RSS element)
		if (!empty(image)) {
			image_url = image.getElementsByTagName("url")[0].childNodes[0].nodeValue;		//<url>
			image_link = image.getElementsByTagName("link")[0].childNodes[0].nodeValue;		//<link>
			image_html = !empty(image_url) ? image_url : '<img src="'+image_url+'" title="'+title+'": "'+description+'" style="float:left; vertical-align:middle;"/>';
		}

   	      //language = data.getElementsByTagName("language")[0].childNodes[0].nodeValue;//<language>
		  //copyright = data.getElementsByTagName("copyright")[0].childNodes[0].nodeValue;	//<copyright>
          //lastBuildDate = data.getElementsByTagName("lastBuildDate")[0].childNodes[0].nodeValue; //<lastBuildDate>
          //docs = data.getElementsByTagName("docs")[0].childNodes[0].nodeValue;	  		//<docs>
          //ttl = data.getElementsByTagName("ttl")[0].childNodes[0].nodeValue;				//<ttl>		
		  metadata = "<a href=\""+link+"\">"+image_html+"</a>";//"<br/>" + lastBuildDate + " | " + copyright + "<br/>Following spec at: " +  docs + " | Cache for: " + ttl + " | " + language + "<div style=\"clear:both;\"> </div>";      

	  //Parse RSS Feed items 
      items = data.getElementsByTagName("item"); 											//<item>
      news = "<ol>";
      for (i = 0; i < items.length; i++) {	  	
           title = items[i].getElementsByTagName("title")[0].childNodes[0].nodeValue;	  		  //<title>
			guid = items[i].getElementsByTagName("guid")[0].childNodes[0].nodeValue;				  //<guid>	
				id = !empty(guid) ? guid : title.substring(0,12)+'-'+item;					//unique ID
		   image = 'RSS.png';
			try {
				//pic = items[i].getElementsByTagName("media:thumbnail")[0].getAttribute("url");  		  //<media:thumbnail> (image) mRSS2.0 only
				//	image = !empty(pic) ? pic : 'RSS.png';
			}
			  catch (ex) {
			}				
		   link = items[i].getElementsByTagName("link")[0].childNodes[0].nodeValue;		  		  //<link>
           pubDate = items[i].getElementsByTagName("pubDate")[0].childNodes[0].nodeValue;		  //<pubDate>
		   desc = items[i].getElementsByTagName("description")[0].childNodes[0].nodeValue; //<description>		  
				description = desc.replace(/</gi,'<').replace(/>/gi,'>');
		   news += '<div class="article"><a href="#lb'+i+'" title="Click once for summary, twice to visit source..."><img class="icon" src="'+image+'" alt="'+title+'" /> '+title+'</a><div id="lb'+i+'" class="lb"><a href="'+link+'"><img src="'+image+'" alt="'+title+'" /></a><a href="#top" class="close"><img src="close.gif" alt="Close" /></a><div class="story">'+description+'</div></div></div>';
      }
	  news += "</ol>";
	return metadata+news;
}


function parseAtom(data) {
	var feed = data.getElementsByTagName("feed");				//<feed>
	var title = data.getElementsByTagName("title")[0].childNodes[0].nodeValue;			 //<title>
	var subtitle = data.getElementsByTagName("subtitle")[0].childNodes[0].nodeValue;		 //<subtitle>	
	//var link = data.getElementsByTagName("link")[0].childNodes[0].nodeValue;				 //<link>
	//var description = data.getElementsByTagName("description")[0].childNodes[0].nodeValue;//<description>
	var updated = data.getElementsByTagName("updated")[0].childNodes[0].nodeValue; 		  //<updated>
	var news = '';//METADATA: '<a href="'+link+'">'+title+'</a><br/>' + description + ' | ' + subtitle + '<br/>' + updated + '<div style="clear:both;"> </div>';
	var entry = data.getElementsByTagName("entry");
	for (var i=0; i<entry.length; i++) {					//<entry>
		title =	entry[i].getElementsByTagName("title")[0].childNodes[0].nodeValue; //<title>			
		  guid = items[i].getElementsByTagName("guid")[0].childNodes[0].nodeValue;				  //<guid>	
			id = !empty(guid) ? guid : title.substring(0,12)+'-'+item;					//unique ID				
		image = 'RSS.png';
			try {
				pic = entry[i].getElementsByTagName("link")[1].getAttribute("href");	//<image> link[type='image/jpeg']
					image = !empty(pic) ? pic : 'RSS.png';
			}
			  catch (ex) {
			}
		link = entry[i].getElementsByTagName("link")[0].getAttribute("href");		//<link> link[type='text/html']
		desc = entry[i].getElementsByTagName("description")[0].childNodes[0].nodeValue;	//<description>
			description = desc.replace(/</gi,'<').replace(/>/gi,'>');
		news += '<div class="article"><a href="#lb'+i+'" title="Click once for summary, twice to visit source..."><img class="icon" src="'+image+'" alt="'+title+'" /> '+title+'</a><div id="lb'+i+'" class="lb"><a href="'+link+'"><img src="'+image+'" alt="'+title+'" /></a><a href="#top" class="close"><img src="close.gif" alt="Close" /></a><div class="story">'+description+'</div></div></div>';
	}
	return news;	
}

var FEED_URL = 'http://feeds.wired.com/wired/index';
var type = 'RSS';
	var contentType = type.toLowerCase();
	var url = 'proxy.php?url='+encodeURI(FEED_URL)+'&f='+contentType+'&e=utf-8';	
//    xmlDoc = loadXMLString(xml);
var xmlDoc = loadXMLDoc(url);
var news = '';
if (contentType==='atom'||contentType==='feed') { 
	news = parseAtom(xmlDoc);
}
else {
	news = parseRSS(xmlDoc);
} 
document.write(news);


-or-

Conclusion

OK, Admittedly both are equally ugly code but as they say there’s more than one way to skin a cat. This was at least a useful exercise for me to get my head around some of the differences between jQuery and vanilla JavaScript DOM parsing with hand-coded AJAX, for such a task as trivial as displaying an RSS feed’s XML (which clearly got out of hand here).

If I had to do it over again, I would probably see the value of jQuery and design the code with use of the library in mind from the start, doing a better job at using the jQuery style of coding instead of old-school JS function style. The jQuery RSS Reader is more dynamic in that it lets you select from multiple feeds. You could even put in a text box and allow user-powered URL submission, but that’s an entirely different topic.

PETA:
Though I’m quite allergic, I still don’t really approve of skinning cats!

 

flattr this!


Viewing all articles
Browse latest Browse all 16

Trending Articles