Mobile Zone is brought to you in partnership with:

Den is a DZone Zone Leader and has posted 460 posts at DZone. You can read more from them at their website. View Full User Profile

Getting The Flights Above You, And Much More, On Windows Phone, With WolframAlpha

04.30.2012
| 3007 views |
  • submit to reddit

The reason I like WolframAlpha is because it is a "knowledge engine" that can give quick insights in a multitude of topics. Specifically, the most interesting part for me is related getting a list of flights that are currently above me. So here is how to track flights that are above you from inside a Windows Phone application, with the help of WolframAlpha API. Of course, this sample is built in such a way that you can easily adapt it to any input query - I just like tracking flights.

The first thing you need to do is head over to https://developer.wolframalpha.com/portal/myapps/ and get an AppID.

NOTE: Also, download the API guide.

The structure of the request is quite simplistic. All requests are executed against one endpoint:

http://api.wolframalpha.com/v2/query?input=YOUR QUERY&appid=0000-000000

The returned data is in XML format and is structured in nodes, called pods. For example, let's take a look at a query about planes that are currently above me:

http://api.wolframalpha.com/v2/query?input=planes over me right now&appid=0000-000000

This will return an XML file that looks somewhat like this:

<?xml version='1.0' encoding='UTF-8'?>
<queryresult success='true'
    error='false'
    numpods='3'
    datatypes='Flight'
    timedout=''
    timedoutpods=''
    timing='2.556'
    parsetiming='0.343'
    parsetimedout='false'
    recalculate=''
    id='MSPa50291a18174ad9dd8i5100004b9gia4chgd2h5b5'
    host='http://www4b.wolframalpha.com'
    server='12'
    related='http://www4b.wolframalpha.com/api/v2/relatedQueries.jsp?id=MSPa50301a18174ad9dd8i5100004id6id1d223f71a8&s=12'
    version='2.5'>
 <pod title='Result'
     scanner='Data'
     id='Result'
     position='200'
     error='false'
     numsubpods='1'
     primary='true'>
  <subpod title=''>
   <plaintext> | altitude | angle
Southwest Airlines flight 573 | 41000 feet | 14 degrees up
American Airlines flight 1799 | 34000 feet | 11 degrees up
Frontier Airlines flight 231 | 38000 feet | 11 degrees up
Atlantic Southeast Airlines flight 4641 | 36000 feet | 9.4 degrees up
AirTran Airways flight 443 | 30700 feet | 8.3 degrees up
 | type | slant distance
Southwest Airlines flight 573 | Boeing 737-700 | 31 miles east
American Airlines flight 1799 | McDonnell Douglas MD-83 | 34 miles east-northeast
Frontier Airlines flight 231 | Airbus A319 | 38 miles east-northeast
Atlantic Southeast Airlines flight 4641 | Embraer EMB-145XR | 40 miles north
AirTran Airways flight 443 | Boeing 717-200 | 39 miles west
(locations based on projections of delayed data)
(angles with respect to nominal horizon)</plaintext>
   <img src="http://www4b.wolframalpha.com/Calculate/MSP/MSP50321a18174ad9dd8i5100005e0c7g4i3cigh14b?MSPStoreType=image/gif&s=12"
       alt=' | altitude | angle
Southwest Airlines flight 573 | 41000 feet | 14 degrees up
American Airlines flight 1799 | 34000 feet | 11 degrees up
Frontier Airlines flight 231 | 38000 feet | 11 degrees up
Atlantic Southeast Airlines flight 4641 | 36000 feet | 9.4 degrees up
AirTran Airways flight 443 | 30700 feet | 8.3 degrees up
 | type | slant distance
Southwest Airlines flight 573 | Boeing 737-700 | 31 miles east
American Airlines flight 1799 | McDonnell Douglas MD-83 | 34 miles east-northeast
Frontier Airlines flight 231 | Airbus A319 | 38 miles east-northeast
Atlantic Southeast Airlines flight 4641 | Embraer EMB-145XR | 40 miles north
AirTran Airways flight 443 | Boeing 717-200 | 39 miles west
(locations based on projections of delayed data)
(angles with respect to nominal horizon)'
       title=' | altitude | angle
Southwest Airlines flight 573 | 41000 feet | 14 degrees up
American Airlines flight 1799 | 34000 feet | 11 degrees up
Frontier Airlines flight 231 | 38000 feet | 11 degrees up
Atlantic Southeast Airlines flight 4641 | 36000 feet | 9.4 degrees up
AirTran Airways flight 443 | 30700 feet | 8.3 degrees up
 | type | slant distance
