I touched upon yahoo query language (YQL) interface in my last post. Today, I will show some quick practical uses of YQL and demonstrate how easy it is for the programmers to tap into this information.
For today’s example, we will examine the table named ‘weather.forecast’, which is available in the YQL interface.
Head over to the YQL Console to examine the parameters to be used for ‘weather.forecast’.
As shown in the screenshot, there is one parameter named ‘location’ that is required for querying data from this table.
1 |
SELECT * FROM weather.forecast WHERE location="63126" |
The complete URL would look like below:
Windows Phone Application
Create a new ‘Windows Phone Application’ project in Visual Studio.
Preparing the User Interface
The user will provide the location for which the weather forecast is to be displayed as input.
For this, I added a horizontal StackPanel with a TextBox and a Button into the MainPage.xaml.
1 2 3 4 5 |
<TextBlock Text="Enter the zip code:" /> <StackPanel Orientation="Horizontal" Margin="0,0,0,50"> <TextBox Name="locationTextBox" Text="" Width="300"></TextBox> <Button Name="goButton" Content="GO" Width="100" Click="goButton_Click"></Button> </StackPanel> |
For displaying the results, I used a WebBrowser control, as some of the data for ‘weather.forecast’ is returned as HTML.
1 |
<phone:WebBrowser Name="browserControl" Height="300" Visibility="Collapsed" /> |
The XAML listing for the UI is here:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<!--LayoutRoot is the root grid where all page content is placed--> <Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <!--TitlePanel contains the name of the application and page title--> <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> <TextBlock x:Name="ApplicationTitle" Text="WEATHER WATCH" Style="{StaticResource PhoneTextNormalStyle}"/> </StackPanel> <!--ContentPanel - place additional content here--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <StackPanel Grid.Row="0" Grid.Column="0" Orientation="Vertical" Margin="12, 0, 12, 0"> <TextBlock Text="Enter the zip code:" /> <StackPanel Orientation="Horizontal" Margin="0,0,0,50"> <TextBox Name="locationTextBox" Text="" Width="300"></TextBox> <Button Name="goButton" Content="GO" Width="100" Click="goButton_Click"></Button> </StackPanel> <TextBlock Name="titleTextBlock" Text=""></TextBlock> <phone:WebBrowser Name="browserControl" Height="300" Visibility="Collapsed" /> </StackPanel> </Grid> </Grid> |
Getting data from YQL
The user enters the zip code for which weather forecast has to be displayed and press on ‘GO’ button.
The program takes this location, construct the correct URL and make a web request to retrieve the data from the internet.
Windows Phone SDK provides two options to make a web request and get data from the internet, WebClient and HTTPWebRequest. See here for more information.
For this example, I used the WebClient API for it’s inherent simplicity as this is a post more to demonstrate the YQL than about performance.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public void PopulateCurrentConditions(string location) { const string locVariable = "$$LOCATION$$"; string query = "http://query.yahooapis.com/v1/public/yql?q=%20SELECT%20*%20FROM%20weather.forecast%20WHERE%20location%3D%22" + locVariable + "%22%20%20&diagnostics=true"; string url = query.Replace(locVariable, location); // get the currrent conditions from YQL WebClient web = new WebClient(); web.DownloadStringCompleted += new DownloadStringCompletedEventHandler(web_DownloadStringCompleted); web.DownloadStringAsync(new Uri(url)); } |
Since the program did not specify a output format, JQL returns XML by default. The output format can be specified as JSON by adding parameter to the original URL.
Parsing the XML is made simpler by the XDocument class provided in the System.Xml.Linq namespace.
1 2 3 4 5 6 7 |
XDocument doc = XDocument.Parse(e.Result); XElement result = doc.Root.Element("results").Element("channel").Element("item"); if (result == null) return; string title = result.Element("title").Value; string currentConditions = result.Element("description").Value; |
Displaying the results
WebClient returns data on the same thread, so it can directly access the UI elements. On the other hand, HTTPWebRequest returns data on a different thread and the result has to be marshaled back to the UI thread. Since data is returned on a different thread, HTTPWebRequest has the advantage of not locking up the UI thread when it is processing.
1 2 3 4 |
// Update the UI elements // Since the WebClient returns on the same thread, it can access the UI elements directly titleTextBlock.Text = title; browserControl.NavigateToString(currentConditions); |
The complete MainPage.xaml.cs code behind:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using Microsoft.Phone.Controls; using System.Xml; using System.Xml.Linq; namespace WeatherWatch { public partial class MainPage : PhoneApplicationPage { // Constructor public MainPage() { InitializeComponent(); } private void goButton_Click(object sender, RoutedEventArgs e) { if (locationTextBox.Text.Length == 0) return; browserControl.Visibility = System.Windows.Visibility.Visible; browserControl.NavigateToString("Loading..."); PopulateCurrentConditions(locationTextBox.Text); } public void PopulateCurrentConditions(string location) { const string locVariable = "$$LOCATION$$"; string query = "http://query.yahooapis.com/v1/public/yql?q=%20SELECT%20*%20FROM%20weather.forecast%20WHERE%20location%3D%22" + locVariable + "%22%20%20&diagnostics=true"; string url = query.Replace(locVariable, location); // get the currrent conditions from YQL WebClient web = new WebClient(); web.DownloadStringCompleted += new DownloadStringCompletedEventHandler(web_DownloadStringCompleted); web.DownloadStringAsync(new Uri(url)); } void web_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { XDocument doc = XDocument.Parse(e.Result); XElement result = doc.Root.Element("results").Element("channel").Element("item"); if (result == null) return; string title = result.Element("title").Value; string currentConditions = result.Element("description").Value; // Update the UI elements // Since the WebClient returns on the same thread, it can access the UI elements directly titleTextBlock.Text = title; browserControl.NavigateToString(currentConditions); } } } |