/* * 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 * can 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); } } }