連載:VS 2005 Expressプログラミング

第2回 livedoor提供のお天気WebサービスをC#で使う

デジタルアドバンテージ 遠藤 孝信
2006/06/28
Page1 Page2 Page3 Page4

■XMLデータの取得と解析

連載:.NETで簡単XML

 .NET Frameworkのクラス・ライブラリにはXMLデータを扱う方法がいくつか用意されています。ここでは、取得したXMLデータから特定の位置にあるデータを抜き出すだけなので、最もシンプルに実装できるXmlDocumentクラス(System.Xml名前空間)を使います。

 このクラスを使えば、XMLデータの取得と解析は非常に簡単です。例えば、お天気Webサービスから次のようなXMLデータが返ってくる場合、

<?xml version="1.0" encoding="UTF-8" ?>
<lwws version="livedoor Weather Web Service 1.0">
  <author>livedoor Weather Team.</author>
  <location area="関東" pref="東京都" city="東京" />
  <title>東京都 東京 - 今日の天気</title>
  …以下省略…
お天気Webサービスから返されるXMLデータの先頭部分

 次のようなコードだけで、<title>タグ内のデータが取得できます。

string _title;

XmlDocument doc = new XmlDocument();
doc.Load(lwwsUrl);
_title =
  doc.DocumentElement.SelectSingleNode("/lwws/title").InnerText;
お天気Webサービスにアクセスし<title>タグの内容を取得するコード

 Loadメソッドでは、XMLデータのあるURLをパラメータに指定するだけで、ネットワークからの読み込みが行われます。また、最後の行の「/lwws/title」は、<lwws>タグ内の<title>タグを示しています。ちなみに、このようなスラッシュで区切った形式で特定のタグを指定する構文はXPathと呼ばれます。

 同様にして、必要なタグ部分をXPathで指定して取得し、各フィールドに設定していきます。Refreshメソッドの の「XMLデータの取得と解析」部分は最終的には次のようなコードとなります。

// XMLデータの取得と解析
XmlDocument doc = new XmlDocument();
try {
  doc.Load(lwwsUrl);
} catch {
  return;
}
_title = doc.DocumentElement.SelectSingleNode
                               ("/lwws/title").InnerText;
_tenki = doc.DocumentElement.SelectSingleNode
                               ("/lwws/image/title").InnerText;
_link = doc.DocumentElement.SelectSingleNode
                               ("/lwws/image/link").InnerText;
string imageURL = doc.DocumentElement.SelectSingleNode
                               ("/lwws/image/url").InnerText;
string pt = doc.DocumentElement.SelectSingleNode
                              ("/lwws/publictime").InnerText;
_publicTime = DateTime.Parse(pt);
Refreshメソッドの 「XMLデータの取得と解析」部分のコード
お天気Webサービスから取得したXMLデータから必要なデータを取り出し、フィールドに設定しておく。

 PCがネットワークに接続されていない場合などは、Loadメソッドで例外が発生する可能性があるためtry-catch構文が必要になります。もし例外が発生した場合には何もせずにリターンします。Refreshメソッドでは、最初に_availableフィールドにfalseを代入しているので、この場合にはAvailableプロパティはfalseを返します。

 上記のコードでは、変数imageURLには今日の天気を示すGIF画像のURLが入ります。続いてはこのURLから、タスクトレイ・アイコン用のアイコンを作成する部分を作ります。

■天気アイコンの作成

 今日の天気を示すGIF画像は、実際にはlivedoor天気情報のページで表示されているような、50×31ピクセルの画像です。

 一方、タスクトレイ・アイコンで表示できるアイコンの画像は、16×16ピクセルのサイズです。また、アイコンは.NETではIconクラス(System.Drawing名前空間)のオブジェクトとなります。

 ここでは、GIF画像を示すURLを受け取り、その画像をダウンロードしてから、それをアイコンのサイズに縮小しIconオブジェクトを作成する処理を次のような1つのメソッドにまとめました。

