Creating A Simple PDF With The Zend Framework

I’ve recently been playing with creating PDF documents for a project I’ve been working on.

I thought I’d share some of the knowledge I’ve gained in the hope it will help others.

I’ve been using the excellent Zend Framework as usual, and the Zend_Pdf component in particular. This is a pure PHP implementation of the PDF standard and it doesn’t require any other libraries to be installed to work.

A PDF document is text document that has been been designed by Adobe a way to create and share printable documents across multiple platforms. If you open a PDF document in a text editor, you can see the markup for yourself, however it’s not very user friendly. This is where Zend_Pdf comes to our aid.

Let’s create a simple A4 document, and say Hello World!.


<?php
// load the Zend Framework Autoloader.
ini_set("include_path","./library");
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
try {
// create a new PDF document.
$pdf = new Zend_Pdf();
// create the Helvetica font.
$font = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA);
// create a new A4 sized page.
$page = new Zend_Pdf_Page(Zend_Pdf_Page::SIZE_A4);
// draw the text Hello World! to position 0,0 with the Helvetica font.
$page->setFont($font, 16)
->drawText('Hello World!',0,0);
// add the page to the pdf document.
$pdf->pages[] = $page;
// save the finished PDF to a file
$pdf->save('helloworld.pdf');
// catch any errors
} catch (Zend_Pdf_Exception $e) {
die('PDF error: ' . $e->getMessage());
} catch (Exception $e) {
die ('Error: ' . $e->getMessage());
}
?>

What’s going on? Well firstly I take advantage of Zend Frameworks autoloader to load in the required components.

Next I create an empty PDF document. A copy of the Helvetica font is prepared for use. We’ll need to add pages to this document, so after this we create a new A4 sized page. I’ve used A4 as that is the common paper size in Europe, but in the US letter size is the standard. This can be changed by using Zend_Pdf_Page::SIZE_LETTER instead of Zend_Pdf_Page::SIZE_A4.

Now I have a page, I want to add some text to it. This is easily achieved using the drawText method. This takes the text, and an X and Y position to draw it at. We do need to set the font first, let’s use the Helvetica font we defined earlier, and use size 16. I chose position 0,0 to write the text, this is the bottom left hand side of the page.

Finally, I add the page to PDF document, and save it.

If an error occurs, I catch this with my exception handlers.

Of course, in reality you’ll want o do a lot more than just write one line of text. Zend_Pdf allows you to do a lot more, such as adding images, drawing graphics, adding meta data. I’ll cover this in another post.

Using The Cycle Function In Twig

I was looking at adding zebra stripes to some data to improve readability to a page of data generated from PHP using the Twig templating system.

Twig provides a method called cycle that can be used to alternate through a list of values, so this is was the obvious candidate.

cycle takes 2 parameters, the first is an array of values to iterate through, the second is an integer with the cycle value.

This means all I have to do is to pass in an array with the css class names I’m using for my striping, and the position of the loop I’m iterating through to display my data. For example…

 
{% if users|length > 0 %}
  <ul>
{% for user in users %}
  <li class="{{ cycle(['even','odd'],loop.index) }}">{{ user.username|e }}</li>
{% endfor %}
  </ul>
{% endif %}

I have a list of users that I’m iterating through. For each user I choose wether to display use either the odd or even class using the cycle function. I have to pass in loop.index as the cycle value to count as this increments each time the loop is iterated through.

This gave me an output something like this…

 
<ul>
  <li class="even">Rob</li>
  <li class="odd">John</li>
  <li class="even">Paul</li>
  <li class="odd">George</li>
  <li class="even">Ringo</li>
</ul>

Adding A Trailing Slash To A Zend Framework URL

“We need all our URL’s to have a trailing slash”, was a request I had in recently.

This sounds easy enough, a quick rewrite rule will do the trick, and that is what I added.

RewriteRule ^(.*[^/])$ /$1/ [R=301,L]

I look at the start of the URL, grab every character to the end of the URL, making sure the last one isn’t a slash already, then rewrite that with slashes around it, issuing a 301 redirect and informing Apache not to process any more rules.

This works great for pages already on the server, for example /guestbook becomes /guestbook/. However, what if we wanted to load /logo.gif, this would rewrite to /logo.gif/ and cause a error.

OK, so we need not to match every character in the URL, but only if it doesn’t have a dot in there. The site in question was a Zend Framework application, and this caused it’s own problems.

Zend Framework applications have their own rewriting rules…

RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

This checks if the requested resource is actually a real object Apache can serve, if not it passes it over to the Zend Framework to handle internally via the index.php script.

So what happens if /guestbook is actually a Zend Framework application?

Well, the URL would be rewritten to /index.php/.

Why? Well the first rewrite we added a slash, this caused the page to re-requested, this then passed to the Zend Framework rewrites, this saw it needed to rewrite to index.php, this caused the page to be re-requested again internally, which added a slash to the end, and redirected again. Finally this request was /index.php/ which doesn’t exist and failed.

Wow, that was a mouthful, let’s look at that as a sequence diagram.

sequence diagram showing apache rewrites and Zend Framework working incorrectly

What we need is to only rewrite the requested URL if it doesn’t have a trailing slash and if it doesn’t have a dot in the request and if it isn’t an internal Apache redirect. We also only want to rewrite if the request is a GET, POSTs (DELETE’s and PUT’s too) don’t support rewriting in the browser.

This indicates a series a conditions that need to be met, so tells me we should be using Apache’s RewriteCond directive.

Let’s check for a GET request first…

RewriteCond %{REQUEST_METHOD} GET [NC]

The %{REQUEST_METHOD} variable in a rewrite rule tells us the HTTP method used to make the request, so we just need to check if that is GET. The [NC] makes the check case insensitive so matches GET, get, Get, etc…

Next we need to see if the request already has a trailing slash.

RewriteCond %{REQUEST_URI} !/$

This checks the requested URI and sees if the last character isn’t a slash.

Now we need to check if there are any dots in the request.

RewriteCond %{REQUEST_URI} !.

This just checks that there isn’t a dot in the requested URI. As dot normally matches any character, we need to escape this with a clash first.

If all these conditions match, we can issue our RewriteRule.

RewriteRule ^.*$ %{REQUEST_URI}/ [R=301,L]

This takes the requested URI, adds a slash and issues a 301 status code to force the browser to re-request the page and change the URL shown in the address bar. We add the L to tell Apache not to process any more rules.

Let’s put this all together, and insert it above the normal Zend Framework rewrites, but after RewriteEngine On.

RewriteCond %{REQUEST_METHOD} GET [NC]
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{REQUEST_URI} !.
RewriteRule ^.*$ %{REQUEST_URI}/ [R=301,L]

Let’s request /guestbook again, and see what happens.

sequence diagram showing apache rewrites and Zend Framework

Handling HTTP And HTTPS Ads With JavaScript

A few days ago I wrote about a problem I had with some javascript ad code defering execution. Well another problem arose today with the code, and I thought I’d share the solution.

Some pages on the site I’m developing on are served over https, others are served over http. They share a common template so the same ad code is served across all pages. At the moment they serve purely over http, and this is great most of the time, however when the page is served over https a security alert is shown asking the user if they want to show unsecure content. Most users would say no in this situation so our ads won’t be shown.

What we need is a way for ads to be shown if a user is on a secure or normal connection.