Southwest Airlines flight 573 | Boeing 737-700 | 31 miles east
American Airlines flight 1799 | McDonnell Douglas MD-83 | 34 miles east-northeast
Frontier Airlines flight 231 | Airbus A319 | 38 miles east-northeast
Atlantic Southeast Airlines flight 4641 | Embraer EMB-145XR | 40 miles north
AirTran Airways flight 443 | Boeing 717-200 | 39 miles west
(locations based on projections of delayed data)
(angles with respect to nominal horizon)'
       width='495'
       height='524' />
  </subpod>
  <states count='2'>
   <state name='More'
       input='Result__More' />
   <state name='Show metric'
       input='Result__Show metric' />
  </states>
 </pod>
</queryresult>

At first it might seem that you are getting a whole bunch of unusable garbage, however if you look closer, you will notice that the data is very well structured. Each container (pod) carries a descriptive name, a plaintext representation of the requested data as well as a generated image.

It is worth mentioning, that even though XML represents the main skeleton, data can be obtained in various representation formats. For example, if I would want to get HTML data, or images that are mapped by section (imagemap), I can add a format parameter. For example:

http://api.wolframalpha.com/v2/query?input=planes over me right now&appid=0000-000000&format=html

As a sample part of the response, you will get a CDATA-wrapped node:

<pod title='Input interpretation'
     scanner='Identity'
     id='Input'
     position='100'
     error='false'
     numsubpods='0'>
  <markup><![CDATA[<div id="pod_0100" class="pod "><hr class="top" /><h2>Input interpretation:</h2><div id="subpod_0100_1" class="sub "width="413"width="413"><div class="output pnt" id="scannerresult_0100_1"><img height="39"width="413" src="http://www4b.wolframalpha.com/Calculate/MSP/MSP32331a181999971gg24g0000184dig7311dc929e?MSPStoreType=image/gif&s=11&w=413&h=39" id="i_0100_1" alt="flights seen from current geoIP location | current time" title="flights seen from current geoIP location | current time"  data-attribution="" /></div><div class="annotpod">
	</div></div>
<hr class="bot" /></div>]]></markup>
 </pod>

Let's start with the easiest data representation response - raw XML. I built a test Windows Phone application that is composed of a single page, that has a TextBox control to accept user input and a ListBox to show the results. When the query is executed, I am attempting to deserialize the data in a QueryResult model.

[XmlRoot("queryresult")]
public class QueryResult
{
    [XmlElement("pod")]
    public ObservableCollection<Pod> Pods { get; set; }
}

The Pod class:

public class Pod
{
    [XmlAttribute("title")]
    public string Name { get; set; }
    [XmlElement("subpod")]
    public ObservableCollection<SubPod> SubPods { get; set; }
}

For all most common scenarios there will only be one subpod, but for compatibility purposes I decided to make it a collection and ensure that if there will be more, the application won't break.

The SubPod class:

public class SubPod
{
    [XmlElement("plaintext")]
    public string Plaintext { get; set; }
    [XmlElement("img")]
    public WImage Image { get; set; }
}

WImage (stands for WolframImage) is a class that is used purely for serialization convenience, in order to be able to easily read attribute data from the image node for the associated subpod.

public class WImage
{
    [XmlAttribute("src")]
    public string Location { get; set; }
}

The data is obtained and serialized by using the stock .NET XML serializer:

WolframAlpha.SendInput(txtInput.Text, result =>
    {
        XmlSerializer serializer = new XmlSerializer(typeof(QueryResult));
        TextReader reader = new StringReader(result);

        Binder.Instance.CurrentQueryResult = serializer.Deserialize(reader) as QueryResult;
        Debug.WriteLine(result);
    });

Here is where it gets interesting. The obtained data is nothing if it cannot be shown to the user. However, there is one small limitation - Windows Phone does not support GIF images out-of-the-box. To bind the image to the UI, I need to either use a third-party library to covert the data, use a service, or use a WebBrowser that will load the image. I chose the last option.

<ListBox ItemsSource="{Binding Path=Instance.CurrentQueryResult.Pods,Source={StaticResource Binder}}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Style="{StaticResource PhoneTextLargeStyle}" Text="{Binding Name}"></TextBlock>
                <ListBox ItemsSource="{Binding SubPods}">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel>
                                <TextBlock Text="{Binding Name}"></TextBlock>
                                <phone:WebBrowser Margin="12" Width="400" Height="400"  Tag="{Binding Image.Location}" Loaded="WebBrowser_Loaded"></phone:WebBrowser>
                            </StackPanel>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

When the WebBrowser control is loaded, I am able to use NaviagateToString to load the images:

private void WebBrowser_Loaded(object sender, RoutedEventArgs e)
{
    string location = ((WebBrowser)sender).Tag.ToString();
    ((WebBrowser)sender).NavigateToString("<img style=\"width: 100%;\" src=\"" + location + "\" />");
}

NOTE: Remember that the control itself has a Tag property, that is set to the image location. That way it is really easy to see which of the WebBrowser elements is responsible for what image.

You end up with an UI like this:

Of course, you can apply more restrictions to the WebBrowser control itself, like limited zoom and scrolling. In its current configuration, it does its basic job pretty well - consider this a proof of concept.

You can download the sample here (code + XAP).