Icon makeIconFromLWWSGif(string url)
{
  // GIF画像を示すビットマップ
  Bitmap origBitmap;

  // タスクトレイ・アイコンを示すビットマップ
  // (サイズは16×16)
  Bitmap iconBitmap = new Bitmap(16, 16);

  // GIF画像を取得してビットマップを作成
  using (WebClient wc = new WebClient()) {
    Stream st;
    try {
      st = wc.OpenRead(url);
    } catch {
      return null;
    }
    origBitmap = (Bitmap)Bitmap.FromStream(st);
  }

  // GIF画像の中央部分のみをアイコンに描画
  Rectangle src = new Rectangle(
    10, 0, origBitmap.Width - 18, origBitmap.Height);
  int height = src.Height * 16 / src.Width;
  Rectangle dest = new Rectangle(0, (16 - height) / 2, 16, height);

  using (Graphics g = Graphics.FromImage(iconBitmap)) {
    g.Clear(Color.White);
    g.DrawImage(origBitmap, dest, src, GraphicsUnit.Pixel);
    origBitmap.Dispose();
  }

  // BitmapオブジェクトからIconオブジェクトを作成
  Icon icon = Icon.FromHandle(iconBitmap.GetHicon());

  origBitmap.Dispose();
  iconBitmap.Dispose();

  return icon;
}
URLで指定されたGIF画像から16×16のIconオブジェクトを作成するメソッド

 取得したGIF画像を単に縮小するだけでは小さすぎてよく分からないアイコンになってしまいますので、ここではGIF画像の中央部分だけを抜き出して16×16のサイズに縮小しています(抜き出す部分の座標やサイズは筆者の試行錯誤の結果です)。

■天気アイコンのキャッシュ

 ところで、お天気Webサービスから返される天気(「晴れ」「曇り」「曇時々雨」など)には全部で十数種類しかありません。にもかかわらず、Refreshメソッドが呼び出されるたびに、上記のmakeIconFromLWWSGifメソッドを呼び出してIconオブジェクトを作成していてはメモリ・リソースと時間の無駄になります。

 そこで、すでに作成したIconオブジェクトを保存しておいて使い回せるようにしておきましょう。つまり、一度「晴れ」に対する「晴れ用Iconオブジェクト」を作ったら、次から「晴れ」の場合には新たにアイコンを作成せずに、すでに作ったIconオブジェクトを使うようにします。

ハッシュテーブル(連想配列)を使うには?(Dictionaryクラス編)
C#&VBジェネリック超入門:ジェネリック・クラスで変わるC#とVBのコレクション

 このような用途には「ハッシュテーブル」と呼ばれるデータ構造が便利です。具体的にはキーと値のコレクションであるDictionaryクラス(System.Collections.Generic名前空間)を使います。

 まず、LWWSクラスのコンストラクタでDictionaryクラスのインスタンスを作成しておきます。

IconCache = new Dictionary<string, Icon>();

 そして、先ほどのRefreshメソッドの の「アイコンの作成」部分は次のようになります。

// アイコンの作成
if (IconCache.ContainsKey(_tenki)) {
  // すでに作成済み
  _icon = IconCache[_tenki];
} else {
  _icon = makeIconFromLWWSGif(imageURL);
  if (_icon == null) {
    return;
  }
  // 新規追加
  IconCache[_tenki] = _icon;
}
Refreshメソッドの 「アイコンの作成」部分のコード
ハッシュテーブルに存在しない場合にのみmakeIconFromLWWSGifメソッドを呼び出してIconオブジェクトを作成する。

 Dictionaryクラスの使い方については上記の関連記事を参考にしてください。以上でLWWSクラスの実装は完了です。

■LWWSクラスのテスト

 それではさっそくLWWSクラスを使ってタスクトレイ・アイコンに天気を表示してみましょう。フォームのコンストラクタであるWebFormメソッドに以下のコードを記述します。

public WebForm()
{
  InitializeComponent();
  notifyIcon1.Icon = SystemIcons.Question;

  LWWS lwws = new LWWS(63); // 63:東京
  lwws.Refresh();

  notifyIcon1.Icon = lwws.Icon;
  webBrowser1.Navigate(lwws.Link);
}
LWWSクラスを使って天気アイコンを表示するコード

 最後の行では「lwws.Link」により天気情報ページのURLを取得し、フォームに配置しているWebBrowserコントロールでそのページを表示するようにもしています。

 実行すると、タスクトレイの「?」マーク・アイコンがしばらくして天気のアイコンに変わり、フォームが現れてlivedoor天気情報のページが表示されれば成功です。今回はここまでにしておきましょう。

 なお、C# Expressでは明示的な保存を行うまでは、プロジェクトの内容は一時ディレクトリにしか作成されておらず、一度もプロジェクトを保存せずにC# Expressを強制終了させたりすると、作業内容がすべて失われてしまいます。そんな目に遭わないように、適当なタイミングで[ファイル]メニューの[すべてを保存]を実行して、プロジェクトを保存するようにしてください。

 次回では残りの部分のプログラミングを行い、「今日の天気」アプリを完成させる予定です。

 

 INDEX
  VS 2005 Expressプログラミング
  第2回 livedoor提供のお天気WebサービスをC#で使う
    1.プロジェクトの作成
    2.フォームの設定/タスクトレイ・アイコン
    3.livedoor提供の「お天気Webサービス」
  4.XMLデータの取得と解析/天気アイコンの作成
 
インデックス・ページヘ  「VS 2005 Expressプログラミング」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間