天気情報を表示する1(基本編)

ウィジェットの定番の1つに「天気予報」があります。
しかし、海外のウィジェットしか見たことがありません。
そのせいなのか、天気の表示も見慣れたパターンしかありません。
せっかく、ウィジェットを作ることを紹介しているので、天気予報もやろうと思います。

天気情報の取得にもいろいろありますが、取得した天気情報によって、表示のレイアウトもいろいろ考えることができます。(考えなければなりません)
ここでは、天気情報の取得方法をメインに紹介します。

天気情報を取得する

天気情報を取得する方法はいくつかありますが、ここでは天気情報を配信しているサーバーからXMLを取得し、表示する方法を紹介します。
個人的な判断ですが、このやり方を「基本」とします。

Webサイトではピンポイント天気まで表示できるのに、情報配信は主要都市までというところがほとんどですので、ピンポイント天気を開いた状態のWebサイトから、直接情報を取得するやり方もどこかで紹介します。

いきなり取得してみる

早速、天気情報を取得してみましょう。
当サイト「都市コード」を参考にして、パソコンのブラウザで、以下のURLを開いて下さい。

http://weather.yahooapis.com/forecastrss?p=JAXX0005&u=c

北海道旭川市の天気情報が表示されましたでしょうか?
お分かりかと思いますが、Yahooウェザーの天気情報で、温度を摂氏で指定して取得しています。
URLに、都市コード「JAXX0005」を指定していますが、都市コードの部分はお好みで変更して下さい。

ただし、その表示方法はブラウザによって違います
それこそ、「天気情報の取得先によって情報が違う」という事実もあります。
情報が変われば、表示方法も変わりますので、天気情報表示ウィジェットを進めながら対応していきます。

取得した情報を見てみる

天気情報なるものが取得できることは分かりました。
そして、その情報をブラウザで確認することもできました。
ただ、情報自体はどうなってるのでしょうか?
情報をブラウザで見ようとしても、勝手にブラウザが整形してしまうので、取得した情報がどのような形で取得できるのか、確認することができません。
そこで、取得した天気情報をそのまま表示するサンプルを作ったのですが、その前に、イメージだけでも掴んでおいて欲しいので、以下のページを開いてみて下さい。

http://weather.livedoor.com/forecast/webservice/rest/v1?city=113&day=tomorrow

ライブドア提供による、翌日の久留米の天気情報です。
データと言っても、文字化けしたような感じではありませんね。
データ構造を理解すれば、人間が読み取ることも容易い内容かと思います。
これがXMLです。
イメージだけでも掴んでおいて下さい。

では、先程のYahooウェザー天気情報のXMLはどうなっているのでしょうか。
取得した天気情報をそのまま表示するサンプルを作ったので、ダウンロードしてLockBackground.htmlを開いてみて下さい。

右の画像は、そのスクリーンショットの一部です。
パソコンでもiPhoneでも見ることができます。
iPhoneでは、テーマとしてWinterboardで適用すると、ロック画面に表示されるファイル構造になっております。
ダウンロードはこちら ー> wf_11のダウンロード
ブラウザ表示はこちら ー> wf_11の表示


情報提供元によって、XMLの構造に違いはあるものの、データを見ることで、何となくでも分かることができれば、それでOKです。

取得方法を知る

さきほどのサンプルで、取得した天気情報XMLをそのまま表示しましたが、その中の取得方法を抜き出して説明します。個別で調べたい方は「ajax」でググって下さい。

LockBackground.htmlには、"data"というidを持つpタグを用意しました。
読み込み後に、JavaScriptファイルに記述してあるsetWeatherという関数を実行します。
HTMLファイルはこれくらいです。

では、JavaScriptファイル(script.js)の、setWeather()を見て行きましょう。

var url="http://weather.yahooapis.com/forecastrss?p=JAXX0005&u=c";

urlという文字列変数に、いきなり取得したURLを入れています。
後から出てきますが、情報を要求する行がやたら長くなってしまうので、その対応にもなりますし、都市コードを書き換える場所が分かりやすくなるという利点もあり、このようにしました。

var httpRequest = new XMLHttpRequest();

このXMLHttpRequest()が、今回の最大の情報です。
XMLHttpRequestは、サーバとの通信を行うための組み込みオブジェクトですので、これを使って、サーバーから情報を得ることにします。
すでに、天気情報を表示する何らかのウィジェットを使っている方は、ソースを眺めてみて下さい。ソースのどこかにXMLHttpRequestがあると思います。
今回は、このオブジェクトをhttpRequestに格納しているので、この先はxml_requestに対して処理をします。

httpRequest.open("GET", url);