Thankfully our ad provider allows us to request the same ad in either http or https by just changing the protocol, e.g. http://ad... or https://ad... .

The ad is written out using a document.write statement and is meant to be executed as the page is rendering.

We need to detect how the current page is being served, so we know what protocol to request the ad in.

This is easy in JavaScript, we can just query the value document.location.protocol. This returns either ‘http:’ or ‘https:’. Note the trailing colon…

We can use the value document.location.protocol directly, but just incase another protocol has been used, we can default everything to http if https hasn’t been used. The following code will help here…


var protocol = 'https:' == document.location.protocol ? 'https' : 'http';

Here we are seeing if document.location.protocol is the value ‘https:’, if it is set the value of protocol to ‘https’, else set it to ‘http’.

Let’s look at the original ad code…


<script type="text/javascript">
<!--
if (window.adgroupid == undefined) {
window.adgroupid = Math.round(Math.random() * 1000);
}
document.write('>scr'+'ipt language="javascript1.1" src="http://adserver.adtech.de/addyn|3.0|311.0|3328078|0|225|ADTECH;cookie=info;alias=FindClassicCars+Maserati+7+leaderboard;loc=100;target=_blank;key=key1+key2+key3+key4;grp='+window.adgroupid+';misc='+new Date().getTime()+'"></scri'+'pt>');
//-->
</script>

We can take our earlier ternary expression to embed the protocol directly into the ad code like this.


<script type="text/javascript">
<!--
if (window.adgroupid == undefined) {
window.adgroupid = Math.round(Math.random() * 1000);
}
document.write('>scr'+'ipt language="javascript1.1" src="'+( 'https:'==document.location.protocol?'https':'http') +'://adserver.adtech.de/addyn|3.0|311.0|3328078|0|225|ADTECH;cookie=info;alias=FindClassicCars+Maserati+7+leaderboard;loc=100;target=_blank;key=key1+key2+key3+key4;grp='+window.adgroupid+';misc='+new Date().getTime()+'"></scri'+'pt>');
//-->
</script>

The ad code will now serve ads to our customers if they are on either a normal or secure page, and our ad team is happy again.

Defering Inline JavaScript Problems

I came across an interesting problem trying to debug a website that had issues with some ad code earlier. The site was working fine until ad code had been added, then in Internet Explorer it was only showing the ad instead of the page. Firefox, Safari and Chrome were fine, so it suggested a problem with the ad code.

The ad code in question was pretty common, the sort that inserts a script tag via a document.write.

<script language="javascript" defer="defer" async >
<!--
if (window.adgroupid == undefined) {
window.adgroupid = Math.round(Math.random() * 1000);
}
document.write('>scr'+'ipt language="javascript1.1" src="http://adserver.adtech.de/addyn|3.0|311.0|3328078|0|225|ADTECH;cookie=info;alias=FindClassicCars+Maserati+7+leaderboard;loc=100;target=_blank;key=key1+key2+key3+key4;grp='+window.adgroupid+';misc='+new Date().getTime()+'"></scri'+'pt>');
//-->
</script>

The problem turned out to be with the attribute defer in the script tag.

Defer gives the browser a clue that a piece of JavaScript can be run later, rather than as soon as the browser sees it. This can be used to speed up the rendering of a site. However, Internet Explorer runs differently to other browsers. As the script in question was inline, all the other browsers ran it immediately, whereas Internet Explorer didn’t. On Internet Explorer the code was run once the page DOM had been created, so writing out the fresh tags after the document was closed. This caused the ads to show on what looked like a new page on IE’s below version 9, and on IE 9 the ads appeared at the bottom of the page.

The fix is to simply remove the defer attribute and change the the opening script tag to the following, leaving the rest of the ad tag in place.

<script type="text/javascript">

You may have noticed I’ve ignored the async attribute that was in the original script tag. That’s an interesting new attribute in HTML5, but alas a topic for another time.

HTTP Methods For RESTful Web Services

The use of HTTP methods when designing and building a RESTful web service is very important.

Most developers only use the GET and POST methods offered by the HTTP specification, and for most web sites this is fine.

However, there are other useful methods in the specification that are often overlooked by web developers, but as a RESTful web service developer you will need to know. The most important of these are PUT and DELETE.

REST uses HTTP methods as a one to one mapping to the CRUD (Create, Read, Update and Delete) operations you may be familiar with as a developer. These are

  • Create a resource – POST
  • Read a resouce – GET
  • Update a resource – PUT
  • Delete a resource – DELETE

There are also two other terms associated with RESTful services that you should be aware of, “safe” and “idempotent”.

A safe request is a request to read some data, not to change any server state. GET requests are safe as you should be able to GET a resource any number of times without affecting it’s state.

An idempotent request is request that however many times it is invoked, the end result is the same. GET, PUT and DELETE are all idempotent. You should be able to DELETE a resource any number of times, once deleted it’s gone, trying to delete it again won’t change the fact it’s gone.

POST is the method that causes problems, it is neither safe or idempotent. Using our CRUD example from earlier, POSTing to a server, could create duplicate resources.

For more details on other HTTP methods, such as HEAD and OPTIONS, have a look at RFC2616 – The HTTP 1.1 specification.

XML Web Services And Character Sets

When developing web services that serve XML, it’s important to get the MIME type right as the wrong one could decoding errors due to default character sets.

text/xml defaults to sending your XML document in the us-ascii character set. See section 3.1 of RFC 3032 for the reason why.

application/xml defaults to sending your XML document in the utf-8 character set. See section 8.10 of RFC 3032 and Appendix F of the XML specification for the reasons why.

Of course, you can override these defaults, but it’s worth remembering if your XML application doesn’t behave quite as you were expecting and is rendering odd characters.

Inside The Met Office iPhone App

Being on annual leave for the annual Eastbourne Airbourne air show, I’ve been using the Met Office app on my iPhone quite a bit to keep track of the weather.

This has to be one of the apps I use most frequently, and the according to a press release from the Met Office from September 2010, the Met Office iPhone app has had over a million downloads and it ranks amongst the top 5 apps in the UK.

The app was written by an agency called Gorillabox.

I thought I’d take a look at how it works.

All the pages seem to take advantage of a web service located at http://metip.g-box.tv/ . Judging from the headers sent from the service, this appears to be written in Perl using the excellent Catalyst framework. They return UTF-8 encoded XML.

Loading

When you load the app, it queries your device’s GPS to get your current latitude and longitude, this location is used throughout the app.

Home

The first page you get to is the home page. This shows the Met Office logo, a space for an advertisement that is currently just pushing the Met Office’s Twitter account, an image of the current weather, and a bar showing your current location’s weather, temperature, wind speed / direction and sunset time.

Met office app home screen

Behind the scenes a query is sent to http://metip.g-box.tv/home with your lat and long in the query string. Here’s what was sent for my location. As you can see, all elements are returned from the web service.

