I wanted this in the same post as the first part, but Live Writer seemed to think that it was already long enough and didn't want me pasting any more code it that post ... so here is the rest of how I created the new subscription list.
Step 5: Write console app to do the comparison of the scrubbed blog urls to my opml file ad create new opml file with matches
Now that I had a table of partial blog urls, I just needed to loop thorough the table and search for a match in the opml file. My first thought was to just run an Xslt transform, but I decided to just write a little utility app to do it (that way I could extend it easier if I needed to).
First thing I need was function to do the matching and keep track of the matches and the not found items (shown below).
private static List<OpmlEntry> _subscriptions;
private static List<string> _notFound;
private static void PopulateSubscriptions()
{
_subscriptions = new List<OpmlEntry>();
_notFound = new List<string>();
// loop through the blogUrls list checking the opml entries for a match
foreach(string blogUrl in _blogUrls)
{
OpmlEntry item = FindSubscription(blogUrl);
if (item != null)
{
if (_subscriptions.Contains(item))
{
// just log duplicates to console, don't add to subscription list
Console.WriteLine("Duplicate entry found: " + item.title);
}
else
{
_subscriptions.Add(item);
}
}
else
{
// keep track of the not found items
if (!_notFound.Contains(blogUrl))
{
_notFound.Add(blogUrl);
}
}
}
}
private static OpmlEntry FindSubscription(string blogUrl)
{
OpmlEntry entryMatch = null;
string url = "http://" + blogUrl;
// Loop through all subscriptions
foreach(OpmlEntry entry in _entries)
{
// check the xmlUrl attribute and the htmlUrl
if (entry.xmlUrl.StartsWith(url) | entry.htmlUrl.StartsWith(url))
{
entryMatch = entry;
break;
}
}
return entryMatch;
}
Once the PopulateSubscriptions() function is done, there are 2 lists that contain the opml entry information of matching links and a list containing the items that were not found.
There ar also a couple of other utility functions used to read in the opml file and the list of links that are necessary for the PopulateSubscriptions() function to have its needed objects to search. Here are those functions:
private static List<OpmlEntry> _entries;
private static void LoadOpml(string filepath)
{
XmlDocument doc = new XmlDocument();
doc.Load(filepath);
XmlNodeList entries = doc.SelectNodes(@"//outline");
_entries = new List<OpmlEntry>();
foreach (XmlNode node in entries)
{
_entries.Add(new OpmlEntry(node));
}
}
private static List<string> _blogUrls;
private static void LoadBlogUrls()
{
using (SqlConnection conn = new SqlConnection())
{
conn.ConnectionString = @"Server=...;Database=blog;Integrated Security=SSPI;";
conn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = conn;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "select distinct Link from Blogs$ order by Link";
_blogUrls = new List<string>();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
_blogUrls.Add(reader.GetString(0));
}
}
}
You might have also noticed an OpmlEntry object being used. I figured one of the ways (taking the least amount of code) to create an opml file would be just to use Xml Serialization ... so I did. Here is the object hierarcy I created in order to save the found opml matches out to a completely new ompl file:
[XmlRoot("opml")]
public class Opml
{
[XmlAttribute("version")]
public string version = "1.0";
[XmlElement("head")]
public Head head;
[XmlElement("body")]
public Body body;
public Opml()
{}
}
public class Head
{
public Head()
{ }
[XmlElement("title")]
public string title = "Feed Subscripions";
}
public class Body
{
public Body()
{ }
//public OpmlEntry[] outline;
[XmlElement("outline")]
public List<OpmlEntry> outline;
}
public class OpmlEntry
{
public OpmlEntry()
{}
public OpmlEntry(XmlNode node)
{
this.title = node.SelectSingleNode("@title").InnerText;
this.text = node.SelectSingleNode("@text").InnerText;
try
{
this.description = node.SelectSingleNode("@description").InnerText;
}
catch
{
this.description = string.Empty;
}
this.xmlUrl = node.SelectSingleNode("@xmlUrl").InnerText;
try
{
this.htmlUrl = node.SelectSingleNode("@htmlUrl").InnerText;
}
catch
{
this.htmlUrl = string.Empty;
}
this.type = node.SelectSingleNode("@type").InnerText;
}
[XmlAttribute("title")]
public string title;
[XmlAttribute("text")]
public string text;
[XmlAttribute("description")]
public string description;
[XmlAttribute("xmlUrl")]
public string xmlUrl;
[XmlAttribute("htmlUrl")]
public string htmlUrl;
[XmlAttribute("type")]
public string type;
}
Continued to next entry ...