urlで指定されているサーバーURLに対し、リクエストの初期化・設定を行ないます。
今回は、データの取得が目的なので、"GET"としていますが、ここではまだ、サーバーに対するリクエストは行いません。

httpRequest.overrideMimeType("text/xml");

サーバーから返ってくるMIMEタイプを強制的にtext/xmlとします。
サーバーがどのようなMIMEタイプで返すか分からなくても、このように記述しておけば安心できるため、私はこうしています。

httpRequest.setRequestHeader('Cache-Control', 'no-cache');

ブラウザ内のキャッシュデータが取得されてしまい、最新の情報が取得できない可能性があるため、このような記述をし、キャッシュ読み込みを回避します。

httpRequest.send(null);

これまでは設定でしたが、ここにきてやっとサーバーにリクエストを送信します。
情報を得るだけなので、ここで送信するデータはありません。
サンプルではnullを入れていますが、空文字列の""でも構いません。

httpRequest.onload = function() {xml_responded(httpRequest);}

今回は、取得したデータをそのまま表示することにしましたので、レスポンスデータの読込みが完了した時に、データを表示する関数を呼び出します。

function xml_responded (request) {
 var resData = request.responseText;
 document.getElementById("data").innerText = resData;
}

こちらが、その関数です。
読み込みが完了してから実行される関数なので、データがあるかどうか関係なく処理をします。
リクエストによって得られたレスポンスをテキスト形式で取得しますが、一度resDataに格納します。
"data"というidを持つエレメントのテキストを、ごっそりresDataと入れ替えます。
入れ替えると言っても、もともと文字列が入っていない"data"ですので、「テキスト形式で得たデータを、エレメント"data"を使って表示する」と理解した方が簡単だと思います。

取得データから抜き出す

取得したデータは、XMLと言われるもので、冒頭の「いきなり取得してみる」で取得したような形式のテキストデータです。
このデータは、記述方法が決まっていますので、そのルールが分かれば簡単に読み取ることができます。
ただ、あなたが「読み取る」ことと、プログラミング上において「読み取る」ということは、まったく違います。
理解したことを、どのように「プログラム」という形にするかを紹介していきます。

より理解しやすい形にする

これは、あくまでも頭の中でやることであって、実際に形を変える訳ではありません。
これまで作ってきたサンプルで意識してきたことなのですが、後で見直しても分かりやすい記述をしてきたつもりです。
その筆頭に挙げられる方法が「インデント」と言われるもので、構造(階層が)一目で理解することができます。
XMLはテキストデータですが、HTMLと同様にタグを利用して記述されています。
タグで記述されているということは、「入れ子」が存在することを意識しなければなりません。
しかし、実際に取得したYahooウェザーのXMLを見て、「入れ子」になっていることの分かる人がどれほどいるでしょうか?
私は、このページを作成するためにXMLを見直して始めて気付きました。

<?xml ... >
<rss ... >
 <channel>
  <title>Yahoo! Weather - ... </title>
  <link>http://us ... </link>
   ・
   ・
   ・
  <image>
   <title>Yahoo! Weather</title>
   <width>142</width>
   <height>18</height>
     ・
     ・
     ・
  </image>
  <item>
   <title>Conditions for Asahikawa ... </title>
   <geo:lat>43.77</geo:lat>
     ・
     ・
   <yweather:condition text= ... />
     ・
     ・
  </item>
 </channel>
</rss>

すべてを記載するのは場所を取るだけなので、「入れ子」になっていることが分かるような書き方で紹介します。
取得したデータ構造が分かっていると、その後が楽になりますので、構造用のテキストファイルを新規で作るくらいしても良いと思います。

私は、ブラウザーに表示されたXMLをコピーし、テキストエディターで新たにファイルを作成しています。
頭の中でできる方は、ここまでする必要はありません。

抜き出してみる

XMLを眺めることで、何となくでも構いませんが、「目的の情報はここっぽい」くらいの目処は立つと思います。
ここでは、その目的の情報まで、どのように辿っているかを考えます。
そもそも、タグを利用して記述されているのですから、さきほどの「インデント」で見やすくした抜粋XMLでピンと来る方も多いと思います。
もう答えは出ているのですが、「タグを辿る」のですね!
上から○番目のタグの中の、上から□番目のタグの中の、上から△番目のタグの中にあるテキスト」という具合に辿れば、誰でも同じ情報に辿り着けますよね?
これは、私と同じようにやっていただき、同じような結果が出れば納得していただけることなので、ぜひ同じようにやっていただきたいと思います。