GET /home?lat=50.7732N&long=0.2887E HTTP/1.1
Host: metip.g-box.tv
User-Agent: Gorillabox/2011031601.1.3 CFNetwork/485.13.9 Darwin/11.0.0
Accept: */*
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: keep-alive
HTTP/1.1 200 OK
Date: Mon, 15 Aug 2011 18:36:02 GMT
Server: Apache/2.2.12 (Ubuntu)
Content-Length: 456
X-Catalyst: 5.80031
X-PageCache: Catalyst
Connection: close
Content-Type: application/xml
<?xml version="1.0" encoding="UTF-8"?> <xml last_updated="15/08/2011 18:31">
<ad img="http://image.metip.g-box.tv:80/Twitter.png" url="http://twitter.com/metoffice" />
<severe_weather status="false" />
<site Sunset="20:24" display="Eastbourne Station" site_id="138" site_name="Eastbourne">
<view type="home">
<data date="15/08/2011" temp="16" time="21:00" weather_code="7" wind_direction="SW" wind_speed="8" />
</view>
</site>
</xml>

Weather

The next page is probably the most important one, the weather! This gives you a 5 day forecast of the weather for your location, along with a more detailed 24 hour forecast.

Met office app weather screen

Behind the scenes a query is sent to http://metip.g-box.tv/weather with your lat and long in the query string. Here’s what was sent for my location.

GET /weather?lat=50.7732N&long=0.2887E HTTP/1.1
Host: metip.g-box.tv
User-Agent: Gorillabox/2011031601.1.3 CFNetwork/485.13.9 Darwin/11.0.0
Accept: */*
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: keep-alive
HTTP/1.1 200 OK
Date: Mon, 15 Aug 2011 19:13:07 GMT
Server: Apache/2.2.12 (Ubuntu)
Content-Length: 3804
X-Catalyst: 5.80031
Connection: close
Content-Type: application/xml
<?xml version="1.0" encoding="UTF-8"?>
<xml last_updated="15/08/2011 18:33">
<site display="Eastbourne Station" site_name="Eastbourne">
<view type="overview">
<data id="1945892" display="Today 15/08/2011" index="0" sunrise="05:47" sunset="20:24" temp="15" type="night_header" weather_code="12" wind_direction="W" wind_speed="5" />
<data id="1950464" display="Tuesday 16/08/2011" index="1" sunrise="05:49" sunset="20:22" temp="19" type="standard" weather_code="7" wind_direction="SW" wind_speed="13" />
<data id="1955036" display="Wednesday 17/08/2011" index="2" sunrise="05:50" sunset="20:20" temp="19" type="standard" weather_code="3" wind_direction="E" wind_speed="7" />
<data id="1959608" display="Thursday 18/08/2011" index="3" sunrise="05:52" sunset="20:18" temp="19" type="standard" weather_code="7" wind_direction="NE" wind_speed="15" />
<data id="1964180" display="Friday 19/08/2011" index="4" sunrise="05:54" sunset="20:16" temp="21" type="standard" weather_code="1" wind_direction="NW" wind_speed="8" />
</view>
<view overview_index="0" type="detail">
<data display="15/08/2011 18:00 - 21:00" humidity="69"
index="0" temp="17" type="3hr" visibility="GO" weather_code="10" wind_direction="SW" wind_speed="9" />
<data display="15/08/2011 21:00 - 00:00" humidity="79" index="0" temp="16" type="3hr" visibility="VG" weather_code="2" wind_direction="SW" wind_speed="6" />
</view>
<view overview_index="1" type="detail">
<data display="16/08/2011 00:00 - 03:00" humidity="86" index="0" temp="15" type="3hr" visibility="GO" weather_code="12" wind_direction="W" wind_speed="5" />
<data display="16/08/2011 03:00 - 06:00" humidity="85" index="0" temp="15" type="3hr" visibility="VG" weather_code="7" wind_direction="SW" wind_speed="9" />
<data display="16/08/2011 06:00 - 09:00" humidity="83" index="0" temp="15" type="3hr" visibility="EX" weather_code="7" wind_direction="SW" wind_speed="8" />
<data display="16/08/2011 09:00 - 12:00" humidity="82" index="0" temp="17" type="3hr" visibility="VG" weather_code="7" wind_direction="SW" wind_speed="10" />
<data display="16/08/2011 12:00 - 15:00" hu
midity="75" index="0" temp="18" type="3hr" visibility="VG" weather_code="3" wind_direction="SW" wind_speed="13" />
<data display="16/08/2011 15:00 - 18:00" humidity="73" index="0" temp="18" type="3hr" visibility="VG" weather_code="3" wind_direction="SW" wind_speed="15" />
<data display="16/08/2011 18:00 - 21:00
" humidity="85" index="0" temp="17" type="3hr" visibility="GO" weather_code="8" wind_direction="SW" wind_speed="13" />
<data display="16/08/2011 21:00 - 00:00" humidity="92" index="0" temp="17" type="3hr" visibility="GO" weather_code="2" wind_direction="SW" wind_speed="11" />
</view>
<view overview_index="2" type="detail">
<data id="1955036" display="Wednesday 17/08/2011" index="0" temp="19" type="day" weather_code="3" wind_direction="E" wind_speed="7" />
<data id="1955036" display="Night" index="1" temp="16" type="night" weather_code="2" wind_direction="E" wind_speed="15" />
</view>
<view overview_index="3" type="detail">
<data id="1959608" display="Thursday 18/08/2011" index="0" temp="19" type="day" weather_code="7" wind_direction="NE" wind_speed="15" />
<data id="1959608" display="Night" index="1" temp="13" type="night" weather_code="2" wind_direction="NW" wind_speed="8" />
</view>
<view overview_index="4" type="detail">
<data id="1964180" display="Friday 19/08/2011" index="0" temp="21" type="day" weather_code="1" wind_direction="NW" wind_speed="8" />
<data id="1964180" display="Night" index="1" temp="13" type="night" weather_code="0" wind_direction="W" wind_speed="10" />
</view>
</site>
</xml>

Maps

The maps section allows you to either see the weather, temperature or wind speed for the whole UK, or to click into a specific part of the country to see regional data. There is also an icon on the top right of the page that gives you a written weather forecast.

This is probably the most complex part of the app, and a lot of data is returned from the query made to http://metip.g-box.tv/map. Here’s a cut back version of the data returned when tested.

