Monday, November 08, 2010 at 12:02 AM.

	<<4/29/10; 5:16:20 PM by DW
		<<If the user gives us an HTML page, do the auto-discovery routine, cribbed from river2website.quicksub. 
	<<5/21/08; 8:40:30 PM by DW
		<<Rewrite to handle RSS 2.0, 1.0 and Atom feeds. Faster. Much simpler.
	<<3/19/06; 2:31:34 PM by DW
		<<Cribbed from newsRiverSuite.menuCommands.addRssAtts.
		<<Adds a node of type "rss" to the frontmost outline, after prompting the user for the URL of the feed.
on decode (s) {
	return (xml.rss.decodeString (s))};
if not defined ( {
	if defined (newsRiverData.prefs.lastFeedUrl) { = newsRiverData.prefs.lastFeedUrl}
	else { = "http://"}};
local (url =;
local (clipboardValue = clipboard.getValue (stringType));
if string.lower (clipboardValue) beginswith "http://" {
	url = clipboardValue};
op.attributes.getOne ("xmlUrl", @url);
if dialog.ask ("URL for feed:", @url) {
	local (xmltext = tcp.httpreadurl (url), xstruct, atts);
	try {
		xml.compile (xmltext, @xstruct)}
	else { //4/29/10 by DW
		local (linktable, flfoundfeed = false);
		xml.getHtmlLinks ("", @linktable, @xmltext);
		on getlink (type) {
			local (adrlink);
			for adrlink in @linktable {
				if adrlink^.rel == "alternate" {
					if adrlink^.type == type {
						url = nameof (adrlink^);
						flfoundfeed = true;
						return (true)}}};
			return (false)};
		if not getlink ("application/rss+xml") {
			if not getlink ("application/atom+xml") {
				return ("<h1>Can't subscribe because there are no suitable links in the HTML.</h1>")}};
		if not flfoundfeed {
			scriptError ("Can't add the feed because there is no feed link in the web page.")};
		xml.compile (tcp.httpreadurl (url), @xstruct)};
	<<scratchpad.xstruct = xstruct
	new (tabletype, @atts);
	atts.type = "rss";
	atts.xmlUrl = url;
	atts.title = "Untitled";
	atts.htmlUrl = "http://";
	bundle { //set atts.title, atts.htmlUrl
		try { //try RSS 2.0 first
			local (adrrss = xml.getaddress (@xstruct, "rss"));
			local (adrchannel = xml.getaddress (adrrss, "channel"));
			try {atts.title = decode (xml.getvalue (adrchannel, "title"))};
			try {atts.htmlUrl = decode (xml.getvalue (adrchannel, "link"))}}
		else { //then Atom, then RSS 1.0
			try { //see if it's Atom
				local (adrfeed = xml.getaddress (@xstruct, "feed"), adr);
				try {atts.title = decode (xml.getvalue (adrfeed, "title"))};
				for adr in adrfeed { //find atts.htmlUrl, which is buried in a link element (there could be many)
					if nameof (adr^) endswith "link" {
						try {
							local (adratts = @adr^.["/atts"]);
							if adratts^.rel == "alternate" {
								if string.lower (adratts^.type) == "text/html" {
									atts.htmlUrl = decode (adratts^.href)}}}}}}
			else { //see if it's RSS 1.0
				try {
					local (adrrdf = xml.getAddress (@xstruct, "RDF"));
					local (adrchannel = xml.getAddress (adrrdf, "channel"));
					try {atts.title = decode (xml.getValue (adrchannel, "title"))};
					try {atts.htmlUrl = decode (xml.getValue (adrchannel, "link"))}}}}};
	op.setDisplay (false);
	op.attributes.addgroup (@atts);
	op.setlinetext (atts.title);
	op.setDisplay (true);
	<<bundle //old code, 5/21/08 by DW
		<<local (adrdata = xml.aggregator.init ())
		<<local (adrservice = @adrdata^.services.[url], atts)
		<< = url
		<<local (servicestable)
		<<if not defined (adrservice^)
			<<new (tabletype, @servicestable)
			<<xml.aggregator.readService (url, @servicestable)
			<<adrservice = @servicestable.[url]
		<<if string.trimwhitespace (op.getlinetext ()) == ""
			<<op.setlinetext (adrservice^.compilation.channeltitle)
		<<new (tabletype, @atts)
		<<atts.title = adrservice^.compilation.channeltitle
		<<atts.htmlUrl = adrservice^.compilation.channellink

This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.