Atom Feed ActionScript 2 Class Alpha

I am putting together an ActionScript 2 class to represent and parse Atom feeds. I have put together an early alpha version of the class, but wanted to get some feedback on it before I continue work on it.

Alpha .22: (Feb.12 2004)

  • Refactored to make it easier to extend and add support for custom namespaces
  • User cannot add nodes
  • tag attributes are now placed in attributes object for element.
  • TODO: check case sensitivity in switch statements
  • TODO: check if namespace is added tags : atom:element
  • TODO: optimize parse functions
  • TODO: document api
  • TODO: wrap in MXP file for distribution

Alpha .20:

  • Should parse all elements and attributes described in the Atom .03 spec.
  • Does not currently support non-atom namespaces.
  • Utilizes the W3CDateTime class

Alpha .10:

  • Does not parse all Atom elements.
  • Only parses elements included in default Movable Type atom feed. Specifically, my Atom feed.
  • Cannot yet add nodes
  • Dates are not supported yet. Need to make a date class for the date types used by Atom
  • This is a super early version, and the code will probably drastically change.

Before I finish up adding support for all of Atom, I wanted to get some input on the class, and how I make the Atom dom avaliable. Please post any suggestions in the comments.

One quick comment (and my personal opinion), thus far, Atom has been a pure joy to work with. It is so nice have a structured format to work with. I love what RSS enables, but with all of the different versions, and permutations, it is a huge hassle to work with.

Anyways, here is the class (v .20):

