While in the process of writing the code to create the new Jackson Marketing Group (JMG) blog it was decided that we needed to somehow incorporate our other social media outlets into the new blog to create a cohesive presence for the user. De.licio.us (the subject of this post) and Twitter were the first outlets we decided to include on the site. The basic premise was that each time a user lands on our main blog page to have it go out to de.licio.us, find the JMG bookmarks and feed them back to the site to be displayed to the user as a "blog post". This seemed easy enough until it was revealed that these had to be actual blog posts (pieces of content) that users could comment on and link to, as well as have the bookmarks show up in our "recent blog posts" and "most popular blog post" areas.
Since the layout for our blog is generated entirely in the code behind of the page that meant the bookmark would have to be added to the Content Management System (CMS) dynamically before being served up to the end user. This also means that the main blog page will have to check the current set of bookmarks against the current blog posts to make sure there are no duplicates. Then, if all was well, the new bookmarks would be added as a post to the blog, and then added to the blog taxonomy for URL aliasing purposes, before finally being displayed on the screen.
First things first, determining what kind of data can be retrieved from del.ico.us via API calls. After a few quick Google searches I came across a wealth of information in Scott Hanselman's blog post about Web 2.0 API's. This post got me pointed in the right direction and it was quickly determined that the information from del.icio.us is delivered as an XML document that looks strikingly similar to the following:
<?xml version="1.0" encoding="UTF-8" ?>
<posts user="JacksonMarketingGroup" tag="" >
<post href="http://webdesignledger.com/resources/14-most-useful-web-design-cheat-sheets"
hash="a0e39d1987b9e2606b498101d6056f55"
description="14 Most Useful Web Design Cheat Sheets | Web Design Ledger"
tag="Bookmarks"
time="2009-04-06T18:47:23Z"
extended="This is a TEST of the emergency broadcast system" />
</posts>
<!-- fe04.api.del.ac4.yahoo.net uncompressed/chunked Thu Apr 23 13:48:41 PDT 2009 -->
From here you basically have to create an HttpWebRequest with the proper network credentials. The HttpWebReponse returned is then put into a string via a StreamReader so that we can parse out only the information needed leaving us with a string in the format of "<posts><post/> … </posts>".
private void getDelicious()
{
GlobalFunctions myFunctions = new GlobalFunctions();
//first lets make sure delicious is up and that the feed is good otherwise do nuttin
try
{
// lets get the del.icio.us bookmarks first - so create the web request to gather the rss/xml and see what we get
HttpWebRequest request = WebRequest.Create("https://api.del.icio.us/v1/posts/recent") as HttpWebRequest;
// Add authentication to request (req'd by API) – obviously enter your username and password
request.Credentials = new NetworkCredential("YourUserName", "YourPassword");
String strXML = "";
// Get/use response
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
// Get the response stream
StreamReader reader = new StreamReader(response.GetResponseStream());
// application output to a string parsing it out for just posts (no header and footer)
strXML = reader.ReadToEnd();
reader.Close();
int a = strXML.IndexOf("<!--");
int b = strXML.IndexOf("<posts");
strXML = strXML.Substring(b, a - b);
}
Now that we have the string in the format needed it is loaded into an Xml document so that we can parse the individual nodes as needed. With this in mind character arrays are created that we will be used to modify the data returned so it will fit into the blog smart form used in the CMS. After that we create Ektron content and taxonomy API variables as well as taxonomy request that will be used for adding the bookmark to the site. Lastly, we retreive all the unique blog post names via a custom SQL call to the CMS and load them into the ArrayList named arrTemp.
//create an xml doc for easy node parsing
XmlDocument myXML = new XmlDocument();
myXML.LoadXml(strXML);
//now rearrange the info to put it into a usable format
XmlNodeList nodes = myXML.SelectNodes("/posts/post");
//for splitting the URL and dates from delicious respectively
char[] splitter = { '/' };
char[] splitty = { 'T' };
//now setup some Ektron api variables for use when adding to the CMS
Ektron.Cms.API.Content.Content content_api = new Ektron.Cms.API.Content.Content();
//taxonomy api variable used for the aliasing after the content is created
Ektron.Cms.API.Content.Taxonomy tax_api = new Taxonomy();
TaxonomyRequest tr = new TaxonomyRequest();
//create an array list to use in data comparison
ArrayList arrTemp = new ArrayList();
DataTable dtPosts = myFunctions.GetBlogPosts().Tables[0];
foreach (DataRow dr in dtPosts.Rows)
{ //fill the array list with unique blog post titles
if (!arrTemp.Contains(dr["postName"].ToString()))
{
arrTemp.Add(dr["postName"].ToString());
}
}
This step is the meat of the process - we take our node list created earlier and step through it node by node. Del.icio.us stores all its bookmark information as attributes of the "post" node, this allows us to use the ".GetNamedItem" method to grab each piece of information we need for our blog post. Using the named attribute "href" we can split it into an array using the "/" character. To be consistent with our URL aliasing naming convention we replace any empty spaces in the bookmark name with a "-".
//step through the node list and create a new string to be used in an xml doc later
foreach (XmlNode n in nodes)
{
string strContent = n.Attributes.GetNamedItem("href").InnerXml;
string[] arrContent = strContent.Split(splitter);
int x = arrContent.Length;
strContent = arrContent[x - 1].ToString().Replace(" ", "-");
We then check to see if the new name is included in our array of current blog post names. If it is not included in the array we can continue with our new post by doing a whole lot of string building to create each node of the CMS smart form.
// catch for already existing blog posts via content title
if (!arrTemp.Contains(strContent))
{ //if not in the array then add the post
string strTitle = "<blogTitle>" + n.Attributes.GetNamedItem("description").InnerXml + "</blogTitle>";
string strLink = "<blogLink>" + n.Attributes.GetNamedItem("href").InnerXml + "</blogLink>";
string strAuthor = "<blogAuthor>Jackson Marketing Group</blogAuthor>";
string strDate = n.Attributes.GetNamedItem("time").InnerXml;
string[] arrDate = strDate.Split(splitty);
strDate = "<blogDate>" + arrDate[0].ToString() + "</blogDate>";
string strBody = "<blogBody><p>" + n.Attributes.GetNamedItem("extended").InnerXml + "</p></blogBody>";
string strCat = "<blogSubject>" + n.Attributes.GetNamedItem("tag").InnerXml + "</blogSubject>";
string strPosts = "<root>" + strTitle + strLink + strAuthor + strDate + strBody + strCat + "</root>";
The end result of the above code is strPosts, which is then loaded into an XML document for adding to the CMS. The Ektron API method ".AddContent" adds the content (go figure) and returns the content ID number which is then fed directly to the ".UpdateContentMetaData" method. So in one line we add the content and update its metadata in one fell swoop. The last thing to do is add the content id to the blog taxonomy in the CMS so that the URL aliasing will be in place.
XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(strPosts);
//add the post to the blog folder '.addContent' returns the content id and thus feeds the '.UpdateContentMetaData' function
content_api.UpdateContentMetaData(content_api.AddContent(strContent, "", xmldoc.OuterXml, "", "", "1033", 175, "", "", "", 5, 0), 125, n.Attributes.GetNamedItem("description").InnerXml + " | blog | Jackson Marketing Group");
//turn around and grab the newly created blog post so the ID can be had
DataTable dt = myFunctions.GetContentByName(strContent).Tables[0];
string conID = "";
foreach (DataRow drow in dt.Rows)
{ //will be a 1 row dataset
conID = drow["conID"].ToString();
}
//add it to the taxonomy as well so it will show up when called by the blog post constructor
tr.TaxonomyId = 142;
tr.TaxonomyLanguage = 1033;
tr.TaxonomyIdList = conID;
tax_api.AddTaxonomyItem(tr);
}
}
}
catch (Exception eID) {}
}
And that's it, all done. There may be better ways to add the post to the CMS but this seemed the most direct and simple way to do it. Overall it seems to be efficient and doesn't seem to strain either the web or SQL servers. With that said, I would love to hear any feedback or suggestions for simplifying and/or improving the code. I am always on the lookout for clean concise code and as this is my first attempt at using the various social media APIs I would love to hear the experiences others have had.