Před pár dny jsem se dostal do situace, kdy jsem potřeboval najít nějakou webovou službu, ze které bych získaval informace o aktuálním počasí. Webovou službu jsem bohužel nenašel a tak jsem se musel spokojit s RSS kanálem od yahoo weather. Tak jsem se pustil tedy do hraní s xml souborem a proto jsem neváhal využít LINQu ( konečně jsem se k němu aspoň trošku dostal :-) ). Díky LINQ jsem si potřebné data zjistil za chvilku a mohl přejít k závěrečné fázi, zobrazení aktuálního počasí na mapě. Nyní máte přehled o tom, s čím jsem si hrál a proto se na to už můžeme podívat detailněji:

Yahoo Weather:

základní URL adresa RSS kanálu je http://weather.yahooapis.com/forecastrss . K této adrese je možné připojit dva parametry:

  • p pro specifikaci města
  • u pro stupně (Fahrenheit(f) nebo Celsius(c) )

zašleme-li požadavek ve tvaru http://weather.yahooapis.com/forecastrss?p=EZX0009&u=c , odpovědí nám bude xml soubor ve kterém nalezneme potřebné informace o aktuálním počasí v Ostrava. Popíšu zde pouze elementy, které jsem využíbal. Ostatní informace naleznete na http://developer.yahoo.com/weather

  • Channel elements
    • yweather:location - obsahuje atributy které popisují danou oblast
      • city - název města
      • region - stát (v USA), oblast, region
      • country - 2 znakový kód země
    • yweather:astronomy - obsahuje atributy popisující východ a západ slunce
      • sunrise - východ slunce
      • sunset - západ slunce
  • Item elements
    • geo:lat - zeměpisná šířka
    • geo:long - zeměpisná délka
    • yweather:condition - obsahuje atributy popisující aktuální počasí
      • text - textový popis počasí např. "jasno"
      • code - číselný kód textové popisu počasí
      • temp - aktuální teplota
      • date - aktuální datum
    • description -  text + temp + url obrázku

Vytvořil jsem si tedy třídu City, která obsahuje pouze vlastnosti uchovávající požadované hodnoty o aktuálním počasí v daném městě

public class City
{
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private string m_Description;
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private string m_Code;

    public string Name { get; set; }
    public string Region { get; set; }
    public string Country { get; set; }
    public string Sunrise { get; set; }
    public string Sunset { get; set; }
    public double Lat { get; set; }
    public double Lon { get; set; }
    public string ConditionText { get; set; }
    public double Temp { get; set; }
    public string Date { get; set; }
    public string ImageSource { get; set; }
    public string CurrentConditions { get; set; }
    public string Code
    {
        get { return m_Code; }
        set { m_Code = value; }
    }
    public string Description
    {
        set
        {
            m_Description = value;
            string pom = m_Description.Remove(0, m_Description.IndexOf('"') + 1);
            ImageSource = pom.Remove(pom.IndexOf('"'));
            string currConditions = pom.Remove(0, m_Description.IndexOf("</b><br />"));
            CurrentConditions = currConditions.Remove(currConditions.IndexOf("<BR />"));
        }
    }
}
a třídu Weather, ve které jsem využil již zmiňovaný LINQ to XML :-). Třída obsahuje "zatím" dvě metody
City GetWeatherByCity(string name)

Metodě předám url adresu konkrétního města (např. viz výše url pro Ostravu) a vytvořím si instanci třídy XDocument

XDocument xmlSource = XDocument.Load(name);

nesmím zapomenout na definici namespace, které xml využívá

XNamespace yweather = "http://xml.weather.yahoo.com/ns/rss/1.0";
XNamespace geo = "http://www.w3.org/2003/01/geo/wgs84_pos#";

nyní můžu provést dotaz na xml soubor a všechny potřebné hodnoty si držím v mém anonymním tyou, který jsem si vytvořil v konstrukci příkazu select

var elements = xmlSource.Descendants("channel").Select(delegate(XElement c)
{
       return new
          {
              city = c.Element((XName) (yweather + "location")).Attribute("city").Value,
              region = c.Element((XName) (yweather + "location")).Attribute("region").Value,
              country = c.Element((XName) (yweather + "location")).Attribute("country").Value,
              sunrise = c.Element((XName) (yweather + "astronomy")).Attribute("sunrise").Value,
              sunset = c.Element((XName) (yweather + "astronomy")).Attribute("sunset").Value,
              lat = c.Element("item").Element((XName) (geo + "lat")).Value,
              lon = c.Element("item").Element((XName) (geo + "long")).Value,
              conditionText =
                  c.Element("item").Element((XName) (yweather + "condition")).Attribute("text").Value,
              code = c.Element("item").Element((XName) (yweather + "condition")).Attribute("code").Value,
              temp = c.Element("item").Element((XName) (yweather + "condition")).Attribute("temp").Value,
              date = c.Element("item").Element((XName) (yweather + "condition")).Attribute("date").Value,
              description = new XCData(c.Element("item").Element("description").Value)
          };
 });

poté jednoduše projdu "elements", naplním vlastnosti třídy City a vrátím výsledek

