Update: 22 November, 2011
It looks like Weather.com has started charging for accessing this service, so if you are looking for something for free, please look elsewhere. Otherwise, check here: http://www.wunderground.com/weather/api/
Weather.com has suddenly changed their web service overnight. Therefore, I had to make the necessary changes to get this to work.
The biggest changes are:

  1. 5 day forecasts now instead of 10
  2. No more GIF images, just PNG
  3. Different image sizes

XML Data Feeds are very popular and useful. One of them, the weather.com XML Data Feed, allows third-party applications to access a subset of the data available on the weather.com website via an on-request XML feed. The Weather Channel Interactive, Inc. (TWCi) provides this data free of charge to developers who wish to incorporate weather information into a single application in exchange for links back to weather.com.

This article describes how to access and use the XML feed in order to add a weather control on your website. I will try to do this by focusing on the following:

  • how to access the XML feeds from weather.com
  • how to call the custom tag (mandatory/optional tag parameters)
  • what is available to us once we have properly created the tag
  • how to customize the look and feel to your liking

What this article is not going to explain is how to build a custom tag. The source code is freely available to you (download link at the bottom of the article) to do so as you please, so feel free to go though it and see how it works.

Signing up at weather.com

Even though this service is free to use, you will need to sign up and get a subscriber account to use it. There are rules to adhere to for using this service, like how often you should cache your feeds, displaying their logo and a link back to them on your site, etc. You should take the time and read them after you sign up to avoid lockout issues.

The sign up process is fairly quick and easy. At the end of the registration process you will receive an e-mail message containing your Partner ID, unique License Key, and download instructions for the Software Developers Kit (SDK). The Partner ID and License Key must be included as query parameters for all XML weather requests.

The SDK contains:

  1. 2 PDF files that outline the rules of use of the service and instructions on how to call it.
  2. All the images that you could need to add to your control for the current weather conditions, in 3 sizes: 32×32, 64×64 and 128×128 pixels.
  3. 2 weather.com logos: 32×32 and 64×64 pixels.

Getting your location ID

No matter which location you are at in the world, weather.com should have it in their database. They have their own way of storing location codes though (or IDs), so they make available a separate feed upon which we can send requests to find out the ID of our location. For example, let’s say that you are looking for Athens:
http://xoap.weather.com/search/search?where=athens
The result would be this XML file:

For illustration purposes, let’s suppose that what you were after is Athens, Greece, with location ID GRXX0004.

To make this task easier for you, I have included in the download package a file called “location_search.cfm“. This is a form that lets you enter a query in a text field and takes care of posting to the feed above for location IDs, presenting the results in a nicer way. Running this file against the “athens” search would produce the following:

Same thing, just more friendly. :)

Please note that the code for this form does a “cfhttp” request. If you are behind a firewall, you will need to edit the code to add at least the “proxyServer” and “proxyPort” attributes to the call to make it work.

Requesting the XML Data Feed

The URL parameters for the XML feed are:

Query Parameter Usage
cc Current Conditions

OPTIONAL

VALUE IGNORED

dayf Multi-day forecast information

OPTIONAL

VALUE = [ 1..10 ]

link Links for weather.com pages

OPTIONAL

VALUE = xoap

par Partner ID assigned to you

REQUIRED

VALUE = {partner id}

key The license key assigned to you

REQUIRED

VALUE = {license key}

unit Set of units. Standard or Metric

OPTIONAL

VALUES = [ s | m ]

DEFAULT = s

For example:

http://xoap.weather.com/weather/local/GRXX0004?cc=*&par=[partner_id]&key=[license_key]&unit=s&dayf=10

This would return the current conditions in standard (American) units for Athens, Greece, as well as forecast infrormation for the next 10 days. Here’s a snapshot of the returned XML file (some nodes are contracted):

Using the custom tag

All the code you will need is inside a single file, the “weather.cfm” in the downloaded zip file, which acts as the custom tag. Follow the same procedure as you normally do when you store custom tags on your server: place it either in a special mapped folder, or in the same folder as the file that you are calling it from.