では、「タグを辿る」には、どのような記述でプログラミングすれば良いのでしょうか。
入れ子」というキーワードを思い出して下さい。これが、答えに直結しています。
さきほどの抜粋XMLを、家系図と思って下さい。(段差の所だけ)
○番目の子供の□番目の子供の△番目の子供の名前」という感じに、さきほどのイメージを置き換えることができれば、プログラミングも簡単です。
なぜなら、"child"を使ってプログラミングしていくからです。

では、実際のプログラミングではどのように記述するかを紹介します。
ものすごくシンプルなのですが、1番目の子供は、「childNodes(0)」と表します。
プログラミングの基本なのですが、数字は0から始まるものと思って下さい。
ですから、childNodes(2)という記述があれば、それは3番目を指しています。
「ノード」は要素と理解して結構です。
そして、「タグを辿る」というのは、プログラミング的な言葉にすると、「子ノード」を探索するって感じかな。
この先、「ノード」という言葉が多く出てくると思いますが、文書構造を示すものはすべて「ノード」と呼びますので、覚えておいて下さい。

家系図であれば、きっとアダムとイブから辿らなければならないのかもしれませんが(大笑)、XMLはそんな大袈裟に考える必要はありません。
今回は、天気情報をXMLで取得しているので、サンプルで紹介した記述のまま紹介すると、

request.responseXML.childNodes(0).childNodes(1).childNodes(2)

このように書くことで、取得した情報の、1番目のタグの中の、2番目のタグの中の、3番目のタグを示しています。
では、Yahooウェザーのタグを辿って、目的の天気を見つけましょう。
さきほどの抜粋XMLで、色の変わっている部分を探して下さい。
ただ、XMLの最初にある "<?XML ... " は、XMLであることの宣言なので、タグとしては数えません
一緒に辿りましょう!
1番目の<rss...の中の、1番目の<channel>の中の、13番目の<item>の中の、6番目のタグが、<yweather:condition text="... になっていますでしょうか?
目的のタグでは、「text」「code」「temp」などが入っていますので、この中の特定のものを抜き出すには、getAttributeを使います。
ここで、実際に数えて辿り着いた情報までの道のりを、childNodesで表現すると、

XML.childNodes(0).childNodes(0).childNodes(12).childNodes(5).getAttribute("text")

このようになります。
便宜上、XMLから辿っているように書きました。
この記述で、都市コードで指定した都市の現在の天気情報が文字で取得できます
これを組み込んだサンプルを用意しました。
ダウンロードはこちら ー> wf_12のダウンロード
ブラウザ表示はこちら ー> wf_12の表示

ダウンロードしたフォルダ内のLockBackground.htmlをブラウザで開いて下さい。
現在の天気が表示されていますでしょうか?

ん?? 表示されない??
ホントだねぇ・・・

ちょっと調べてみましょうか。
興味のある方は、Safariの環境設定の詳細から、「メニューバーに"開発"メニューを表示」のチェックを入れて下さい。
では、LockBackground.htmlを、Safariで開いてみます。
表示されませんね・・・

幸いにもエラーが出ているので、エラーを見てみましょう。

データを抜き出す所でタイプエラーが出ていますね。

エラーが出る行で止めます。

原因はすぐに分かりました。

右の画像は、エラーが出たときのXMLなのですが、childNodesに注目できる部分を抜き出しています。

赤い線を引いておきましたが、childNodes内のエレメントの順番がズレています。
どうしてズレているのでしょう?
よく見ると、エレメントだけでなくテキストもありますね。
画像を用意していませんが、エレメントとテキストが交互に出現することが確認できましたので、そういうものとして対応しましょう。

エレメントを辿るので、最初にchildNodes(0)、次にchildNodes(1)であることは、画像から容易に推測できるますね。
その中のエレメント内には27個の要素があり、テキストから並んでいます。
本来ならchildNodes(12)が目的のエレメントなのですが、テキストから始まる13番目の要素として考え直すと、childNodes(25)になります。
同様に、この後のchildNodes(5)も対応すると、childNodes(11)になります。
ご自身で書き換えた方が早いかもしれませんが、エラーに対応したサンプルを用意しました。
ダウンロードはこちら ー> wf_13のダウンロード
ブラウザ表示はこちら ー> wf_13の表示

では、LockBackground.htmlを、Safariで開いてみて下さい。
天気情報がテキストで表示されているはずです。
もちろん英語ですが・・・

念のため、iPhoneのロック画面で表示したスクリーンショットです。
白地に黒で表示させているのですが、フォントサイズを指定していないので、左上に小さく表示されています。
Yahooウェザーで、現在はSnow Showerという天気なんですね。
吹雪いてるのか!?

ページトップへ

2012/04/01