Old blog post
This article was originally published on August 7, 2008.
One of my current projects at work has an RSS requirement. I’m redesigning the university’s policies website. My customers are concerned that other departments at Purdue have previously copied the content of a policy and placed it on a different site, which is problematic when policies are revised, superseded, or retired.
Implementing an RSS XML file for each policy will allow anyone else to embed a policy in their own site using any web technology while keeping the policies site owners in complete control of the content, no matter where it’s used.
Unfortunately, I had a pretty hard time finding a clear-cut solution for creating XML files dynamically with ColdFusion and SQL. It turns out that it’s not that difficult; it just took a little time to figure it out. One solution involved creating an actual XML file and writing it to the server. This would work for content that never gets updated, but this is a situation where the user needs to be able to implement the RSS in their site and not worry about it again.
The problem is, the XML specification is quite strict. You must be able to pass the file as XML in the header information, which will allow RSS readers (and embedding codes or scripts) to see it and parse it. This is accomplished quite easily through the cfcontent tag. Once you’ve identified the content as XML, you generate the file just like you would a regular HTML-formatted page.
Some quick Googling got me the information I needed on how to create an RSS feed to current specifications – you can check it out on Pete Freitag’s site here1).
This is pretty code-heavy, so hit the jump to read the rest.
The code for the feed itself is pretty easy. Since I’m dynamically generating the feed based on what policy is selected, I’m passing the ID of the policy (from the database) via a URL parameter. My link looks something like this: http://www.thesite.com/rss/?id=1
. All my code is in index.cfm
in a directory called rss
on my server.
<cfsilent> <!--- get the information from the database, based on ID ---> <cfinvoke component="TheComponent.cfc" method="theMethod" ID="#url.id#" returnvariable="Result"> </cfsilent> <!--- if the database returned a result, create the RSS data ---> <cfif Result.RecordCount EQ 1> <!--- set the file type as XML ---> <cfcontent type="text/xml"> <cfoutput> <!--- remove any blank lines from the generated source ---> <!--- this is MANDATORY for standards-compliant XML ---> <cfcontent reset="true"><?xml version="1.0" encoding="utf-8"?> <rss version="2.0"> <channel> <title>The Feed Title</title> <link>http://www.thesite.com/</link> <description>This is an XML feed of my content.</description> <languages>en-us</languages> <item> <title>#Result.Title#</title> <link>http://www.thesite.com/?id=#url.id#</link> <guid>http://www.thesite.com/?id=#url.id#</guid> <date>#Result.Date#</date> <description>#Result.Body#</description> </item> </channel> </rss> </cfoutput> <cfelse> <!--- if no data was returned, redirect the user back home ---> <cflocation url="../index.cfm" addtoken="no"> </cfif>
While you need the basic RSS elements in order for your feed to work with a reader (title, link, description, date, etc.), you can add your own tags for other data. In my case, I’m also going to use tags for the policy number, revision date, issuing office(s), etc.
I also discovered that the first line after the opening cfoutput
tag must have the and XML declaration. This annoys my OCD side in regards to how organized my markup is, but if you put the XML declaration on the next line, it adds a blank line at the top of the generated source, which is against the XML specification.
I needed to make sure my XML was properly generated, so I also went ahead and put together a test page that allowed me to output the contents of my feed. It turns out that ColdFusion (starting with at least MX 6, since that’s what we have on our server) has built-in functions for dealing with XML. It, too, is quite simple.
The basic process goes like this:
cfhttp
and the GET
method.
XMLParse
function that is native to ColdFusion.
The code looks something like this:
<cfsilent> <cfset TheUrl = "http://www.thesite.com/rss/?id=1"> <cfhttp url="#TheUrl#" method="GET" timeout="15"></cfhttp> <cfset TheFeed = trim(cfhttp.filecontent)> <cfset TheXML = XMLParse(TheFeed)> </cfsilent> <cfoutput> <html> <head> <!--- header stuff goes here, of course ---> </head> <body> <h1>#XmlContent.rss.channel.item[1].title.xmlText#</h1> <p> <a href="#XmlContent.rss.channel.item[1].link.xmlText#">Original article</a> </p> <p> #XmlContent.rss.channel.item[1].description.xmlText# </p> </body> </html> </cfoutput>
I’m only dealing with one item in my feed, since I’m using this for individual policies. If you were parsing a blog feed, for instance, you’d just need to add a for loop around the output section, with the to
value being the length of the array – ArrayLen(TheXML)
.
Now. As you can see, the structured array that the XmlParse
function in ColdFusion creates is fairly complex – there are many levels to it. I wrote a small cfscript
to create a function that I could pass different elements through to create the full XmlContent.rss.channel.item[1].element.xmlText
. This makes it much more efficient when coding a page that deals with a lot of calls to your XML array.
<cfscript> function getXML(element) { if (len(element) GT 0) { TheElement ="XMLContent.rss.channel.item[1]." & TheElement & ".xmlText"; } else { TheElement= ""; } TheElement= Evaluate(TheElement); return TheElement; } </cfscript>
Actually using the function is extremely easy. For instance, to get the title of the item in your feed:
<h1>#getXML("title")#</h1>
None of this code is particularly complex; it’s just that there doesn’t appear to be a whole lot of documentation readily available on how to work with RSS in ColdFusion. Once I found the solution, implementation was fast and surprisingly easy.