<cf_weather> attributes
Name Default Mandatory Description
locationCode Yes The location ID of the place where the control is for.
partnerID Yes Your Partner ID given to you by weather.com after registering.
licenseKey Yes Your license key given to you by weather.com after registering.
imageLocation /weather/images/ No The virtual path to the weather.com images and logos.

Make sure you include the last “/”.

imageSize medium No Acceptable values:

  1. small
  2. medium
  3. large

small = 32×32 pixels

medium = 64×64 pixels

large = 128×128 pixels

imageType png No Acceptable values:

  1. png
  2. gif

The weather.com SDK provides all the images in PNG format. These PNGs have a transparent background, which does not display in IE 6.x and below. To work around this, I added a GIF duplicate of each PNG file so that you can choose which one you want to have displayed. Also, in the downloadable examples you will notice that I added to the pages a Javascript “hack” which displays PNGs fine even in IE. Thank you Bob Osola!

daysForecast 10 No Acceptable values:

  • 1-10
xmlFolder #ExpandPath(‘.’)# No The folder where the cached XML data feed file will be saved to. It defaults to the same folder as the one that you are calling it from, but you can place it anywhere on the server. The path needs to be absolute, i.e. “C:\wwwroot\website”.
xmlFile weather No The name that will be given to the XML file.
unit s No Acceptable values:

  1. s
  2. m

s = Standard, or American

m = Metric, or everybody else!

cacheSeconds 3600 No Acceptable values:

  • >= 0

The number in seconds that the local XML file will be cached. Once this expires, the tag will call the XML data feed again the next time it is called. There is no need to set it any less than one hour, the feeds to not get refreshed that often anyway.

proxyServer No In case you are behind a firewall you might need to add proxy settings to do a HTTP GET request for the feed.
proxyPort No In case you are behind a firewall you might need to add proxy settings to do a HTTP GET request for the feed.
proxyUser No In case you are behind a firewall you might need to add proxy settings to do a HTTP GET request for the feed.
proxyPassword No In case you are behind a firewall you might need to add proxy settings to do a HTTP GET request for the feed.

Armed with the knowledge of all available attributes of this tag, the simplest way of calling it:

<cf_weather locationCode="GRXX0004" partnerID="xxxxxxxxxx" licenseKey="xxxxxxxxxxxxxxxx">
 ...
</cf_weather>

Between the opening and closing of the tag, we have access to an all-powerful structure called “sWeather“. This structure has all the information from the XML feed stored in it. Populating a local variable this way from the custom tag proves to be very powerful in this case. The reason is that we can now write our own HTML/CF code inside the tags to create our custom look and feel of the weather control. Go ahead and try it: do a <cfdump> of this structure within the tags and see what you get:

<cf_weather locationCode="GRXX0004" partnerID="xxxxxxxxxx" licenseKey="xxxxxxxxxxxxxxxx">
   <cfdump var="#sWeather#">
</cf_weather>


Taking a look at the resulting <cfdump>, we see 4 nested structures:

  1. sCurrentConditions
    Used mostly for outputting current conditions
  2. sForecast
    Nested information for each of the days in the forecast
  3. sParams
    These are the custom and default attributes of the tag
  4. sProperties
    General display properties for the custom tag, e.g. units of measurement

Current Conditions example

OK! Now let’s see an actual example of how to use the tag to produce the current conditions of Athens, Greece. Create a new CFM file and add the following code to it:

<style type="text/css">
.currentWeather {
	background-color:#EFF5D7;
	color:#3A5029;
	font-family:Tahoma;
	font-size:70%;
	border:1px solid #CAD3A4;
	width:250px;
}
.currentWeather table {
	font-size:100%;
	color:#3A5029;
}
.currentWeather .location {
	background-color:#BED273;
	padding:5px 10px;
	font-weight:bold;
	text-align:center;
}
.currentWeather .icon {
	text-align:center;
}
.currentWeather .temperature {
	font-size:280%;
	padding-left:25px;
	text-align:center;
}
.currentWeather .description {
	font-weight:bold;
}
.currentWeather .feelslike {
	font-weight:bold;
	padding-left:25px;
}
.currentWeather .lastupdate {
	padding:10px;
}
</style>