GET /map HTTP/1.1
Host: metip.g-box.tv
User-Agent: Gorillabox/2011031601.1.3 CFNetwork/485.13.9 Darwin/11.0.0
Accept: */*
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: keep-alive
HTTP/1.1 200 OK
Date: Mon, 15 Aug 2011 18:49:57 GMT
Server: Apache/2.2.12 (Ubuntu)
Content-Length: 34217
X-Catalyst: 5.80031
Connection: close
Content-Type: application/xml
<?xml version="1.0" encoding="UTF-8"?>
<xml last_updated="15/08/2011 18:45">
<forecast_text>
<item display="Headline:" index="0">Outbreaks of rain spreading north, heaviest towards the west.</item>
<item display="This Evening and Tonight:" index="1">Outbreaks of rain spreading north, with the far northeast of Scotland remaining dry. Heaviest bursts are expected across northwestern areas with extensive hill fog developing later. Very little rain reaching southeastern parts. Brisk winds across the southwest.</item>
<item display="Tuesday:" index="2">Cloudy with occasionally rain, heavy at times over northern UK. Generally drier towards the southeast, but a chance of sharp showers during the afternoon. Brisk winds.</item>
<item display="Outlook for Wednesday to Friday:" index="3">Rain or showers across northwestern
and southern parts of the UK, possibly thundery at times across the far south. The best of the drier and brighter weather across central parts.</item>
</forecast_text>
<region region_name="SW Scotland, Lothian">
<site site_name="Galashiels" xpos="159" ypos="108">
<view type="map">
<data display="Monday 21:00" index="0" temperature="12" weather_code="2" wind_direction="SW" wind_speed="8" />
<data display="Tuesday 00:00" index="1" temperature="12" weather_code="7" wind_direction="S" wind_speed="6" />
<data display="Tuesday 03:00" index="2" temperature="11" weather_code="15" wind_direction="SE" wind_speed="6" />
<data display="Tuesday 06:00" index="3" temperature="11" weather_code="15" wind_direction="SE" wind_speed="8" />
<data display="Tuesday 09:00" index="4" temperature="12" weather_code="7" wind_direction="SE" wind_speed="8" />
<data display="Tuesday 12:00" index="5" temperature="14" weather_code="8" wind_direction="SE" wind_speed="7" />
<data display="Tuesday 15:00" index="6" temperature="16" weather_code="7" wind_direction="SW" wind_speed="9" />
<data display="Tuesday 18:00" index="7" temperature="14" weather_code="3" wind_direction="W" wind_speed="14" />
<data display="Tuesday 21:00" index="8" temperature="12" weather_code="2" wind_direc
tion="W" wind_speed="14" />
<data display="Wednesday 00:00" index="9" temperature="12" weather_code="2" wind_direction="W" wind_speed="14" />
<data display="Wednesday" index="10" temperature="17" weather_code="3" wind_direction="NW" wind_speed="8" />
<data display="Wednesday Night" index="11" temper
ature="10" weather_code="2" wind_direction="N" wind_speed="4" />
<data display="Thursday" index="12" temperature="15" weather_code="14" wind_direction="SE" wind_speed="5" />
<data display="Thursday Night" index="13" temperature="9" weather_code="2" wind_direction="W" wind_speed="7" />
<data display="Friday" index="14" temperature="16" weather_code="3" wind_direction="W" wind_speed="10" />
<data display="Friday Night" index="15" temperature="11" weather_code="9" wind_direction="SW" wind_speed="10" />
</view>
</site>
</region>
<region region_name="East England">
<site site_name="Norwich" xpos="249" ypos="214">
<view type="map">
<data display="Monday 21:00" index="0" temperature="18" weather_code="2" wind_direction="SW" wind_speed="5" />
<data display="Tuesday 00:00" index="1" temperature="17" weather_code="12" wind_direction="SW" wind_speed="6" />
<data display="Tuesday 03:00" index="2" temperature="15" weather_code="12" wind_direction="SW" wind_speed="4" />
<data display="Tuesday 06:00" index="3" temperature="14" weather_code="7" wind_direction="SW" wind_speed="6" />
<data display="Tuesday 09:00" index="4" temperature="16" weather_code="7" wind_direction="SW" wind_speed="11" />
<data display="Tuesday 12:00" index="5" temperat
ure="18" weather_code="7" wind_direction="SW" wind_speed="13" />
<data display="Tuesday 15:00" index="6" temperature="19" weather_code="7" wind_direction="SW" wind_speed="13" />
<data display="Tuesday 18:00" index="7" temperature="20" weather_code="3" wind_direction="SW" wind_speed="12" />
<data display="Tuesday 21:00" index="8" temperature="18" weather_code="2" wind_direction="SW" wind_speed="9" />
<data display="Wednesday 00:00" index="9" temperature="16" weather_code="2" wind_direction="NW" wind_speed="9" />
<data display="Wednesday" index="10" temperature="20" weather_code="3" wind_direction="NW" wind_speed="8" />
<data display="Wednesday Night" index="11" temperature="13" weather_code="7" wind_direction="NE" wind_speed="5" />
<data display="Thursday" index="12" temperature="17" weather_code="10" wind_direction="NE" wind_speed="9" />
<data display="Thursday Night" index="13" temperature="13" weather_code="7" wind_direction="NW" wind_speed="8"
/>
<data display="Friday" index="14" temperature="19" weather_code="1" wind_direction="NW" wind_speed="12" />
<data display="Friday Night" index="15" temperature="12" weather_code="0" wind_direction="S" wind_speed="9" />
</view>
</site>
</region>
<region region_name="East Midlands">
<site
site_name="Boston" xpos="216" ypos="189">
<view type="map">
<data display="Monday 21:00" index="0" temperature="18" weather_code="2" wind_direction="SW" wind_speed="5" />
<data display="Tuesday 00:00" index="1" temperature="16" weather_code="9" wind_direction="SW" wind_speed="6" />
<data display="Tuesday 03:00" index="2" temperature="14" weather_code="12" wind_direction="S" wind_speed="7" />
<data display="Tuesday 06:00" index="3" temperature="14" weather_code="15" wind_direction="S" wind_speed="10" />
<data display="Tuesday 09:00" index="4" temperature="15" weather_code="12" wind_direction="S" wind_speed="12" />
<data display="Tuesday 12:00" index="5" temperature="18" weather_code="7" wind_direction="SW" wind_speed="15" />
<data display="Tuesday 15:00" index="6" temperature="21" weather_code="3" wind_direction="SW" wind_speed="17" />
<data display="Tuesday 18:00" index="7" temperature="20" weather_code="1" wind_direction="W" wind_speed="1
3" />
<data display="Tuesday 21:00" index="8" temperature="16" weather_code="2" wind_direction="W" wind_speed="10" />
<data display="Wednesday 00:00" index="9" temperature="14" weather_code="0" wind_direction="W" wind_speed="9" />
<data display="Wednesday" index="10" temperature="20" weather_code="3" wind_direction="NW" wind_speed="6" />
<data display="Wednesday Night" index="11" temperature="14" weather_code="12" wind_direction="E" wind_speed="6" />
<data display="Thursday" index="12" temperature="18" weather_code="12" wind_direction="NE" wind_speed="7" />
<data display="Thursday Night" index="13" temperature="11" weather_code="12" wind_direction="NW" wind_speed="7" />
<data display="Friday" index="14" temperature="20" weather_code="3" wind_direction="NW" wind_speed="11" />
<data display="Friday Night" index="15" temperature="12" weather_code="2" wind_direction="S" wind_speed="7" />
</view>
</site>
</region>
<region region_name="Grampian">
<site site_name="Fraserburgh" xpos="180" ypos="35">
<view type="map">
<data display="Monday 21:00" index="0" temperature="14" weather_code="2" wind_direction="W" wind_speed="2" />
<data display="Tuesday 00:00" index="1" temperature="13" weather_code="7" wind_direction="S" wind_speed="3" /
>
<data display="Tuesday 03:00" index="2" temperature="12" weather_code="7" wind_direction="S" wind_speed="4" />
<data display="Tuesday 06:00" index="3" temperature="12" weather_code="3" wind_direction="SE" wind_speed="7" />
<data display="Tuesday 09:00" index="4" temperature="14" weather_code="7" wind_direction="SE" wind_speed="10" />
<data display="Tuesday 12:00" index="5" temperature="14" weather_code="7" wind_direction="SE" wind_speed="13" />
<data display="Tuesday 15:00" index="6" temperature="14" weather_code="12" wind_direction="SE" wind_speed="14" />
<data display="Tuesday 18:00" index="7" temperature="13" weather_code="12" wind_direction="E" wind_speed="11" />
<data display="Tuesday 21:00" index="8" temperature="13" weather_code="11" wind_direction="E" wind_speed="10" />
<data display="Wednesday 00:00" index="9" temperature="13" weather_code="12" wind_direction="E" wind_speed="9" />
<data display="Wednesday" index="10" temperature="14" weather_code="12" wind_direction="NW" wind_speed="14" />
<data display="Wednesday Night" index="11" temperature="11" weather_code="2" wind_direction="NW" wind_speed="4" />
<data display="Thursday" index="12" temperature="14" weather_code="7" wind_direction="E" wind_speed="4" />
<data display="Thursday Night" index="13" temperature="12" weather_code="9" wind_direction="N" wind_speed="6" />
<data display="Friday" index="14" temperature="14" weather_code="10" wind_direction="NW" wind_speed="10" />
<data display="Friday Night" index="15" temperature="12" weather_code="7" wind_direction="SE" wind_sp
eed="13" />
</view>
</site>
</region>
<region region_name="Highlands &amp; Eilean S">
<site site_name="Fort William" xpos="110" ypos="39">
<view type="map">
<data display="Monday 21:00" index="0" temperature="13" weather_code="2" wind_direction="SE" wind_speed="3" />
<data display="Tuesday 00:00" index="1" temperature="12" weather_code="2" wind_direction="NE" wind_speed="3" />
<data display="Tuesday 03:00" index="2" temperature="12" weather_code="12" wind_direction="NE" wind_speed="4" />
<data display="Tuesday 06:00" index="3" temperature="12" weather_code="15" wind_direction="N" wind_speed="5" />
<data display="Tuesday 09:00" index="4" temperature="13" weather_code="15" wind_direction="NE" wind_speed="5" />
<data display="Tuesday 12:00" index="5" temperature="13" weather_code="15" wind_direction="N" wind_speed="3" />
<data display="Tuesday 15:00" index="6" temperature="13" weather_code="15" wind_direction="W" wind_speed="4" />
<data display="Tuesday 18:00" index="7" temperature="13" weather_code="15" wind_direction="W" wind_speed="12" />
<data display="Tuesday 21:00" index="8" temperature="12" weather_code="7" wind_direction="SW" wind_speed="9" />
<data display="Wednesday 00:00" index="9" temperature="12" weather_code="7" wind_direction="SW" wind_speed="8" />
<data display="Wednesday" index="10" temperature="16" weather_code="3" wind_direction="NW" wind_speed="9" />
<data display="Wednesday Night" index="11" temperature="10" weather_code="2" wind_direction="N" wind_speed="2" />
<data display="Thursday" index="12" temperature="14" weather_code="10" wind_direction="N" wind_speed="7" />
<data display="Thursday Night" index="13" temperature="10" weather_code="2" wind_direction="NW" wind_speed="5" />
<data display="Friday" index="14" temperature="16" weather_code="12" wind_direction="SW" wind_speed="9" />
<data display="Friday Night" index="15" temperature="13" weather_code="13" wind_direction="S" wind_speed="16" />
</view>
</site>
</region>
<region region_name="North East England">
<site site_name="Newcastle International" xpos="197" ypos="119">
<view type="map">
<data display="Monday 21:00" index="0" temperature="15" weather_code="0" wind_direction="SW" wind_speed="5" />
<data display="Tuesday 00:00" index="1" temperature="14" weather_code="7" wind_direction="S" wind_speed="6" />
<data display="Tuesday 03:00" index="2" temperature="12" weather_code="12" wind_direction="S" wind_speed="6" />
<data display="Tuesday 06:00" index="3" temperature="12"
weather_code="12" wind_direction="SE" wind_speed="7" />
<data display="Tuesday 09:00" index="4" temperature="13" weather_code="15" wind_direction="S" wind_speed="9" />
<data display="Tuesday 12:00" index="5" temperature="15" weather_code="7" wind_direction="S" wind_speed="9" />
<data display="Tuesday 15:00" index="6" temperature="19" weather_code="3" wind_direction="SW" wind_speed="10" />
<data display="Tuesday 18:00" index="7" temperature="16" weather_code="1" wind_direction="W" wind_speed="14" />
<data display="Tuesday 21:00" index="8" temperature="13" weather_code="0" wind_direction="W" wind_speed="13" />
<data display="Wednesday 00:00" index="9" temperature="12" weather_code="0" wind_direction="W" wind_speed="13" />
<data display="Wednesday" index="10" temperature="16" weather_code="7" wind_direction="N" wind_speed="8" />
<data display="Wednesday Night" index="11" temperature="11" weather_code="7" wind_direction="NW" wind_speed="3" />
<data display="Thursday" index="12" temperature="15" weather_code="10" wind_direction="SE" wind_speed="5" />
<data display="Thursday Night" index="13" temperature="9" weather_code="0" wind_direction="W" wind_speed="8" />
<data display="Friday" index="14" temperature="18" weather_code="1" wind_direction="NW" wind_speed="10" />
<data display="Friday Night" index="15" temperature="12" weather_code="7" wind_direction="SW" wind_speed="8" />
</view>
</site>
</region>
<region region_name="Northern Ireland">
<site site_name="Belfast" xpos="89" ypos="134">
<view type="map">
<data display="Monday 21:00" index="0" temperature="14" weather_code="15" wind_direction="SE" wind_speed="5" />
<data display="Tuesday 00:00" index="1" temperature="14" weather_code="9" wind_direction="S" wind_speed="8" />
<data display="Tuesday 03:00" index="2" temperature="14" weather_code="7" wind_direction="S" wind_speed="6" />
<data display="Tuesday 06:00" index="3" temperature="14" weather_code="11" wind_direction="S" wind_speed="5" />
<data display="Tuesday 09:00" index="4" temperature="15" weather_code="11" wind_direction="SW" wind_speed="10" />
<data display="Tuesday 12:00" index="5" temperature="16" weather_code="3" wind_direction="W" wind_speed="16" />
<data display="Tuesday 15:00" index="6" temperature="17" weather_code="1" wind_direction="NW" wind_speed="16" />
<data display="Tuesday 18:00" index="7" temperature="15" weather_code="1" wind_direction="NW" wind_speed="14" />
<data display="Tuesday 21:00" index="8" temperature="13" weather_code="0" wind_direction="NW" wind_speed="9" />
<data display="Wednesday 00:00" index="9" temperature="11" weather_code="2" wind_direction="W" wind_speed="6" />
<data display="Wednesday" index="10" temperature="17" weather_code="10" wind_direction="NW" wind_speed="5" />
<data display="Wednesday Night" index="11" temperature="11" weather_code="7" wind_direction="N" wind_speed="2" />
<data display="Thursday" index="12" temperature="15" weather_code="10" wind_direction="NW" wind_speed="4" />
<data display="Thursday Night" index="13" temperature="9" weather_code="0" wind_direction="W" wind_speed="5" />
<data display="Friday" index="14" temperature="19" weather_code="10" wind_direction="SW" wind_speed="9" />
<data display="Friday Night" index="15" temperature="13" weather_code="13" wind_direction="S" wind_speed="16" />
</view>
</site>
</region>
<region region_name="North West England">
<site site_name="Blackpool" xpos="161" ypos="157">
<view type="map"
>
<data display="Monday 21:00" index="0" temperature="15" weather_code="9" wind_direction="SW" wind_speed="11" />
<data display="Tuesday 00:00" index="1" temperature="14" weather_code="15" wind_direction="S" wind_speed="11" />
<data display="Tuesday 03:00" index="2" temperature="14" weather_code="15" wind_direction="SE" wind_speed="13" />
<data display="Tuesday 06:00" index="3" temperature="13" weather_code="15" wind_direction="SE" wind_speed="18" />
<data display="Tuesday 09:00" index="4" temperature="15" weather_code="15" wind_direction="S" wind_speed="16" />
<data display="Tuesday 12:00" index="5" temperature="16" weather_code="11" wind_direction="SW" wind_speed="20" />
<data display="Tuesday 15:00" index="6" temperature="16" weather_code="3" wind_direction="W" wind_speed="21" />
<data display="Tuesday 18:00" index="7" temperature="16" weather_code="7" wind_direction="NW" wind_speed="17" />
<data display="Tuesday 21:00" index="8" temperature="15" weather_code="2" wind_direction="NW" wind_speed="18" />
<data display="Wednesday 00:00" index="9" temperature="14" weather_code="2" wind_direction="NW" wind_speed="17" />
<data display="Wednesday" index="10" temperature="16" weather_code="7" wind_direction="NW" wind_speed="11" />
<data display="Wednesday Night" index="11" temperature="12" weather_code="7" wind_direction="N" wind_speed="4" />
<data display="Thursday" index="12" temperature="16" weather_code="3" wind_direction="NW" wind_speed="8" />
<data display="Thursday Night" index="13" temperature="13" weather_code="0" wind_direction="NW" wind_speed="12" />
<data display="Friday" index="14" temperature="16" weather_code="1" wind_direction="W" wind_speed="11" />
<data display="Friday Night" index="15" temperature="13" weather_code="12" wind_direction="SW" wind_speed="14" />
</view>
</site>
</region>
<region region_name="Orkney &amp; Shetland">
<site site_name="Lerwick" xpos="247" ypos="25">
<view type="map">
<data display="Monday 21:00" index="0" temperature="12" weather_code="2" wind_direction="SW" wind_speed="9" />
<data display="Tuesday 00:00" index="1" temperature="11" weather_code="2" wind_direction="SW" wind_speed="9" />
<data display="Tuesday 03:00" index="2" temperature="11" weather_code="7" wind_direction="SW" wind_speed="8" />
<data display="Tuesday 06:00" index="3" temperature="11" weather_code="7" wind_direction="S" wind_speed="4" />
<data display="Tuesday 09:00" index="4" temperature="13" weather_code="3" wind_direction="SE" wind_speed="9" />
<data display="Tuesday 12:00" index="5" temperature="14" weather_code="3" wind_direction="SE" wind_speed="11" />
<data display="Tuesday 15:00" index="6" temperature="14" weather_code="3" wind_direction="SE" wind_speed="10" />
<data display="Tuesday 18:00" index="7" temperature="13" weather_code="3" wind_direction="E" wind_speed="9" />
<data display="Tuesday 21:00" index="8" temperature="12" weather_code="2" wind_direction="E" wind_speed="7" />
<data display="Wednesday 00:00" index="9" temperature="12" weather_code="2" wind_direction="E" wind_speed="6" />
<data display="Wednesday" index="10" temperature="15" weather_code="10" wind_direction="NE" wind_speed="8" />
<data display="Wednesday Night" index="11" temperature="10" weather_code="2" wind_direction="W" wind_speed="3" />
<data display="Thursday" index="12" temperature="13" weather_code="10" wind_direction="NW" wind_speed="7" />
<data display="Thursday Night" index="13" temperature="9" weather_code="7" wind_direction="N" wind_speed="6" />
<data display="Friday" index="14" temperature="14" weather_code="3" wind_direction="NW" wind_speed="13" />
<data display="Friday Night" index="15" temperature="7" weather_code="2" wind_direction="SE" wind_speed="9" />
</view>
</site>
</region>
<region region_name="South East England">
<site site_name="London" xpos="219" ypos="250">
<view type="map">
<data display="Monday 21:00" index="0" temperature="18" weather_code="12" wind_direction="W" wind_speed="10" />
<data display="Tuesday 00:00" index="1" temperature="16" weather_code="7" wind_di
rection="SW" wind_speed="7" />
<data display="Tuesday 03:00" index="2" temperature="15" weather_code="2" wind_direction="SW" wind_speed="7" />
<data display="Tuesday 06:00" index="3" temperature="15" weather_code="7" wind_direction="SW" wind_speed="7" />
<data display="Tuesday 09:00" index="4" temperature="16" weather_code="8" wind_direction="SW" wind_speed="9" />
<data display="Tuesday 12:00" index="5" temperature="18" weather_code="8" wind_direction="SW" wind_speed="10" />
<data display="Tuesday 15:00" index="6" temperature="19" weather_code="8" wind_direction="SW" wind_speed="11" />
<data display="Tuesday 18:00" index="7" temperature="19" weather_code="7" wind_direction="SW" wind_speed="10" />
<data display="Tuesday 21:00" index="8" temperature="18" weather_code="2" wind_direction="SW" wind_speed="6" />
<data display="Wednesday 00:00" index="9" temperature="16" weather_code="2" wind_direction="W" wind_speed="5" />
<data display="Wednesday" index="10" temperature="22" weather_code="3" wind_direction="NE" wind_speed="3" />
<data display="Wednesday Night" index="11" temperature="14" weather_code="7" wind_direction="E" wind_speed="6" />
<data display="Thursday" index="12" temperature="17" weather_code="14" wind_direction="NE" wind_speed="7"
/>
<data display="Thursday Night" index="13" temperature="12" weather_code="9" wind_direction="NW" wind_speed="5" />
<data display="Friday" index="14" temperature="21" weather_code="1" wind_direction="NW" wind_speed="8" />
<data display="Friday Night" index="15" temperature="13" weather_code="0" wind_direction="SW" wind_speed="5" />
</view>
</site>
</region>
<region region_name="Strathclyde">
<site site_name="Glasgow International" xpos="116" ypos="99">
<view type="map">
<data display="Monday 21:00" index="0" temperature="14" weather_code="2" wind_direction="E" wind_speed="3" />
<data display="Tuesday 00:00" index="1" temperature="14" weather_code="7" wind_direction="SE" wind_speed="4" />
<data display="Tuesday 03:00" index="2" temperature="13" weather_code="15" wind_direction="E" wind_speed="5" />
<data display="Tuesday 06:00" index="3" temperature="12" weather_code="15" wind_direction="E" wind_speed="7" />
<data display="Tuesday 09:00" index="4" temperature="13" weather_code="15" wind_direction="E" wind_speed="7" />
<data display="Tuesday 12:00" index="5" temperature="14" weather_code="15" wind_direction="E" wind_speed="5" />
<data display="Tuesday 15:00" index="6" temperature="15" weather_code="10" wind_direction="W" wind_speed="11" />
<data display="Tuesday 18:00" index="7" temperature="14" weather_code="8" wind_direction="W" wind_speed="13" />
<data display="Tuesday 21:00" index="8" temperature="13" weather_code="2" wind_direction="W" wind_speed="12" />
<data display="Wednesday 00:00" index="9" temperature="12" weather_code="0" wind_direction="W" wind_speed="11" />
<data display="Wednesday" index="10" temperature="18" weather_code="3" wind_direction="NW" wind_speed="7" />
<data display="Wednesday Night" index="11" temperature="10" weather_code="2" wind_direction="NW" wind_speed="3" />
<data display="Thursday" index="12" temperature="16" weather_code="3" wind_direction="W" wind_speed="7" />
<data display="Thursday Night" index="13" temperature="9" weather_code="2" wind_direction="W" wind_speed="6" />
<data display="Friday" index="14" temperature="17" weather_code="3" wind_direction="W" wind_speed="10" />
<data display="Friday Night" index="15" temperature="12" weather_code="9" wind_direction="S" wind_speed="10" />
</view>
</site>
</region>
<region region_name="South West England">
<site site_name="Exeter" xpos="157" ypos="266">
<view type="map">
<data display="Monday 21:00" index="0" temperature="15" weather_code="7" wind_direction="S" wind_speed="5" />
<data display="Tuesday 00:00" index="1" temperature="14" weather_code="7" wind_direction="S" wind_speed="8" />
<data display="Tuesday 03:00" index="2" temperature="14" weather_code="8" wind_direction="S" wind_speed="8" />
<data display="Tuesday 06:00" index="3" temperature="15" weather_code="7" wind_direction="SW" wind_speed="9" />
<data display="Tuesday 09:00" index="4" temperature="17" weather_code="7" wind_direction="SW" wind_speed="10" />
<data display="Tuesday 12:00" index="5" temperature="20" weather_code="3" wind_direction="SW" wind_speed="10" />
<data display="Tuesday 15:00" index="6" temperature="21" weather_code="7" wind_direction="W" wind_speed="11" />
<data display="Tuesday 18:00" index="7" temperature="19" weather_code="1" wind_direction="NW" wind_speed="10" />
<data display="Tuesday 21:00" index="8" temperature="15" weather_code="0" wind_direction="NW" wind_speed="6" />
<data display="Wednesday 00:00" index="9"
temperature="14" weather_code="2" wind_direction="NW" wind_speed="5" />
<data display="Wednesday" index="10" temperature="18" weather_code="7" wind_direction="E" wind_speed="8" />
<data display="Wednesday Night" index="11" temperature="13" weather_code="9" wind_direction="NE" wind_speed="9" />
<data display="Thursday" index="12" temperature="18" weather_code="3" wind_direction="NE" wind_speed="10" />
<data display="Thursday Night" index="13" temperature="11" weather_code="2" wind_direction="NW" wind_speed="8" />
<data display="Friday" index="14" temperature="21" weather_code="1" wind_direction="W" wind_speed="4" />
<data display="Friday Night" index="15" temperature="12" weather_code="0" wind_direction="SW" wind_speed="6" />
</view>
</site>
</region>
<region region_name="Central, Tayside &amp; F">
<site site_name="Perth" xpos="154" ypos="70">
<view type="map">
<data display="Monday 21:00" index="0" temperature="14" weather_code="2" wind_direction="SW" wind_speed="7" />
<data display="Tuesday 00:00" index="1" temperature="12" weather_code="7" wind_direction="E" wind_speed="2" />
<data display="Tuesday 03:00" index="2" temperature="12" weather_code="7" wind_direction="E" wind_speed="4" />
<data display="Tuesday 06:00" index="
3" temperature="12" weather_code="7" wind_direction="E" wind_speed="6" />
<data display="Tuesday 09:00" index="4" temperature="13" weather_code="7" wind_direction="E" wind_speed="8" />
<data display="Tuesday 12:00" index="5" temperature="14" weather_code="15" wind_direction="E" wind_speed="7" />
<data display="Tuesday 15:00" index="6" temperature="14" weather_code="12" wind_direction="NE" wind_speed="4" />
<data display="Tuesday 18:00" index="7" temperature="14" weather_code="7" wind_direction="W" wind_speed="7" />
<data display="Tuesday 21:00" index="8" temperature="13" weather_code="2" wind_direction="W" wind_speed="9" />
<data display="Wednesday 00:00" index="9" temperature="12" weather_code="2" wind_direction="W" wind_speed="8" />
<data display="Wednesday" index="10" temperature="18" weather_code="3" wind_direction="NW" wind_speed="5" />
<data display="Wednesday Night" index="11" temperature="11" weather_code="2" wind_direction="E" wind_speed="4" />
<data display="Thursday" index="12" temperature="14" weather_code="14" wind_direction="SE" wind_speed="7" />
<data display="Thursday Night" index="13" temperature="10" weather_code="2" wind_direction="W" wind_speed="4" />
<data display="Friday" index="14" temperature="17" weather_code="3" wind_direction="W" wind_speed="8" />
<data display="Friday Night" index="15" temperature="12" weather_code="9" wind_direction="S" wind_speed="8" />
</view>
</site>
</region>
<region region_name="Wales">
<site site_name="Carmarthen" xpos="137" ypos="217">
<view type="map">
<data display="Monday 21:00" index="0" temperature="14" weather_code="13" wind_direction="SW" wind_speed="10" />
<data display="Tuesday 00:00" index="1" temperature="15" weather_code="12" wind_direction="S" wind_speed="13" />
<data display="Tuesday 03:00" index="2" temperature="15" weather_code="15" wind_direction="S" wind_speed="16" />
<data display="Tuesday 06:00" index="3" temperature="16" weather_code="12" wind_direction="SW" wind_speed="13" />
<data display="Tuesday 09:00" index="4" temperature="16" weather_code="7" wind_direction="SW" wind_speed="10" />
<data display="Tuesday 12:00" index="5" temperature="17" weather_code="8" wind_direction="SW" wind_speed="13" />
<data display="Tuesday 15:00" index="6" temperature="18" weather_code="7" wind_direction="NW" wind_speed="11" />
<data display="Tuesday 18:00" index="7" temperature="17" weather_code="3" wind_direction="N" wind_speed="8" />
<data display="Tuesday 21:00" index="8" temperature="14" weather_code="2" wind_direction="W" wind_speed="5" />
<data display="Wednesday 00:00" index="9" temperature="12" weather_code="0" wind_direction="NE" wind_speed="3" />
<data display="Wednesday" index="10" temperature="17" weather_code="7" wind_direction="NE" wind_speed="4" />
<data display="Wednesday Night" inde
x="11" temperature="12" weather_code="7" wind_direction="NE" wind_speed="5" />
<data display="Thursday" index="12" temperature="17" weather_code="10" wind_direction="N" wind_speed="6" />
<data display="Thursday Night" index="13" temperature="9" weather_code="0" wind_direction="NW" wind_speed="6" />
<data display="Friday" index="14" temperature="18" weather_code="1" wind_direction="SW" wind_speed="8" />
<data display="Friday Night" index="15" temperature="15" weather_code="2" wind_direction="SW" wind_speed="14" />
</view>
</site>
</region>
<region region_name="West Midlands">
<site site_name="Birmingham" xpos="182" ypos="210">
<view type="map">
<data display="Monday 21:00" index="0" temperature="15" weather_code="9" wind_direction="SW" wind_speed="7" />
<data display="Tuesday 00:00" index="1" temperature="14" weather_code="9" wind_direction="S" wind_speed="7" />
<data display="Tuesday 03:00" index="2" temperature="13" weather_code="7" wind_direction="SW" wind_speed="8" />
<data display="Tuesday 06:00" index="3" temperature="13" weather_code="7" wind_direction="S" wind_speed="10" />
<data display="Tuesday 09:00" index="4" temperature="15" weather_code="7" wind_direction="SW" wind_speed="12" />
<data display="Tuesday 12:00" ind
ex="5" temperature="19" weather_code="3" wind_direction="SW" wind_speed="14" />
<data display="Tuesday 15:00" index="6" temperature="20" weather_code="3" wind_direction="SW" wind_speed="14" />
<data display="Tuesday 18:00" index="7" temperature="19" weather_code="3" wind_direction="W" wind_speed="12" />
<data display="Tuesday 21:00" index="8" temperature="16" weather_code="2" wind_direction="NW" wind_speed="9" />
<data display="Wednesday 00:00" index="9" temperature="13" weather_code="0" wind_direction="NW" wind_speed="6" />
<data display="Wednesday" index="10" temperature="18" weather_code="7" wind_direction="N" wind_speed="6" />
<data display="Wednesday Night" index="11" temperature="12" weather_code="12" wind_direction="N" wind_speed="6" />
<data display="Thursday" index="12" temperature="17" weather_code="12" wind_direction="N" wind_speed="4" />
<data display="Thursday Night" index="13" temperature="10" weather_code="2" wind_direction="NW" wind_speed="7" />
<data display="Friday" index="14" temperature="20" weather_code="1" wind_direction="W" wind_speed="8" />
<data display="Friday Night" index="15" temperature="13" weather_code="2" wind_direction="SW" wind_speed="6" />
</view>
</site>
</region>
<region region_name="Yorkshire &amp; Humber">
<site site_name="York" xpos="209" ypos="154">
<view type="map">
<data display="Monday 21:00" index="0" temperature="15" weather_code="2" wind_direction="NW" wind_speed="3" />
<data display="Tuesday 00:00" index="1" temperature="14" weather_code="12" wind_direction="SE" wind_speed="3" />
<data display="Tuesday 03:00" index="2" temperature="13" weather_code="15" wind_direction="SE" wind_speed="5" />
<data display="Tuesday 06:00" index="3" temperature="14" weather_code="14" wind_direction="S" wind_speed="8" />
<data display="Tuesday 09:00" index="4" temperature="14" weather_code="12" wind_direction="S" wind_speed="12" />
<data display="Tuesday 12:00" index="5" temperature="16" weather_code="11" wind_direction="S" wind_speed="12" />
<data display="Tuesday 15:00" index="6" temperature="19" weather_code="3" wind_direction="SW" wind_speed="13" />
<data display="Tuesday 18:00" index="7" temperature="17" weather_code="1" wind_direction="W" wind_speed="15" />
<data display="Tuesday 21:00" index="8" temperature="14" weather_code="0" wind_direction="W" wind_speed="12" />
<data display="Wednesday 00:00" index="9" temperature="12" weather_code="0" wind_direction="W" wind_speed="10" />
<data display="Wednesday" index="10" temperature=
"19" weather_code="3" wind_direction="NW" wind_speed="7" />
<data display="Wednesday Night" index="11" temperature="13" weather_code="7" wind_direction="NW" wind_speed="4" />
<data display="Thursday" index="12" temperature="17" weather_code="12" wind_direction="S" wind_speed="4" />
<data display="Thursday Night" index="13" temperature="10" weather_code="9" wind_direction="W" wind_speed="6" />
<data display="Friday" index="14" temperature="19" weather_code="1" wind_direction="W" wind_speed="11" />
<data display="Friday Night" index="15" temperature="13" weather_code="7" wind_direction="SW" wind_speed="5" />
</view>
</site>
</region>
</xml>

Data

The data page shows either a radar image or a satellite image and shows the last 2 hours worth of data in 4 half hour images. The images can be animated to be shown as an animation when the play icon is pressed, or you can swipe left or right to alternate between the radar and satellite views.

Met office app data screen

Behind the scenes a query is sent to http://metip.g-box.tv/data. There is no query string as this is for the whole of the country not just a specific area.

The returned XML shows the images are all date and time stamped, so there is a possibility of a lot of historical weather images being stored in an machine accessible way. Indeed, by changing the value of the month in the image filename, it would appear that at least 6 months worth of images have been stored. The format appears to be either UKRadarYYYYMMDDHHmm.jpg for radar images, or EuropeSatYYYYMMDDHHmm.jpg for satellite images. For example, http://image.metip.g-box.tv:80/UKRadar201108151600.jpg

GET /data HTTP/1.1
Host: metip.g-box.tv
User-Agent: Gorillabox/2011031601.1.3 CFNetwork/485.13.9 Darwin/11.0.0
Accept: */*
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: keep-alive
HTTP/1.1 200 OK
Date: Mon, 15 Aug 2011 18:43:29 GMT
Server: Apache/2.2.12 (Ubuntu)
Content-Length: 1006
X-Catalyst: 5.80031
X-PageCache: Catalyst
Connection: close
Content-Type: application/xml
<?xml version="1.0" encoding="UTF-8"?>
<xml last_updated="15/08/2011 18:00">
<radar>
<image display="Monday 17:00" index="0" url="http://image.metip.g-box.tv:80/UKRadar201108151600.jpg" />
<image display="Monday 17:30" index="1" url="http://image.metip.g-box.tv:80/UKRadar201108151630.jpg" />
<image display="Monday 18:00" index="2" url="http://image.metip.g-box.tv:80/UKRadar201108151700.jpg" />
<image display="Monday 18:30" index="3" url="http://image.metip.g-box.tv:80/UKRadar201108151730.jpg" />
</radar>
<satellite>
<image display="Monday 17:00" index="0" url="http://image.metip.g-box.tv:80/EuropeSat201108151600.jpg" />
<image display="Monday 17:30" index="1" url="http://image.metip.g-box.tv:80/EuropeSat201108151630.jpg" />
<image display="Monday 18:00" index="2" url="http://
image.metip.g-box.tv:80/EuropeSat201108151700.jpg" />
<image display="Monday 18:30" index="3" url="http://image.metip.g-box.tv:80/EuropeSat201108151730.jpg" />
</satellite>
</xml>

