/*
* RssCmdlet.cs
* Sample MSH Cmdlet that parses an RSS feed and makes it
* available as somewhat higher level data.. this could probably
* be done completely with XSLT although the intelligence that
* xcan understand different feed formats and make them all look
* the same might not be easy in XSLT.
*
* To use it:
*
* get/rssfeed http://slashdot.org/slashdot.rss
*
* get/rssitems http://slashdot.org/slashdot.rss
*/
using System;
using System.Diagnostics;
using System.Net;
using System.Management.Automation;
using System.Web;
using System.Xml;
using System.Collections;
using System.Xml.XPath;
namespace Samples
{
///
/// This class simply makes the item node look nicer.
///
class RssFeedItem
{
XmlNode thisNode;
public RssFeedItem(XmlNode fromNode)
{
thisNode = fromNode;
}
string GetNodeString(string name)
{
// I'm doing this (obviously not the best way to do it) because
// doing thisNode.SelectSingleNode("title") wasn't working with
// Slashdot's RSS, which includes an xmlns element.. not sure
// why that matters. This is a sample anyway but if you want
// to use this code somewhere else, then fix this :)
foreach (XmlNode n in thisNode.ChildNodes)
{
if (n.Name == name)
{
return n.InnerText;
}
}
return null;
}
public string InnerXml
{
get {
return thisNode.InnerXml;
}
}
public string Title
{
get {
return GetNodeString("title");
}
}
public string Guid
{
get {
return GetNodeString("guid");
}
}
public string Link
{
get {
return GetNodeString("link");
}
}
public string PubDate
{
get {
return GetNodeString("pubDate");
}
}
public string Description
{
get {
return GetNodeString("description");
}
}
}
///
/// Code for accessing an RSS feed. I've tried it with a few
/// formats and it seems fairly robust. The key to making it
/// robust seems to be to not assume that the channel and item
/// nodes are in any particular location. The goal of this code
/// is to support not just any particular verssion of RSS, but
/// rather to support as many sites and formats as possible.
///
public class RssParse
{
public XmlDocument RssDoc;
public XmlNode ChannelNode;
public ArrayList Items;
public ArrayList ItemNodes;
///
/// Constructor, takes an RSS link and initializes the
/// class based on what that link contains. Expect an
/// exception if something goes wrong.
///
/// RSS link
public RssParse(string url)
{
InitFromUrl(url);
}
///
/// Fetches the XML at the given URL and parses it, populating
/// RssDoc, ChannelNode, and Items.
///
/// RSS link
///
public bool InitFromUrl(string url)
{
// Create an HTTP request
HttpWebRequest webreq = (HttpWebRequest)WebRequest.Create(url);
webreq.Timeout = 30*1000;
// Get the response
WebResponse resp = webreq.GetResponse();
// Create the XML doc we're going to hold the RSS data in
RssDoc = new XmlDocument();
// Load it (read the RSS and parse it).
RssDoc.Load(resp.GetResponseStream());
// Create the array of item nodes - an item node
// exists for each - in the rss
Items = new ArrayList();
ItemNodes = new ArrayList();
// Scan two levels from the top looking for items
XmlNode rootNode = RssDoc.SelectSingleNode("/");
foreach (XmlNode node in rootNode.ChildNodes)
{
foreach (XmlNode chNode in node.ChildNodes)
{
if (chNode.Name == "channel")
{
// Found the Channel node
ChannelNode = chNode;
};
if (chNode.Name == "item")
{
// Found an item
ItemNodes.Add(chNode);
Items.Add(new RssFeedItem(chNode));
};
};
};
// For sites that have items as children of the Channel node
foreach (XmlNode chNode in ChannelNode.ChildNodes)
{
if (chNode.Name == "item")
{
// Found an item
Items.Add(new RssFeedItem(chNode));
};
};
// Cool.
return true;
}
// Site title accessor
public string Title
{
get
{
return NodeInnerText(ChannelNode, "title");
}
}
// Site link accessor
public string Link
{
get
{
return NodeInnerText(ChannelNode, "link");
}
}
// Site description accessor
public string Description
{
get
{
return NodeInnerText(ChannelNode, "description");
}
}
///
/// Helper function to return a string, or an empty string
// if the named node doesn't exist.
///
internal static string NodeInnerText(XmlNode node, string Name)
{
XmlNode childNode = node[Name];
if (childNode != null)
{
return (string)childNode.InnerText;
}
else
{
return "";
};
}
}
///
/// GetRssItems returns a list of items in an RSS feed
///
[CmdletDeclaration("get", "rssitems")]
public class GetRssItems : Cmdlet
{
[ParsingMandatoryParameter]
[ParsingPromptString("Enter the RSS feed URL")]
[ParsingParameterMappingAttribute(0)]
public string Url;
public override void StartProcessing()
{
RssParse rp = new RssParse(Url);
WriteObjects(rp.Items);
}
}
public class RssFeedInfo
{
public string Title;
public string Description;
public string Link;
}
///
/// GetRssFeed returns the information on the feed (title, description)
///
[CmdletDeclaration("get", "rssfeed")]
public class GetRssFeed : Cmdlet
{
[ParsingMandatoryParameter]
[ParsingPromptString("Enter the RSS feed URL")]
[ParsingParameterMappingAttribute(0)]
public string Url;
public override void StartProcessing()
{
RssParse rp = new RssParse(Url);
RssFeedInfo rfi = new RssFeedInfo();
rfi.Title = rp.Title;
rfi.Link = rp.Link;
rfi.Description = rp.Description;
WriteObjects(rfi);
}
}
}