[//lasso
/*----------------------------------------------------------------------------

[rss]
A basic type for working with RSS feeds.

Author: Jason Huck
Last Modified: Apr. 26, 2006
License: Public Domain

Description:
This is a basic type for working with RSS feeds. The ->parse method is taken 
from this TOTW article. Currently designed to produce feeds conforming to RSS 
0.91, but could easily be adapted to work with the newer spec. When you create 
a new object using this type, you can either provide it with the URL of a 
remote feed, or supply it with an array of arrays containing title, link, and 
description. (It's designed to be easily populated using [records_array].) The 
specific members are:

->title - The title of the feed.

->link - Link back to the feed you are creating.

->description - A description of the feed.

->language - The language of the feed. Defaults to US English.

->image - A map containing information about the image used to represent the 
feed, including title, url, link, width, and height.

->rows - The feed data; an array of arrays like that produced by 
[records_array].

->url - Any valid feed URL. If supplied when the object is created or as an 
argument to the ->parse method, will populate the type with the contents of 
the given feed.
->setImage - Used internally to populate the ->image member var.

->setRows - Used internally to populate the ->rows member var.

->getOutput - Returns the feed data in RSS format.

->parse - Populates the object with data from a given remote feed.

->serve - Serves the feed using [file_serve].


Sample Usage:
inline(
	$mydbconnection,
	-sql='A query that returns title, link, and description info in each row.'
);	
	var('thisFeed') = rss(
		-title='My RSS Feed',
		-link=('http://' + server_name + '/'),
		-description='A really interesting feed.',
		-rows=rows_array
	);

	$thisFeed->serve;
/inline;

Downloaded from tagSwap.net on Feb. 14, 2007.
Latest version available from <http://tagSwap.net/rss>.

----------------------------------------------------------------------------*/
		

define_type(
		'rss',
		-priority='replace',
		-description='A basic RSS type.'
	);
		local(
			'url' = string,
			'channel' = map(
				'title' = string,
				'link' = string,
				'description' = string,
				'language' = 'en-us'
			),
			'image' = map(
				'title' = string,
				'url' = string,
				'link' = string,
				'width' = string,
				'height' = string
			),
			'items' = array
		);

		
		define_tag(
			'onCreate',
			-optional='url',
			-type='string',
			-optional='title',
			-type='string',
			-optional='link',
			-type='string',
			-optional='description',
			-type='string',
			-optional='language',
			-type='string',
			-optional='image',
			-type='map',
			-optional='rows',
			-type='array'
		);
			if(local_defined('url'));
				self->parse(#url);
			else;
				local_defined('title') ? self->channel->find('title') = encode_xml(#title);
				local_defined('link') ? self->channel->find('link') = encode_xml(#link);
				local_defined('description') ? self->channel->find('description') = encode_xml(#description);			
				local_defined('language') ? self->channel->find('language') = encode_xml(#language);			
				local_defined('image') ? self->setImage(#image);
				local_defined('rows') ? self->setRows(#rows);
			/if;
		/define_tag;

		
		define_tag('setImage');
			local('image' = params->first);
		
			iterate(self->image->keys, local('i'));
				self->image->find(#i) = encode_xml(#image->find(#i));
			/iterate;
		/define_tag;

		
		define_tag('setRows');
			local('rows' = params->first);
		
			iterate(#rows, local('r'));
				local('row' = map);
				#row->insert('title' = encode_xml(#r->get(1)));
				#row->insert('link' = encode_xml(#r->get(2)));
				#row->insert('description' = encode_xml(#r->get(3)));
				self->items->insert(#row);
			/iterate;
		/define_tag;

		
		define_tag('getOutput');
			local('out' = '\
<?xml version="1.0"?>
<!DOCTYPE rss PUBLIC "-//Netscape Communications//DTD RSS 0.91//EN" "http://my.netscape.com/publish/formats/rss-0.91.dtd">
<rss version="0.91">
	<channel>
		<title>' + self->channel->find('title') + '</title>
		<link>' + self->channel->find('link') + '</link>
		<description>' + self->channel->find('description') + '</description>
		<language>' + self->channel->find('language') + '</language>
			');
			
			if(self->image->find('url') != '');
				#out += '
		<image>
			' + (self->image->find('title') != '' ? '<title>' + self->image->find('title') + '</title>') + '
			' + (self->image->find('url') != '' ? '<url>' + self->image->find('url') + '</url>') + '
			' + (self->image->find('link') != '' ? '<link>' + self->image->find('link') + '</link>') + '
			' + (self->image->find('width') != '' ? '<width>' + self->image->find('width') + '</width>') + '
			' + (self->image->find('height') != '' ? '<height>' + self->image->find('height') + '</height>') + '
		</image>
				';
			/if;
			
			iterate(self->items, local('i'));
				#out += '\
		<item>
			<title>' + #i->find('title') + '</title>
			<link>' + #i->find('link') + '</link>
			<description>' + #i->find('description') + '</description>
		</item>
				';
			/iterate;
			
			#out += '\
  </channel>
</rss>
			';
			
			return(@#out);
		/define_tag;


		define_tag('parse');
			fail_if(
				!params->first || !valid_url(params->first), 
				-1, 
				'A valid url must be supplied.'
			);
			
			local('url' = params->first);			
			self->url = #url;
			local('data') = xml(include_url(#url));
			
			iterate(#data->extractone('channel')->children, local('node'));
 				if(#node->name == 'item');
					local('item' = map);
					
					iterate(#node->children, local('subnode'));
						(#subnode->name != 'text') ? #item->insert(#subnode->name = #subnode->contents);
					/iterate;
					
					self->items->insert(#item);				
				else(#node->name == 'image');
					iterate(#node->children, local('subnode'));
						(#subnode->name != 'text') ? self->image->insert(#subnode->name = #subnode->contents);
					/iterate;		
				else(#node->name != 'text');
					self->channel->insert(#node->name = #node->contents);
 				/if;
 			/iterate;
		/define_tag;

		
		define_tag('serve');			
			file_serve(
				self->getOutput,
				-type='text/xml; charset=utf-8'
			);
		/define_tag;
	/define_type;
]