Search

The final screen allows you to change the latitude and longitude you want the weather data for by searching for different areas.

Summary

This is a very well thought out app. The majority of the work is handled by the web service with app just handling the display. The web service appears to be custom written by Gorillabox, and is served from a server with their domain name. There doesn’t seem to be any authentication so this API is open to anyone, however the app’s terms and conditions would seem to imply this shouldn’t be the case.

This post applies to version 1.3 of the Met Office iPhone app.

Disabling The Zend Framework ViewRenderer

There are times when using the Zend Framework that you don’t want a view to render.

For example, you may be generating a feed programaticaly, or you may be using a templating engine such as Twig for some or all paths.

By default, the front controller enables the ViewRenderer action helper. It is the job of the ViewRenderer to inject the view object into the controller and to automatically render the view. The idea is that you don’t need to worry about manually instantiating view objects in your controller, the helper does it for you.

It’s actually very simple to disable this behaviour, and there are several ways to do it.

Firstly, if you want to disable this functionality across your application, you could use the following in the application.ini file…

resources.frontController.noViewRenderer = true

This can also be set programatically…

Zend_Controller_Front::getInstance()-&gt;setParam('noViewRenderer', true);

A better approach would be to simply remove the ViewRenderer helper.

$this->_helper->removeHelper('viewRenderer');

If you don’t want the ViewRenderer disabled across your entire application, you can set it locally in a controller…

$this->_helper->viewRenderer->setNoRender(true);