<script language="javascript">
// Correctly handle PNG transparency in Win IE 5.5 or higher.
// http://homepage.ntlworld.com/bobosola/
function correctPNG() {
	for (var i=0; i<document.images.length; i++) {
		var img = document.images[i]
		var imgName = img.src.toUpperCase()
		if (imgName.substring(imgName.length-3, imgName.length) == "PNG") {
			var imgID = (img.id) ? "id='" + img.id + "' " : "";
			var imgClass = (img.className) ? "class='" + img.className + "' " : "";
			var imgTitle = (img.title) ? "title='" + img.title + "' " : "title='" + img.alt + "' ";
			var imgStyle = "display:inline-block;" + img.style.cssText;
			if (img.align == "left") imgStyle = "float:left;" + imgStyle;
			if (img.align == "right") imgStyle = "float:right;" + imgStyle;
			if (img.parentElement.href) imgStyle = "cursor:hand;" + imgStyle;
			var strNewHTML = "<span " + imgID + imgClass + imgTitle
				+ " style=\"" + "width:" + img.width + "px; height:" + img.height + "px;" + imgStyle + ";"
				+ "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader"
				+ "(src=\'" + img.src + "\', sizingMethod='scale');\"></span>";
			img.outerHTML = strNewHTML;
			i = i-1;
		}
	}
}
window.attachEvent("onload", correctPNG);
</script>

<cf_weather locationCode="GRXX0004" partnerID="xxxxxxxxxx" licenseKey="xxxxxxxxxxxxxxxx">
	<cfoutput>
	<table border="0" cellpadding="0" cellspacing="0" class="currentWeather">
		<tr>
			<td class="location">#sWeather.sLocation.city#</td>
		</tr>
		<tr>
			<td align="center">
				<br />
				<table border="0" cellpadding="0" cellspacing="0">
					<tr>
						<td class="icon"><img src="#sWeather.sParams.imageLocation & sWeather.sParams.imageSize & "x" & sWeather.sParams.imageSize & "/" & sWeather.sCurrentConditions.icon & "." & sWeather.sParams.imageType#" border="0" alt="#sWeather.sCurrentConditions.description#"></td>
						<td class="temperature">#sWeather.sCurrentConditions.temperature#&##176;#sWeather.sProperties.temperature#</td>
					</tr>
					<tr>
						<td class="description">#sWeather.sCurrentConditions.description#</td>
						<td class="feelslike">Feels like #sWeather.sCurrentConditions.feelslike#&##176;#sWeather.sProperties.temperature#</td>
					</tr>
				</table>
			</td>
		</tr>
		<tr>
			<td align="center">
				<br />
				<br />
				<table border="0" cellpadding="1" cellspacing="0">
					<tr>
						<td align="right" valign="top">UV index:</td>
						<td valign="top">#sWeather.sCurrentConditions.uvindex# #sWeather.sCurrentConditions.uvDescription#</td>
					</tr>
					<tr>
						<td align="right" valign="top">Dew Point:</td>
						<td valign="top">#sWeather.sCurrentConditions.dewpoint#&##176;#sWeather.sProperties.temperature#</td>
					</tr>
					<tr>
						<td align="right" valign="top">Humidity:</td>
						<td valign="top">#sWeather.sCurrentConditions.humidity#%</td>
					</tr>
					<tr>
						<td align="right" valign="top">Visibility:</td>
						<td valign="top">#sWeather.sCurrentConditions.visibility# #sWeather.sProperties.distance#</td>
					</tr>
					<tr>
						<td align="right" valign="top">Pressure:</td>
						<td valign="top">#sWeather.sCurrentConditions.barIndex# #sWeather.sProperties.pressure# (#sWeather.sCurrentConditions.barDescription#)</td>
					</tr>
					<tr>
						<td align="right" valign="top">Wind:</td>
						<td valign="top">From the #sWeather.sCurrentConditions.winddirection# at #sWeather.sCurrentConditions.windspeed# #sWeather.sProperties.speed#</td>
					</tr>
				</table>
			</td>
		</tr>
		<tr>
			<td class="lastupdate" align="center">
				<br />
				As reported at #sWeather.sCurrentConditions.station#, on
				<cfset variables.cLastUpdate = Mid(sWeather.sCurrentConditions.lastUpdate, 1, Len(sWeather.sCurrentConditions.lastUpdate) - 10)>
				<cfset variables.cLastUpdateDate = DateFormat(variables.cLastUpdate, "full")>
				<cfset variables.cLastUpdateTime = TimeFormat(variables.cLastUpdate, "h:mm tt")>
				#variables.cLastUpdateDate# at #variables.cLastUpdateTime#
				local time<br />
				<br />
				<a href="http://www.weather.com"><img src="#sWeather.sParams.imageLocation#logos/TWClogo_32px.png" border="0" alt="Data provided by weather.com" title="Data provided by weather.com"></a>
			</td>
		</tr>
	</table>
	</cfoutput>
</cf_weather>

That’s a lot of code but not that complex really. What’s happening here? First, we declare some CSS styles to pretty up our display. Then it’s that IE PNG Javascript fix that I talked about. We then call our custom tag, passing in as arguments the location ID, the partner ID and the license key. The rest of the code nested inside the tag is simply outputting parts of the sWeather structure to create our display. The result is a nice looking weather control:

Weather forecast example

Since the code to generate a forecast is pretty much the same as the one used for generating the current conditions, I am not going to post it again. Besides, all this code is included in the downloadable zip file. Suffice to say that the example I have included in the downloads will produce the following display:

Application and Session scopes

Application and session scopes must be turned on for this tag to work. I have included an “Application.cfm” file together with the downloads, which shows you what you need. You can leave this file inside your weather folder, or enable these scopes at the root level – that’s up to you. All you need really, is one line of code:

<CFAPPLICATION NAME="sWeather" SESSIONMANAGEMENT="Yes">

A word about caching

You could make your weather control even faster by caching its output HTML into the application scope and refreshing it at specific intervals. There are many custom tags out there that do this, and all you have to do is simply wrap their custom tag around mine. An example that I use on my projects is cf_accelerate by Brandon Purcell.

Don’t feel restricted by my designs above. Feel free to experiment with your own, by adding/removing elements from the display and changing the look and feel. I would love to see some different versions of your own, so if you do produce any please include them in the comments below.

There are not many open source ColdFusion weather controls out there, and that was my main motivation for creating one. The article focused more on how the weather.com data feeds work, but a similar technique could be used with any other service that provides weather feeds.

9 Responses to A ColdFusion weather custom tag

  • Rob

    Does this still work for current implementation of the weather.com API? Thanks!!!

    • Evagoras Charalambous

      @Rob,

      It’s been a while since I wrote this code. Since then, weather.com has started charging for this service. Since I do not have a paid account with them I could not verify that it still works – however I am willing to bet that it doees.

      If you do not have a paid account with them, I suggest you try other services like Accuweather or http://portal.theweatherchannel.com/, otherwise if you are willing to pay for access to the weather.com’s data, please let me know if it still works.

  • Rob

    If my client pays for the service I’ll let you know. Thanks again!

  • Rob

    Looks like the structure of the XML document has changed so it doesn’t work: http://98.223.134.36/weather/weather.xml (static example)

    I changed to my own static file to test with and I get errors. Blah.

    You’ve put a lot of work into this, however. It looks fantastic.

    • Evagoras Charalambous

      It looks like they changed the XML reply completely. If you really want to get the weather.com’s feed to work, feel free to adjust my custom tag that queries the XML document. You will have to create your own variables based on the new XML nodes, but it’s doable.

      Good luck with it.

  • Rob

    Are you interested in changing it up? If so, how much? I can download a new XML file for your reference or I can sign up and give you the id/key to test. Let me know!

    • Evagoras Charalambous

      Rob,

      I replied to your email address. Please verify and let me know by responding to my email in return.

      Thanks.

  • Bill

    Any chance of you updating your CF tag to work with the new XML?

    • Evagoras Charalambous

      Since I don’t have a paid account with them, I can’t access their new XML or test. If you are trying to make it work with their updated XML output and are having issues, please post back here and I will be glad to help out. If you like, send me in private your access and/or an XML output example as well.

Leave a Reply

Your email address will not be published. Required fields are marked *