Continuing by "beginner's Monad theme" ( where I am the beginner ) I had a go at consuming an OPML file from Monad.
Now, I'm a beginner on so many levels here. Firstly, I don't understand OPML so I went to try and find a spec (think I ended up at
www.opml.org). What I ended up realising was that there doesn't seem to really be a spec for OPML - it has some structure to it but when you hit the <outline> tag it seems you can just add any old attribute you like.
So, I went off the format that RSS Bandit generates when you export a list of RSS subscriptions as OPML. I wrote a new shell Cmdlet based on that and this is it (not rocket science + apologies for the recursion and the DOM - making life easier for myself).
using System;
using System.Management.Automation;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.XPath;
namespace Mtaulty.Msh.Commands
{
public class OpmlOutline
{
public OpmlOutline()
{
}
public OpmlOutline(string title, string desc, string xmlUrl,
string htmlUrl, string path)
{
this.title = title;
this.description = desc;
this.xmlUrl = xmlUrl;
this.htmlUrl = htmlUrl;
this.path = path;
}
private string xmlUrl;
public string XmlUrl
{
get { return xmlUrl; }
set { xmlUrl = value; }
}
private string htmlUrl;
public string HtmlUrl
{
get { return htmlUrl; }
set { htmlUrl = value; }
}
private string title;
public string Title
{
get { return title; }
set { title = value; }
}
private string description;
public string Description
{
get { return description; }
set { description = value; }
}
private string path;
public string Path
{
get { return path; }
set { path = value; }
}
}
[Cmdlet("get", "opmlfromfile")]
public class GetOpmlFromFileCommand : Cmdlet
{
private string opmlFile;
[Parameter
(
Position = 0,
Mandatory = true,
HelpMessage = "Name of the opml file to consume",
ValueFromPipeline = true
)
]
public string OpmlFile
{
get { return opmlFile; }
set { opmlFile = value; }
}
protected override void EndProcessing()
{
try
{
using (FileStream fs = new FileStream(opmlFile, FileMode.Open,
FileAccess.Read))
{
XmlDocument doc = new XmlDocument();
doc.Load(fs);
XPathNavigator navigator = doc.CreateNavigator();
RecurseOutlineNodes(string.Empty, navigator, "/opml/body/outline");
fs.Close();
}
}
catch (Exception ex)
{
ThrowTerminatingError(new ErrorRecord(ex, null, ErrorCategory.NotSpecified,
null));
}
}
private void RecurseOutlineNodes(string path,
XPathNavigator navigator, string xpath)
{
XPathNodeIterator iterator = navigator.Select(xpath);
while (iterator.MoveNext())
{
if (iterator.Current.HasChildren)
{
string subFolder = iterator.Current.GetAttribute("title",
string.Empty);
if (subFolder != null)
{
RecurseOutlineNodes(path + "/" + subFolder,
iterator.Current, "./outline");
}
}
else
{
OpmlOutline newOutline = GetOutlineItem(path, iterator.Current);
WriteObject(newOutline);
}
}
}
private static OpmlOutline GetOutlineItem(string path, XPathNavigator current)
{
OpmlOutline outline = null;
string title = current.GetAttribute("title",
string.Empty);
string description = current.GetAttribute("description",
string.Empty);
string xmlUrl = current.GetAttribute("xmlUrl",
string.Empty);
string htmlUrl = current.GetAttribute("htmlUrl",
string.Empty);
if (ValidString(title) && ValidString(xmlUrl))
{
outline = new OpmlOutline(title, description,
xmlUrl, htmlUrl, path);
}
return (outline);
}
private static bool ValidString(string s)
{
return ((s != null) && (s != string.Empty));
}
}
}
Once again, I added that to my shell and now I can do something like;
**********************
MSH Transcript Start
Start time: 20060113115425
Username : EUROPE\mtaulty
Machine : MTAULTYVISTA (Microsoft Windows NT 6.0.5270.0)
**********************
Transcript started, output file is c:\temp\trans.txt
MSH C:\Users\mtaulty> get-opmlfromfile w:\temp\feeds.opml
Once again - I'm not sure if this kind of command really makes sense in Monad in that it might make more sense to implement a provider that lets you navigate around the OPML file rather than a command like this.
Posted
Fri, Jan 13 2006 4:24 AM
by
mtaulty