foreach (var c in elements)
{
    city = new City
       {
           Name = c.city,
           Region = c.region,
           Country = c.country,
           Sunrise = c.sunrise,
           Sunset = c.sunset,
           Lat = c.lat,
           Lon = c.lon,
           ConditionText = c.conditionText,
           Code = c.code,
           Temp = c.temp,
           Date = c.date,
           Description = c.description
       };
}
public List<City> GetWeatherInCities(Dictionary<string, string> cities)
{
    List<City> list = new List<City>();
    foreach (KeyValuePair<string, string> city in cities)
    {
        list.Add(this.GetWeatherByCity(city.Value));
    }
    return list;
}

Nyní si už stačí vytvořit pouze jednoduchou stránku, na které si aktuální počasí zobrazíme. Do hlavičky stránky přidáme tyto řádky

<script type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6"></script>  - virtual earth
<script type="text/javascript" src="JScript.js"></script> - muj js

V metodě PageLoad, si vytvořím generický slovník, kde klíčem bude název města a hodnotou url adrea na yahoo weather. Takto vytvořený slovník předám jako parametr již známé metodě GetWeatherInCities. Výsledkem bude list, který si poté projdu v cyklu foreach a základní informace o počasí v daném městě zobrazím v "pomocném" listboxu

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        weather = new YahooWeatherRssLibrary.Weather();
        cities = new Dictionary<string, string>();
        cities.Add("Opava", @"http://weather.yahooapis.com/forecastrss?p=EZXX0008&u=c");
        cities.Add("Ostrava", @"http://weather.yahooapis.com/forecastrss?p=EZXX0009&u=c");
        cities.Add("Praha", @"http://weather.yahooapis.com/forecastrss?p=EZXX0012&u=c");
        cities.Add("Brno", @"http://weather.yahooapis.com/forecastrss?p=EZXX0002&u=c");
        cities.Add("Karvina", @"http://weather.yahooapis.com/forecastrss?p=EZXX0005&u=c");
        cities.Add("Kladno", @"http://weather.yahooapis.com/forecastrss?p=EZXX0006&u=c");
        cities.Add("Cheb", @"http://weather.yahooapis.com/forecastrss?p=EZXX0017&u=c");
        cities.Add("Liberec", @"http://weather.yahooapis.com/forecastrss?p=EZXX0023&u=c");
        cities.Add("Pribyslav", @"http://weather.yahooapis.com/forecastrss?p=EZXX0025&u=c");
        cities.Add("Plzen", @"http://weather.yahooapis.com/forecastrss?p=EZXX0010&u=c");
        cities.Add("Tabor", @"http://weather.yahooapis.com/forecastrss?p=EZXX0015&u=c");

        foreach (City c in weather.GetWeatherInCities(cities))
        {
            this.ListBox1.Items.Add(string.Format("{0}|{1}|{2}|{3}|{4}",
                c.Name, c.CurrentConditions, c.Lat, c.Lon, c.ImageSource));
        }
    }
}

V sekci Body, mám ovšem ještě definovanou JS funkci, která se provede rovněž při "onLoad" a vypadá následovně:

function GetMap()
{
    map = new VEMap('myMap'); // vytvořím si instanci pojmenovanou myMap         
    map.LoadMap(new VELatLong(50.11001070896013, 14.567871093749987), 6 ,'h' ,false); // zavolám metodu LoadMap, které předám konkrétní parametry, nejdůležitější jsou souřadnice (VELatLon), které zobrazí ve středu mapy město Praha
    map.SetMapStyle(VEMapStyle.Aerial); // styl mapy nastavím na letecký pohled
    map.HideDashboard(); // a zneviditelním navigační panel
}  

Na mé stránce se nachází ještě tlačítko "Show weather" s definovanou událostí onclick="Add('ListBox1')":

function Add(ListBox)
{
    var lb = document.getElementById(ListBox);
    var i = 0;
    while(lbIdea != null)
    {
       // v cyklu si projdu jednotlivé položky v listboxu a jejich textovou hodnotu rozdělím podle znaku " | ", poté zavolám metodu AddPushpin s příslušnými parametry
       var pom = lbIdea.outerText.split('|');
       AddPushpin(pom[0], pom[1], pom[2], pom[3], pom[4]);
       i++;
    }
}function AddPushpin(title, description, lat, lon, img)
{
    var shape = new VEShape(VEShapeType.Pushpin, new VELatLong(lat, lon)); // vytvořím si nový tvar s parametrem pushpin (chci označit pouze jediné místo) a s parametry lat a lon, které jsou parametry metody
    shape.SetTitle(title); // nastavím titul na název města
    shape.SetDescription(description); // popisem bude aktuální počasí
    shape.SetCustomIcon(img); // lze nastavit i vlastní ikonu, proto využiju tuto možnost a jako ikonu volím obrázek získaný z yahoo weather
    map.AddShape(shape); // přidám nový tvar na mapu
}

Tak a to je vše, třeba se to někomu bude hodit :-) Nejsou to nějaké převratné věci, ale jak říkám, v dlouhých nudných večerech jsem si pouze hrál :-) Na to jak to funguje se můžete podívat zde http://lucas.aspone.cz/Weather.aspx