[code]/* Atom.as Mike Chambers mesh@macromedia.com Class that represents an Atom XML document. You can find more information on Atom at: http://www.atomenabled.org Version Alpha .22 -user cannot yet add nodes -check case sensitivity in switch statements -check if namespace is added tags : atom:element -optimize parse functions */ import mx.events.EventDispatcher; import com.macromedia.date.W3CDateTime; class com.macromedia.data.Atom extends XML { private var dispatchEvent:Function; public var addEventListener:Function; public var removeEventListener:Function; private var feed:Object; private var entriesArray:Array; private var ignoreWhite:Boolean = true; public function Atom(xmlSource:String) { super(xmlSource); mx.events.EventDispatcher.initialize(this); } private function onLoad(success:Boolean):Void { if(!success) { //throw error trace("xml did not load"); return; } parseFeedTags(); dispatchEvent({type:"onAtomLoad", target:this}); } //need a way to reparse if user manually adds nodes private function parseFeedTags(Void):Void { feed = parseFeedElement(); //should this be in info, or in feed //feed.info = parseFeedElement(); var nodes:Array = firstChild.childNodes; var len:Number = nodes.length; var node:XMLNode; for(var i:Number = 0; i< len; i++) { node = nodes[i]; //do we need to worry about case sensitivity? switch(node.nodeName) { case "entry": { break; } case "title": { feed.title = parseFeedTitle(node); break; } case "author": { feed.author = parseFeedAuthor(node); break; } case "contributor": { feed.contributor = parseFeedContributor(node); break; } case "tagline": { feed.tagline = parseFeedTagline(node); break; } case "copyright": { feed.copyright = parseFeedCopyright(node); break; } case "generator": { feed.generator = parseFeedGenerator(node); break; } case "info": { feed.info = parseFeedInfo(node); break; } case "id": { feed.id = parseFeedId(node); break; } case "link": { feed.link = parseFeedLink(node); break; } case "modified": { feed.modified = parseFeedModified(node); break; } default: { parseFeedDefault(node); break; } } } } private function parseFeedTitle(node:XMLNode):Object { var obj:Object = new Object(); obj.value = node.firstChild.nodeValue; return obj; } private function parseFeedAuthor(node:XMLNode):Object { var obj:Object = parsePersonConstruct(node); return obj; } private function parseFeedContributor(node:XMLNode):Object { var obj:Object = parsePersonConstruct(node); return obj; } private function parseFeedTagline(node:XMLNode):Object { var obj:Object = new Object(); obj.value = node.firstChild.nodeValue; return obj; } private function parseFeedCopyright(node:XMLNode):Object { var obj:Object = new Object(); obj.value = node.firstChild.nodeValue; return; } private function parseFeedGenerator(node:XMLNode):Object { var obj:Object = new Object(); obj.value = node.firstChild.nodeValue; var genAtts:Object = node.attributes; obj.url = genAtts.url; obj.version = genAtts.version; return obj; } private function parseFeedInfo(node:XMLNode):Object { var obj:Object = new Object(); obj.value = node.firstChild.nodeValue; return obj; } private function parseFeedId(node:XMLNode):Object { var obj:Object = new Object(); obj.value = node.firstChild.nodeValue; return; } private function parseFeedLink(node:XMLNode):Object { var obj:Object = parseLinkConstruct(node); return obj; } private function parseFeedModified(node:XMLNode):Object { var obj:Object = new Object(); obj.value = W3CDateTime.parseString(node.firstChild.nodeValue); return obj; } private function parseFeedDefault(node:XMLNode):Object { return undefined; } private function parseLinkConstruct(node:XMLNode):Object { var feedAtts:Object = node.attributes; var link:Object = new Object(); link.attributes = new Object(); link.attributes.rel = feedAtts.rel; link.attributes.type = feedAtts.type; link.attributes.href = feedAtts.href; link.attributes.title = feedAtts.title; return link; } private function parseFeedElement(Void):Object { var feedInfo:Object = new Object(); feedInfo.attributes = new Object(); var feedAttributes:Object = firstChild.attributes; feedInfo.attributes.version = feedAttributes.version; feedInfo.attributes["xml:lang"] = feedAttributes["xml:lang"]; return feedInfo; } //need a way to reparse if user manually adds nodes private function parseEntries(Void):Void { entriesArray = new Array(); var nodes:Array = firstChild.childNodes; var len:Number = nodes.length; var node:XMLNode; var tempEntry:Object; for(var i:Number = 0; i< len; i++) { node = nodes[i]; if(node.nodeName == "entry") { tempEntry = parseEntry(node); entriesArray.push(tempEntry); } } } private function parseEntry(node:XMLNode):Object { if(node == undefined) { return; } var entryElements:Array = node.childNodes; var elementLen:Number = entryElements.length; var entry:Object = new Object(); var entryElement:XMLNode; for(var k:Number = 0; k < elementLen; k++) { entryElement = entryElements[k]; switch(entryElement.nodeName) { case "title": { entry.title = parseEntryTitle(entryElement); break; } case "link": { entry.link = parseEntryLink(entryElement); break; } case "modified": { entry.modified = parseEntryModified(entryElement); break; } case "issued": { entry.issued = parseEntryIssued(entryElement); break; } case "id": { entry.id = parseEntryId(entryElement); break; } case "created": { entry.created = parseEntryCreated(entryElement); break; } case "summary": { entry.summary = parseEntrySummary(entryElement); break; } case "author": { entry.author = parseEntryAuthor(entryElement); break; } case "contributor": { entry.contributor = parseEntryContributor(entryElement); break; } case "content": { entry.content = parseEntryContent(entryElement); break; } default: { //pass this to a parse default function break; } } } return entry; } private function parseEntryTitle(node:XMLNode):Object { var obj:Object = new Object(); obj.value = node.firstChild.nodeValue; return obj; } private function parseEntryLink(node:XMLNode):Object { var obj:Object = parseLinkConstruct(node); return obj; } private function parseEntryModified(node:XMLNode):Object { var obj:Object = new Object(); obj.value = W3CDateTime.parseString(node.firstChild.nodeValue); return obj; } private function parseEntryIssued(node:XMLNode):Object { var obj:Object = new Object(); obj.value = W3CDateTime.parseString(node.firstChild.nodeValue); return obj; } private function parseEntryId(node:XMLNode):Object { var obj:Object = new Object(); obj.value = node.firstChild.nodeValue; return obj; } private function parseEntryCreated(node:XMLNode):Object { var obj:Object = new Object(); obj.value = W3CDateTime.parseString(node.firstChild.nodeValue); return obj; } private function parseEntrySummary(node:XMLNode):Object { var obj:Object = new Object(); obj.value = node.firstChild.nodeValue; obj.type = node.attributes.type; var childNodes:Array = node.childNodes; var childNodesLen:Number = childNodes.length; var childNode:XMLNode; //TODO: test this with a summary tag //find out if there is a created node for(var z:Number = 0; z < childNodesLen; z++) { childNode = childNodes[z]; if(childNode.nodeName == "created") { obj.created = new Object(); obj.created.value = W3CDateTime.parseString(childNode.firstChild.nodeValue); break; } } return obj; } private function parseEntryAuthor(node:XMLNode):Object { var obj:Object = parsePersonConstruct(node); return obj; } private function parseEntryContributor(node:XMLNode):Object { var obj:Object = parsePersonConstruct(node); return obj; } private function parseEntryContent(node:XMLNode):Object { var obj:Object = new Object(); obj.attributes = new Object(); var atts:Object = node.attributes; obj.attributes.mode = atts.mode; obj.attributes.type = atts.type; obj.value = node.firstChild.nodeValue; return obj; } private function parsePersonConstruct(node:XMLNode):Object { var author:Object = new Object(); var children:Array = node.childNodes; var len:Number = children.length; var tempNode:Object; var tempName:String; for(var i:Number = 0; i < len; i++) { tempNode = children[i]; tempName = tempNode.nodeName; switch(tempName) { case "name": { //fall through } case "url": { //fall through } case "email": { author[tempName] = new Object(); author[tempName].value = tempNode.firstChild.nodeValue; break; } } } return author; } /**************** Public API / Getters *******************/ //TODO: make sure we have getters for all of the top level feed elements public function getFeedTitle(Void):String { return feed.title.value; } public function getFeedModified(Void):Date { return feed.modified.value; } public function getFeedLink(Void):Object { return feed.link; } public function getFeedId(Void):String { return feed.id.value; } public function getFeedGenerator(Void):String { return feed.generator.value; } public function getFeedCopyright(Void):String { return feed.copyright.value; } public function getFeedTagline(Void):String { return feed.tagline.value; } //TODO : should this be a property? public function getFeed(Void):Object { return feed; } public function get entries ():Array { if(entriesArray == undefined) { parseEntries(); } return entriesArray; } }[/code]

Comments

  1. Robby
    February 6, 2004 3:32 AM
    Just curious Mike, why the use of actual getxxx() rather than using properties? Preference or reason?
  2. mike chambers
    February 6, 2004 5:06 AM
    To be honest, this is something that I have still not settled on. I may still change it. The main reason that most are getters, is that what I am used to doing. entries is a property, because that felt like a dataProvider. Anyways, it might change, I am still trying to figure out when to use which. Any suggestions? mike chambers mesh@macromedia.com
  3. Robby
    February 6, 2004 6:22 AM
    I dunno, I'm not an actionscript junkie (but heading there). I use properties for any get/set scenario unless the class HAS to follow an interface and the get itself is part of the 'contract'. It's a rare occurance so something not to hold on to. In ColdFusion there isn't a concept of properties per se (not in this context) so I use getxxx() out of habit, I was really just feeling out to see if it was performance/preference based or habit. Properties are pretty sultry, but getxxx() is pretty direct on what is being done. In the end it just might be preference.
  4. February 19, 2004 1:07 PM
    One could potentially use this with blogger couldn't they! I've been searching for this for a while... thanks for the idea.
  5. Jay
    February 16, 2005 3:36 PM
    This might be a dumb question: where do you put this? I have saved it as Atom.as. I have worked created a doc using tree comp named treeXML I thought it needed to go in the classes/mx/data directory but my Flash file isn't seeing this.
  6. pim
    May 23, 2005 1:54 PM
    Do you know how one could use it with Flex? how would you initialize it on a result event from an httpService? Would I have to modify the constructor? Regards, pim
  7. ovidiu
    October 16, 2005 5:45 PM
    How do you connect? Any scripts on WSSE
  8. January 14, 2007 10:00 PM
    Basically Im trying to do something with flash that I think you have either accomplished, or are trying to do. I want to place in its own layer, any kind of component that will allow me to pull in a xml file (atom.xml) which is a blog feed. I want to pull it into flash instead of having to put it in an html page. If you want to see the idea that I want to use, just check out this link ( http://www.he-ekklesia.org) I want to do the exact same thing, I want the blog to be right on top of the first page. The only problem is, I can not figure out how to get flash to import the atom.xml feed into a component. Thanks for your time- Jasen Burkett Yhwh Design

Post a comment




Remember Me?

(you may use HTML and Quickcode tags for style)