Skip to content

Instantly share code, notes, and snippets.

@jwmcpeak
Created November 10, 2011 20:25
Show Gist options
  • Save jwmcpeak/1356097 to your computer and use it in GitHub Desktop.
Save jwmcpeak/1356097 to your computer and use it in GitHub Desktop.
XParser 2 -- A JavaScript RSS/Atom Parser (2006)
/***********************************
XParser: An Atom and RSS parser
Version 2.0
by Jeremy McPeak http://www.wdonline.com
Copyright(c) 2004-2006 Jeremy McPeak. All Rights Reserved.
Dependencies: zXml Library by Nicholas C. Zakas, http://www.nczonline.net/
***********************************/
var xparser = {};
/**
* Enum for the different types of feeds supported.
* @scope public
* @type Enum
*/
xparser.feedType = {
rss : 1,
atom : 2
};
/**
* Gets the remote feed and creates the appropriate feed object.
* @static
* @scope public
* @param sUrl The string containing the URL of the remote feed.
* @param fpCallBack The function to call when the feed is completely parsed.
* @param oCallBackScope The scope in which to call the call back method.
*/
xparser.getFeed = function (sUrl, fpCallBack, oCallBackScope) {
var oReq = zXmlHttp.createRequest();
oReq.onreadystatechange = function () { //Handle the onreadystatechange event
if (oReq.readyState == 4) {
if (oReq.status == 200 || oReq.status == 304) {
var oFeed = null; //Just a variable to hold the feed object.
//Create the XML DOM
var oXmlDom = zXmlDom.createDocument();
//And load the data.
oXmlDom.loadXML(oReq.responseText);
var oRootNode = oXmlDom.documentElement;
//Get the name of the document element.
var sRootName;
if (oRootNode.nodeName.indexOf(":") > -1) { //Check to see if the element has a prefix.
sRootName = oRootNode.nodeName.split(":")[1]; //Split it and get the actual element name.
} else {
sRootName = oRootNode.nodeName; //Else, just get the element name.
}
//Check the element name to decide the feed.
switch (sRootName.toLowerCase()) {
case "feed": //It's Atom. Create the object.
oFeed = new xparser.AtomFeed(
oRootNode,
fpCallBack,
oCallBackScope
);
break;
case "rss": //It's RSS
//Check the version. If it's less than 2, throw an error
if (parseInt(oRootNode.getAttribute("version")) < 2) {
throw new Error("XParser Error! RSS feed version " +
"is not supported"
);
}
//We've made it this far. Create the RssFeed object.
oFeed = new xparser.RssFeed(
oRootNode,
fpCallBack,
oCallBackScope
);
break;
default: //The feed isn't supported. Throw an error
throw new Error("XParser Error: The supplied feed " +
"is currently not supported."
);
break;
}
} else { //The HTTP Status code isn't what we wanted; throw an error.
throw new Error("XParser Error: XMLHttpRequest failed. " +
"HTTP Status: " + oReq.status
);
}
}
};
//Make the request
oReq.open("GET", sUrl, true);
oReq.send(null);
};
/**
* Represents a DOM node.
* @constructor
* @scope public
* @param oNode The node to retrieve data from..
*/
xparser.FeedNode = function (oNode) {
/**
* The text contained in the node.
*/
this.value /*:string*/ = (oNode && (oNode.text || oNode.getText())) || null;
};
/**
* An abstract class representing a feed.
* @constructor
* @scope public
* @param iFeedType The type of feed; value is obtained from feedType
* @param fpCallBack The function to call when the feed is completely parsed.
* @param oCallBackScope The scope in which to call the call back method.
*/
xparser.BaseFeed = function (iFeedType, fpCallBack, oCallBackScope) {
/**
* The feed's type.
* @type Integer
*/
this.type = iFeedType || null;
/**
* Represents the <atom:title/> and <rss:title/> element.
* @type FeedNode
*/
this.title = null;
/**
* Represents the <atom:link/> and <rss:link/> element.
* @type FeedNode
*/
this.link = null;
/**
* Represents the <atom:tagline/> and <rss:description/> element.
* @type FeedNode
*/
this.description = null;
/**
* Represents the <atom:copyright/> and <rss:copyright/> element.
* @type FeedNode
*/
this.copyright = null;
/**
* Represents the <atom:generator/> and <rss:generator/> element.
* @type FeedNode
*/
this.generator = null;
/**
* Represents the <atom:modified/> and <rss:lastbuilddate/> element.
* @type FeedNode
*/
this.modified = null;
/**
* Represents the <atom:author/> and <rss:managingeditor/> element.
* @type FeedNode
*/
this.author = null;
/**
* Array of <atom:entry/> or <rss:item/> element.
* @type Array
*/
this.items = [];
/**
* The function to call when parsing is complete.
* @type Function
*/
this.callBack =
(typeof fpCallBack == "function") ? fpCallBack : function () {};
/**
* The scope in which to call callBack.
* @type Object
*/
this.callBackScope =
(typeof oCallBackScope == "object") ? oCallBackScope : this;
};
xparser.BaseFeed.prototype = {
/**
* Parses the data supplied using XPath.
* @scope public
* @param oContextNode the node in which to evaluate an XPath expression.
* @param oElements A hash table, consisting of key/value pairs of class property names and element names.
* @param oNamespaces A hash table containing prefix/namespaceURI as key/value.
*/
parse : function (oContextNode, oElements, oNamespaces ) {
//Loop through the keys
for (var sProperty in oElements) {
//Create FeedNode objects with the node
//returned from the XPath evaluation
this[sProperty] = new xparser.FeedNode(
zXPath.selectSingleNode(
oContextNode,
oElements[sProperty],
oNamespaces
)
);
}
}
};
/**
* An abstract class representing an <atom:entry/> or <rss:item/> element.
* @constructor
* @scope public
*/
xparser.BaseItem = function () {
/**
* Represents the <atom:title/> and <rss:title/> element.
* @type FeedNode
*/
this.title = null;
/**
* Represents the <atom:author/> and <rss:author/> element.
* @type FeedNode
*/
this.author = null;
/**
* Represents the <atom:link/> and <rss:link/> element.
* @type FeedNode
*/
this.link = null;
/**
* Represents the <atom:content/> and <rss:description/> element.
* @type FeedNode
*/
this.description = null;
/**
* Represents the <atom:issued/> and <rss:pubdate/> element.
* @type FeedNode
*/
this.date = null;
};
xparser.BaseItem.prototype = {
/**
* Parses the data supplied using XPath.
* @scope public
* @param oContextNode the node in which to evaluate an XPath expression.
* @param oElements A hash table, consisting of key/value pairs of class property names and element names.
* @param oNamespaces A hash table containing prefix/namespaceURI as key/value.
*/
parse : function (oContextNode, oElements, oNamespaces ) {
for (var prop in oElements) { //Create a FeedNode object with the selected node.
this[prop] = new xparser.FeedNode(zXPath.selectSingleNode(oContextNode, oElements[prop], oNamespaces));
}
}
};
/**
* Represents an RSS feed.
* @constructor
* @extends xparser.BaseFeed
* @scope public
* @param oRootNode The documentElement of the XML document.
* @param fpCallBack The function to call when the feed is completely parsed.
* @param oCallBackScope The scope in which to call the call back method.
*/
xparser.RssFeed = function (oRootNode, fpCallBack, oCallBackScope) {
//Call the parent class.
xparser.BaseFeed.apply(this,
[xparser.feedType.rss, fpCallBack, oCallBackScope]);
var oChannelNode = zXPath.selectSingleNode(oRootNode, "channel");
//Create the hash of property names/element names
var oElements = {
title : "title",
link : "link",
description : "description",
copyright : "copyright",
generator : "generator",
modified : "lastbuilddate",
author : "managingeditor"
};
//Parse the data
this.parse(oChannelNode, oElements, []);
var cItems = zXPath.selectNodes(oChannelNode, "item");
//Populate items[]
for (var i = 0, oItem; oItem = cItems[i]; i++) {
this.items.push(new xparser.RssItem(oItem));
}
//Call the callback in the specified scope. Pass this object as a parameter.
this.callBack.apply(this.callBackScope, [this]);
};
xparser.RssFeed.prototype = new xparser.BaseFeed();
/**
* Represents a <rss:item/> element.
* @constructor
* @extends xparser.BaseItem
* @scope public
*/
xparser.RssItem = function (oItemNode) {
//Call parent class.
xparser.BaseItem.apply(this, []);
//Create the hash of property names/element names
var oElements = {
title : "title",
link : "link",
description : "description",
date : "pubDate",
author : "author"
};
//Parse the data.
this.parse(oItemNode, oElements, []);
};
xparser.RssItem.prototype = new xparser.BaseItem();
/**
* An abstract class representing a feed.
* @constructor
* @extends xparser.BaseFeed
* @scope public
* @param iFeedType The type of feed; value is obtained from feedType
* @param fpCallBack The function to call when the feed is completely parsed.
* @param oCallBackScope The scope in which to call the call back method.
*/
xparser.AtomFeed = function (oRootNode, fpCallBack, oCallBackScope) {
//Call the parent class.
xparser.BaseFeed.apply(this,
[xparser.feedType.atom, fpCallBack, oCallBackScope]
);
//Create the oNamespaces hash. We need this for the XPath evaluations.
var oNamespaces = {
atom : oRootNode.namespaceURI
};
//Create the hash of property names/element names
var oElements = {
title: "atom:title",
link: "atom:link/@href",
description: "atom:tagline",
copyright: "atom:copyright",
generator: "atom:generator",
modified: "atom:modified",
author: "atom:author"
};
//Parse it
this.parse(oRootNode, oElements, oNamespaces);
var cEntries = zXPath.selectNodes(oRootNode, "atom:entry", oNamespaces);
//Populate items[]
for (var i = 0, oEntry; oEntry = cEntries[i]; i++) {
this.items.push(new xparser.AtomItem(oEntry, oNamespaces));
}
//Call the callback in the specified scope. Pass this object as a parameter.
this.callBack.apply(this.callBackScope, [this]);
};
xparser.AtomFeed.prototype = new xparser.BaseFeed();
/**
* Represents a <atom:entry/> element.
* @constructor
* @extends xparser.BaseItem
* @scope public
*/
xparser.AtomItem = function (oEntryNode, oNamespaces) {
//Call the parent class.
xparser.BaseItem.apply(this, []);
//Create the hash of property names/element names
var oElements = {
title : "atom:title",
link : "atom:link/@href",
description : "atom:content",
date : "atom:issued",
author : "atom:author"
};
//Parse the data
this.parse(oEntryNode, oElements, oNamespaces);
};
xparser.AtomItem.prototype = new xparser.BaseItem();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment