Pete as a Newspaper

Parse Yahoo! Weather RSS using PHP and SimpleXML (also: explore the yweather namespace)

Posted Jul 7, 10:07 AM in by Pete Karl, received one comment, comments closed.

The Yahoo! Weather API is just swell. We get current temp, atmosphere, et cetera for any area of the US and a forecast for tomorrow all for free. In a similar bout of awesomeness, PHP5 contains the SimpleXML class.

I’m assembling a mobile site that uses the weather feed from Yahoo! (it’s secret“.”:http://weathertrafficnews.com) I’m going to run through the trials and tribulations of parsing Yahoo! RSS with SimpleXML, and provide the code I used to do so. Yippee.

Yahoo! Weather API

The weather API from Yahoo! conforms to the RSS 2.0 specification. It’s an XML document that contains elements that describe the feed itself, and elements containing the data being delivered by the feed.

The feed accepts arguments that describe the location (p) & units for temperature (u). For example, Rochester’s feed in fahrenheit would look like this:

http://weather.yahooapis.com/forecastrss?p=14607&u=f

Important data I want to extract from this feed:

  • today’s temperature
  • today’s ‘condtiions’ (cloudy? sunny? etc.)
  • today’s high/low
  • ditto for tomorrow

Thanks, Yahoo!, that’s quite enough information to get a little weather widget going. Let’s take a look at our parsing tools.

PHP & SimpleXML

My first big lesson in XML parsing came from an XML Programming course where we built DOM and SAX parsers in Java. Having that background in XML parsing was helpful in understanding how PHP’s SimpleXML object works.

Essentially, SimpleXML is a DOM parser. This means that the parser reads XML into memory and converts it into an PHP DOM object that can be manipulated by PHP. In this case, we have a SimpleXML object instead of a DOM object.

In case you’re interested, there are big differences in usage between SimpleXML and DOM objects. In a nutshell, DOM is robust and verbose; SimpleXML is quick, but weak. The beginning of this SimpleXML article from the Zend Developer Zone compares the two.

Usage

Starting with the Yahoo! weather RSS, we’re going to sort Yahoo! weather data into a couple of easy-to-use weather objects. One of them will contain channel data about the feed, and the other will be populated with feed items (incl. our weather data).

First thing’s first, let’s get a handle on that weather feed (this is all in PHP, mind you, so don’t forget the )

I’m going to grab the text of the weather feed, check to see if I actually grabbed anything, then create my SimpleXML object.

$weather_feed = file_get_contents("http://weather.yahooapis.com/forecastrss?p=14607&u=f");
if(!$weather_feed) die('weather failed, check feed URL');
$weather = simplexml_load_string($weather_feed);

In the background, PHP has loaded the XML doc into $weather and broken most of it into an easily-accessible PHP object.

Note: SimpleXML does not attempt to obtain namespaced elements, though there is a way to get them. You can obtain direct descendants that belong to a specific namespace by using the children() method.

For example, in order to grab elements in the yweather namespace that belong to the channel element, you pass the namespace into children(), like so:

$channel_yweather = $weather->channel->children("http://xml.weather.yahoo.com/ns/rss/1.0");

Now we have a SimpleXML object that contains yweather elements directly below channel. Yay. The next step is to turn that information into an easy-to-use PHP assoc. array:

foreach($channel_yweather as $x => $channel_item) 
	foreach($channel_item->attributes() as $k => $attr) 
		$yw_channel[$x][$k] = $attr;

Our first array ($yw_channel) should come out looking like this:


Array ( [location] => Array ( [city] => SimpleXMLElement Object ( [0] => Rochester ) [region] => SimpleXMLElement Object ( [0] => NY ) [country] => SimpleXMLElement Object ( [0] => US ) )

[units] => Array ( [temperature] => SimpleXMLElement Object ( [0] => F ) [distance] => SimpleXMLElement Object ( [0] => mi ) [pressure] => SimpleXMLElement Object ( [0] => in ) [speed] => SimpleXMLElement Object ( [0] => mph ) )

[wind] => Array ( [chill] => SimpleXMLElement Object ( [0] => 79 ) [direction] => SimpleXMLElement Object ( [0] => 230 ) [speed] => SimpleXMLElement Object ( [0] => 7 ) )

[atmosphere] => Array ( [humidity] => SimpleXMLElement Object ( [0] => 48 ) [visibility] => SimpleXMLElement Object ( [0] => 10 ) [pressure] => SimpleXMLElement Object ( [0] => 30.04 ) [rising] => SimpleXMLElement Object ( [0] => 2 ) )

[astronomy] => Array ( [sunrise] => SimpleXMLElement Object ( [0] => 5:39 am ) [sunset] => SimpleXMLElement Object ( [0] => 8:52 pm ) )
)

Now the same for each of the individual item elements (with a little bit of extra code to account for the forecast XML):


$item_yweather = $weather->channel->item->children(“http://xml.weather.yahoo.com/ns/rss/1.0”);

foreach($item_yweather as $x => $yw_item) { foreach($yw_item->attributes() as $k => $attr) { if($k 'day') $day = $attr; if($x ‘forecast’) { $yw_forecast[$x][$day . ‘’][$k] = $attr; } else { $yw_forecast[$x][$k] = $attr; } }
}

Now, I’ve got my second array ($yw_forecast); it’s contents looking like this:


Array ( [condition] => Array ( [text] => SimpleXMLElement Object ( [0] => Partly Cloudy ) [code] => SimpleXMLElement Object ( [0] => 30 ) [temp] => SimpleXMLElement Object ( [0] => 79 ) [date] => SimpleXMLElement Object ( [0] => Mon, 07 Jul 2008 9:54 am EDT ) )

[forecast] => Array ( [Mon] => Array ( [day] => SimpleXMLElement Object ( [0] => Mon ) [date] => SimpleXMLElement Object ( [0] => 7 Jul 2008 ) [low] => SimpleXMLElement Object ( [0] => 69 ) [high] => SimpleXMLElement Object ( [0] => 87 ) [text] => SimpleXMLElement Object ( [0] => Isolated Thunderstorms ) [code] => SimpleXMLElement Object ( [0] => 37 ) )

[Tue] => Array ( [day] => SimpleXMLElement Object ( [0] => Tue ) [date] => SimpleXMLElement Object ( [0] => 8 Jul 2008 ) [low] => SimpleXMLElement Object ( [0] => 71 ) [high] => SimpleXMLElement Object ( [0] => 90 ) [text] => SimpleXMLElement Object ( [0] => Isolated Thunderstorms ) [code] => SimpleXMLElement Object ( [0] => 37 ) ) )
)

Results

In short, it works for me. You can download the script in its entirety. SimpleXML is a great tool in the PHP dev’s toolbox for quickly parsing small XML feeds. I hope this article helps w/the namespacing issue that a lot of new PHP devs run into with SimpleXML.

Comments

  1. Rene Pot
    Jul 9, 08:39 AM #

    Hi there,

    thanks for posting this nice document. I love the way you describe it. I was looking for something like this for a couple of days already. You really helped me out!

    Thanks.

Comments closed for this article.