RSSReader–a simple example of Syndication Library

Newspaper-Feed-add-256x256 Problem Summary: Once I want to display a series article of Flex performance from InsideRIA(www.insideria.com) in my blog. I recognized that the amount of the articles is increasing. I should keep the links dynamically. However, I am not the provider of the blog system, so I cannot modify the codes to meet my requirement. Luckily, I can embed SWF in my blog articles. So, I just need to develop a simple RSS reader in SWF format.

Solution Summary: I do not want to parse the RSS myself. It’s a hard work to deal with. I tried to find some open source library of RSS parsing in programmed by action script 3.0. Googled for many, I got the syndication library(http://code.google.com/p/as3syndicationlib/) at last.

Use the syndication library to parse Atom and all versions of RSS easily. This library hides the differences between the formats so you can parse any type of feed without having to know what kind of feed it is.

The detailed information will be found in the project home(http://code.google.com/p/as3syndicationlib/). Then, I started to develop my own RSS reader

Search-256x256 Demo | DownloadDownload Full Project

RSSReader

Codes:

<?xml version="1.0" encoding="utf-8"?>
<rssreader>
	<proxy path="http://ntt.cc/ext/proxy.php"/>
</rssreader>

Following is URLLoader.php:

<?php
$url = $_GET['FeedURL'];
$html = file_get_contents($url);
print($html);
?>

Following is RSSReaderConfig.as:

package
{
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;

	import mx.managers.ISystemManager;

	[Mixin]
	public class RSSReaderConfig
	{
		private static var _proxyPath:String="http://ntt.cc/ext/proxy.php";

		public static function get proxyPath():String
		{
			return _proxyPath;
		}

		public static var loaded:Boolean = false;
		public static function init(systemManager:ISystemManager):void
		{
			var request:URLRequest = new URLRequest("rssreader-config");
			var loader:URLLoader = new URLLoader();
			loader.addEventListener(Event.COMPLETE,complete);
			loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR,onSecurityError);
			loader.addEventListener(IOErrorEvent.IO_ERROR,onIOError);

			loader.load(request);
		}

		private static function complete(event:Event):void
		{
			try
			{
				var config:XML = XML(event.currentTarget.data);
				_proxyPath = config.proxy.@path;
				loaded = true;
			}
			catch(err:Error)
			{
				loaded = false;
			}
		}

		private static function onIOError(event:Event):void
		{
			trace(event);
		} 

		private static function onSecurityError(event:Event):void
		{
			trace(event);
		}
	}
}

Following is RSSReader.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
	xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="absolute"
	creationComplete="initApp();">
	<mx:Style>
		global
		{
			font-size:12;
		}
		ToolTip
		{
			font-size:12;
		}
	</mx:Style>
	<mx:Script>
		<![CDATA[
			import mx.core.UIComponent;
			import mx.core.FlexSprite;
			import mx.controls.Alert;
			import mx.core.ByteArrayAsset;
			import mx.managers.CursorManager;
			import mx.utils.StringUtil;
			import mx.utils.URLUtil;
			import mx.utils.XMLUtil;

			import flash.net.navigateToURL;

			import com.adobe.xml.syndication.generic.Excerpt;
			import com.adobe.xml.syndication.generic.IFeed;
			import com.adobe.xml.syndication.generic.FeedFactory;

			[Bindable]
			private var feedURL:String = "http://blogs.oreilly.com/cgi-bin/mt/mt-search.cgi?search=Flex%20RIA%20Performance%20Considerations&Template=feed&IncludeBlogs=34";

			[Bindable]
			private var feeds:IFeed;

			private function initApp():void
			{
				Security.allowDomain("*");
				var uic:UIComponent = new UIComponent();
				trace(uic.eventListeners);
				if(parameters.FeedURL!=null)
				{
					feedURL = parameters.FeedURL;
				}

				fetchEntries();
			}

			private function fetchEntries():void
			{
				// we should check the url here
				if(feedUrl.text == "")
				{
					return;
				}
				else
				{
					feedURL = feedUrl.text;
				}

				var uri:String = encodeURIComponent(feedURL);

				uri = RSSReaderConfig.proxyPath +"?FeedURL="+uri;

				var request:URLRequest = new URLRequest(uri);
				var loader:URLLoader = new URLLoader();
				loader.addEventListener(Event.COMPLETE,onLoad);
				loader.addEventListener(IOErrorEvent.IO_ERROR,onIOError);
				loader.dataFormat = URLLoaderDataFormat.BINARY;
				loader.load(request);

				CursorManager.setBusyCursor();
			}

			private function onLoad(event:Event):void
			{
				var result:ByteArray = event.currentTarget.data;
				try{
					feeds = FeedFactory.getFeedByString(result.readMultiByte(result.length,"gb2312"));
				}
				catch(error:Error)
				{
					Alert.show("Encounter an unknown error, please confirm your rss source url","Error");
					CursorManager.removeBusyCursor();
					return;
				}
				if(!feeds)
				{
					Alert.show("Cannot get feeds from the specified url","Error");
					CursorManager.removeBusyCursor();
					return ;
				}
				entries.dataProvider = feeds.items;
				CursorManager.removeBusyCursor();
			}

			private function onIOError(event:IOErrorEvent):void
			{
				trace(event);
			}
		]]>
	</mx:Script>
	<mx:Panel title="rss reader" layout="vertical" width="100%" height="100%">
		<mx:HBox width="100%">
			<mx:Label text="URL"/>
			<mx:TextInput id="feedUrl" text="{feedURL}" width="50%"/>
			<mx:Button label="Fetch" click="fetchEntries()"/>
		</mx:HBox>
		<mx:HRule width="100%" height="2" visible="{feeds.metadata.authors!=null}"/>
		<mx:HBox width="100%" verticalAlign="middle">
			<mx:Repeater id="metadataAuthors" dataProvider="{feeds.metadata.authors}">
				<mx:LinkButton>
					<mx:click>
						<![CDATA[
							var dataItem:Object = event.currentTarget.repeater.dataProvider[event.currentTarget.repeaterIndex];
							if(dataItem.url)
							{
								try
								{
									navigateToURL( new URLRequest(dataItem.link),'_blank');
								}
								catch(err:Error)
								{
									System.setClipboard(dataItem.link);
									Alert.show("Security box error. the link url has been copied to your clipboard. paste the url into the browser's location bar, then go to the address");
								}
							}
						]]>
					</mx:click>
					<mx:label>
						{metadataAuthors.currentItem.name!=null?metadataAuthors.currentItem.name:metadataAuthors.currentItem.email}
					</mx:label>
				</mx:LinkButton>
			</mx:Repeater>
			<mx:Image
				toolTip="{feeds.metadata.image.title}"
				visible="{feeds.metadata.image!=null}"
				source="{feeds.metadata.image.url}"
				buttonMode="true"
				mouseChildren="false">
				<mx:click>
					<![CDATA[
						if(feeds.metadata.image.link)
						{
							try
							{
								navigateToURL( new URLRequest(feeds.metadata.image.link),'_blank');
							}
							catch(err:Error)
							{
								System.setClipboard(feeds.metadata.image.link);
								Alert.show("Security box error. the link url has been copied to your clipboard. paste the url into the browser's location bar, then go to the address");
							}
						}
					]]>
				</mx:click>
			</mx:Image>
		</mx:HBox>
		<mx:Label text="Entries"/>
		<mx:HRule width="100%" height="1"/>
		<mx:VBox width="100%" height="100%">
			<mx:Repeater id="entries" width="100%" height="100%">
					<mx:LinkButton
						label="{entries.currentItem.title}"
						fontSize="14" fontWeight="bold">
						<mx:click>
							<![CDATA[
								var dataItem:Object = event.currentTarget.repeater.dataProvider[event.currentTarget.repeaterIndex];
								if(dataItem.link)
								{
									try
									{
										navigateToURL( new URLRequest(dataItem.link),'_blank');
									}
									catch(err:Error)
									{
										System.setClipboard(dataItem.link);
										Alert.show("Security box error. the link url has been copied to your clipboard. paste the url into the browser's location bar, then go to the address");
									}
								}
							]]>
						</mx:click>
					</mx:LinkButton>
					<mx:Repeater id="authors"  dataProvider="{entries.currentItem.authors}">
						<mx:LinkButton
							fontWeight="normal"
							fontSize="12"
							label="{authors.currentItem.name!=null?authors.currentItem.name:authors.currentItem.email}">
							<mx:click>
								<![CDATA[
									var dataItem:Object = event.currentTarget.repeater.dataProvider[event.currentTarget.repeaterIndex];
									if(dataItem.url)
									{
										try
										{
											navigateToURL( new URLRequest(dataItem.url),'_blank');
										}
										catch(err:Error)
										{
											System.setClipboard(dataItem.url);
											Alert.show("Security box error. the link url has been copied to your clipboard. paste the url into the browser's location bar, then go to the address");
										}
									}
								]]>
							</mx:click>
						</mx:LinkButton>
					</mx:Repeater>
			</mx:Repeater>
		</mx:VBox>
	</mx:Panel>
</mx:Application>

Description: During the development process of my simple RSS reader, I meet a problem raised by flash player security sand box. For example, the domain of my blog is www.mydomain.com, the domain of another blog is www.otherdomain.com. If the SWF embed in my blog wants to access the data from www.otherdomain.com, the www.otherdomain.com must grant the related permission to www.mydomain.com. However, I cannot control the permission of www.otherdomain.com. So I need a server to store my SWF file。Suppose the domain of the server is www.server.com.The SWF will load the data from www.otherdomain.com by a HTTP request from www.server.com. For the SWF and the data request are from the same domain, there will be no security sand box issue.

The “proxy” defined in the file rssreader-config is the server referred to above. “Path” is the server-side service with which the SWF stored in the server is able to access data from any web sites without security sandbox issue.

<proxy path=”http://ntt.cc/ext/proxy.php”/>

The class RSSReaderConfig is used to load RSSReader configuration settings into the SWF, such as RSSReaderConfig.proxyPath will return the attribute “path” of the “proxy” tag defined in file rssreader-config.

Pay attention to the class metadata tag “mixin”. With this tag, the init function will be executed automatically to initialize class RSSReaderConfig.

The usage of Syndication library is quite easy. FeedFactory provides us a general way to parse a feed, in ATOM format or RSS, because of all the class implemented the interface IFeed.

FeedFactory.getFeedByString(result.readMultiByte(result.length,“gb2312″));

As the codes above, getFeedByString returns an instance implemented IFeed interface. I am a Chinese, “gb2312” is used to make sure the content loaded correct.

At last, the detailed definition of IFeed and other classes or interfaces lists in the distributed documentation of Syndication library, which is contained in a compressed package you will get from the project home(http://code.google.com/p/as3syndicationlib/).

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • DZone
  • Reddit
  • Technorati
  • StumbleUpon
  • Twitter
RSS Enjoy this Post? Subscribe to Ntt.cc

RSS Feed   RSS Feed     Email Feed  Email Feed Follow us Follow us
You can leave a response, or trackback from your own site.

4 Responses to “RSSReader–a simple example of Syndication Library”

  1. RSSReader–a simple example of Syndication Library…

    原文来自ntt.ccProblem Summary: Once I want to display a series
    article of Flex performance from InsideRIA(www.insideria.com) in my
    blog. I recognized that the amount of the articles is increasing. I
    should keep the links dynamically….

  2. [...] 在RSSReader–a simple example of Syndication Library的编写过程中,跨域问题(cross-domain)曾经让郭大侠(hydra1983)头痛不已–因为当时没能找到可以直接用来当作Proxy的Server。Flex cookbook上看到了一篇关于Flex中如何利用LiveCycle Data Services ES或者BlazeDS解决跨域问题(cross-domain),对于正在使用LiveCycle Data Services ES或者BlazeDS的项目来说,相当的有用,当然如果你不想仅仅为了解决这个问题而额外的使用他们的话,可以参考开头的RSSReader的做法,自己写一个Proxy。下面是Flex cookbook上文章的地址: [...]

  3. [...] At last, the detailed definition of IFeed and other classes or interfaces lists in the distributed documentation of Syndication library, which is contained in a compressed package you will get from the project home(http://code.google.com/p/as3syndicationlib/). Permalink:http://ntt.cc/2008/08/04/rssreader-a-simple-example-of-syndication-library.html [...]

  4. [...] RSSReader–a simple example of Syndication Library [...]

Leave a Reply