天気情報を表示する17(MSN天気予報編2)

今回は、私、必要以上に気合い入ってます!
やはり、日本語表示は外せないし、ここまで来たら画像も外せません。
3日程度の天気予報も物足りないですしね。
今回のMSN天気予報は、前回の天気情報確認でお分かりのことと思いますが、日本語で取得できるのはもちろんのこと、天気画像もあり、5日分の情報があり、気温情報もあり、降水確率まで取得できるのです。

気合いが入っているホントの理由は他にあるのですが、とっとと始めましょう!!

取得した天気情報を確認する

では、もう一度前回取得した天気情報を見てみましょう。

ゴチャゴチャしてますね。
これまで見てきたものと違います。
改行がバラバラですね・・・

これまで見てきた天気情報はキレイに改行され、タグがとても見やすかったのですが、この天気情報はとても見にくいですね。
見れば見るほどイライラしてきます。


見やすくして確認する
<?xml version="1.0" ?>
<?xml-stylesheet ... ?>
<rss ... >
 <channel>
  <title>島根県 隠岐の島町 - MSN ... </title>
  <link>http://weather.jp.msn.com ... </link>
   ・
   ・
   ・
  <item>
   <title>島根県 隠岐の島町 の 2012 ... </title>
     ・
     ・
   <description>
    <p>
     <strong>
      <a href="http:// ... rss">今日</a>:
     </strong>
     曇時々晴.
     <img src="http://stjp.msn.com ... />
     最低: 11&#176;C.
     最高: 16&#176;C.
     降水確率: 20%
     <br />
     <strong>
      <a href="http:// ... rss">明日</a>:
     </strong>
     曇時々晴.
     <img src="http://stjp.msn.com ... />
     最低: 9&#176;C.
     最高: 13&#176;C.
     降水確率: 30%
     <br />
     <strong>
      <a href="http:// ... rss">明日</a>:
     </strong>
     晴時々曇.
       ・
       ・
       ・
    <description>
   </description>
  </item>
 </channel>
</rss>

今回のためにやってきた感じがしますね。

見やすくすることで、あれだけ見にくかったデータがとても見やすくなりましたね。

しかし、違和感があります。
今回の天気データを見やすくしていて気付いたのは、明らかにこれまでと違うデータ構造なのです。
結論から言うと、「データではなく文章」という判断をしても仕方がないデータ構造なんですね。

いつものように、必要な部分に色を付けましたが、今回のデータは、関連付けされたタグに格納されている訳ではなく、情報をくっつけて1つにしてしまい、<description>以下の<p>タグで丸投げされた感じなのです。
確かに、ブラウザではきちんと表示されますが・・・
「腹に入れば同じでしょ?」といわれている気分です。
だからって、こんなにゴチャゴチャにしなくても良いのにね。


関連付けされたタグに情報が格納されている訳ではないのは、気温の部分を見てもらえれば、分かりやすいと思います。
こんな構造をしたデータは初めてです。
どうやって抜き出せば良いのか・・・

ページトップへ

天気情報を抜き出すための考え方

しばらく、データを眺めていましたが、スマートには解決しそうにないですね。
そもそも、こんな乱暴なデータを与えられたのですから、こちらとしても力尽くでやっつけたいと思います。

データを1日ごとの情報に分ける

1つにまとめられれたデータですが、1日ごとのデータに分ける突破口はあります。
1日ごとのデータの間に、<br />があるのです。
JavaScriptの文字列操作には、文字列を文字(列)で分割し、配列に格納してくれるものがあります。
"split"というもので、以下のように記述します。

格納先配列 = 分割元の文字列.split("文字列を分割するための文字(列)");

データをdescriptionで受け取りますので、配列名はdescとでもしましょう。
その際、以下のような記述になります。

desc = description.split("<br />");

これで、descriptionで受け取った乱暴なデータが、改行コード<br />で分割され、descに格納されるのです。
descは配列なので、desc[0]は今日の天気予報、desc[1]は明日の天気予報といった具合に格納されるので、5日目の天気予報だとdesc[4]に格納される訳です。

ページトップへ

1日ごとの情報から「いつの天気なのか」を探す

1日ごとの情報に分割できたので、その情報から必要な部分を抜き出しましょう。
ここでは、「いつの天気なのか」を探します。
5日分すべてに共通する部分を探してみました。
以下の画像の黄色い部分が、目的とする「いつの天気なのか」です。

「"rss"と"</a>"の間にある」と定義して良さそうですね。
ざっと見渡しても、他にこの定義で合致しそうな部分はありませんので、このまま続けます。
では、どこからどこまで抜き出せば良いのでしょうか?
文字探索関数indexOfを使って、以下のように考えます。



"rss"と"</a>"で場所が特定できるのは分かりますが、抜き出すことを考えると、多少の細工が必要になります。
実際のプログラミングでは、以下のように記述します。

desc[0].substring(desc[0].indexOf("rss")+5,desc[0].indexOf("</a>"));

desc[0]ですので、今日の天気に対する文字列操作です。
これにより、いつの天気なのかを抜き出すことができます。

ページトップへ

1日ごとの情報から「その日の天候」を探す

1日ごとの情報に分割できたので、その情報から必要な部分を抜き出しましょう。
ここでは、「その日の天候」を探します。
5日分すべてに共通する部分を探してみました。
以下の画像の黄色い部分が、目的とする「その日の天候」です。


今回目的とする部分は3カ所あり、どれにしようか迷ったのですが、特定するための文字が少なく、その文字自体も分かりやすいところを選びました。
上の赤い下線のように、「"alt"と"title"の間にある」と定義して良さそうですね。
ざっと見渡しても、他にこの定義で合致しそうな部分はありませんので、このまま続けます。
では、実際にどこからどこまで抜き出せば良いのでしょうか?
文字探索関数indexOfを使って、以下のように考えます。



"alt"と"title"で場所が特定できるのは分かりますが、抜き出すことを考えると、多少の細工が必要になります。
実際のプログラミングでは、以下のように記述します。

desc[0].substring(desc[0].indexOf("alt")+5,desc[0].indexOf("title")-2);

desc[0]ですので、今日の天気に対する文字列操作です。
これにより、その日の天候を抜き出すことができます。

ページトップへ

1日ごとの情報から「最低気温」を探す

1日ごとの情報に分割できたので、その情報から必要な部分を抜き出しましょう。
ここでは、「最低気温」を探します。
5日分すべてに共通する部分を探してみました。
以下の画像の黄色い部分が、目的とする「最低気温」です。


「"最低"と". 最高"の間にある」と定義して良さそうですね。
ざっと見渡しても、他にこの定義で合致しそうな部分はありませんので、このまま続けます。
では、どこからどこまで抜き出せば良いのでしょうか?
文字探索関数indexOfを使って、以下のように考えます。



"最低"と". 最高"で場所が特定でき、細工することもなく、以下のように記述します。

desc[0].substring(desc[0].indexOf("最低"),desc[0].indexOf(". 最高"));

desc[0]ですので、今日の天気に対する文字列操作です。
これにより、最低気温を抜き出すことができます。

ページトップへ

1日ごとの情報から「最高気温」を探す

1日ごとの情報に分割できたので、その情報から必要な部分を抜き出しましょう。
ここでは、「最高気温」を探します。
5日分すべてに共通する部分を探してみました。
以下の画像の黄色い部分が、目的とする「最高気温」です。


「"最高"と". 降水"の間にある」と定義して良さそうですね。
ざっと見渡しても、他にこの定義で合致しそうな部分はありませんので、このまま続けます。
では、どこからどこまで抜き出せば良いのでしょうか?
文字探索関数indexOfを使って、以下のように考えます。



"最高"と". 降水"で場所が特定でき、細工することもなく、以下のように記述します。

desc[0].substring(desc[0].indexOf("最高"),desc[0].indexOf(". 降水"));

desc[0]ですので、今日の天気に対する文字列操作です。
これにより、最高気温を抜き出すことができます。

ページトップへ

1日ごとの情報から「降水確率」を探す

1日ごとの情報に分割できたので、その情報から必要な部分を抜き出しましょう。
ここでは、「降水確率」を探します。
5日分すべてに共通する部分を探してみました。
以下の画像の黄色い部分が、目的とする「降水確率」です。


「"降水"以降」と定義して良さそうですね。
ざっと見渡しても、他にこの定義で合致しそうな部分はありませんので、このまま続けます。
文字探索関数indexOfを使って、以下のように考えます。



"降水"だけで抜き出せますので、以下のように記述します。

desc[0].substring(desc[0].indexOf("降水"));

desc[0]ですので、今日の天気に対する文字列操作です。
"<br />"で1日ごとの情報を区切っていますので、上の図にある"<br />"を考える必要はありません。
これにより、降水確率を抜き出すことができます。

ページトップへ

1日ごとの情報から「天気画像のURL」を探す

1日ごとの情報に分割できたので、その情報から必要な部分を抜き出しましょう。
ここでは、「天気画像のURL」を探します。
5日分すべてに共通する部分を探してみました。
以下の画像の黄色い部分が、目的とする「天気画像のURL」です。


「"src"と"width"の間にある」と定義して良さそうですね。
ざっと見渡しても、他にこの定義で合致しそうな部分はありませんので、このまま続けます。
では、どこからどこまで抜き出せば良いのでしょうか?
文字探索関数indexOfを使って、以下のように考えます。



"src"と"width"で場所が特定できるのは分かりますが、抜き出すことを考えると、多少の細工が必要になります。
実際のプログラミングでは、以下のように記述します。

desc[0].substring(desc[0].indexOf('src="')+5,desc[0].indexOf("width")-2);

desc[0]ですので、今日の天気に対する文字列操作です。
"src"で特定できると思ったのですが、実際にサンプルを作成してみると、ダブルクォーテーション(")まで指定しないと特定してくれなかったため、探索文字列をシングルクォーテーション(')で括っています。
これにより、天気画像のURLを抜き出すことができます。

ページトップへ

今日の天気予報を表示してみる

ダラダラと天気情報の抜き出し方を説明したので、とっとと表示させてみましょう。

サンプルHTML

HTMLから見ていきましょう。
以下に示すのが、LockBackground.htmlの中身(ソース)です。

<!DOCTYPE html>
<html>
 <head>
  <meta name="viewport" content="width=device-width,minimum-scale=0.5,initial-scale=0.5"/>
  <meta charset="UTF-8">
  <script src="./script.js" type="text/javascript"></script>
  <link href="./style.css" rel="stylesheet" type="text/css" />
 </head>
 <body onload="setWeather()">
  <div id="weather">
   <p id="city"></p>
   <p id="day"></p>
   <img id="image"/>
   <p id="text"></p>
   <p id="max"></p>
   <p id="min"></p>
   <p id="prob"></p>
  </div>
 </body>
</html>

サンプルHTMLソース1

まぁスタートはこんなもんでしょう。

ページトップへ

サンプルJavaScript

では、JSファイルを見ていきましょう。
以下に示すのが、script.jsの中身(ソース)です。
と言っても、基本的なソースはすでに紹介&配信してあるので、天気情報を読み込んだあとに実行する関数xml_respondedのみを紹介します。

function xml_responded (request) {
 var rss = findChild(request.responseXML, "rss");
 var channel = findChild(rss, "channel");
 var city = findChild(channel, "title").textContent;
 city = city.substring(0, city.indexOf("-"));
 document.getElementById("city").innerText = city;

 var item = findChild(channel, "item");
 var description = findChild(item, "description").textContent;
 var desc = description.split("<br />");
 var day, max, min, probability, title, url;
 day = desc[0].substring(desc[0].indexOf("rss")+5,desc[0].indexOf("</a>"));
 title = desc[0].substring(desc[0].indexOf("alt")+5,desc[0].indexOf("title")-2);
 min = desc[0].substring(desc[0].indexOf("最低"),desc[0].indexOf(". 最高"));
 max = desc[0].substring(desc[0].indexOf("最高"),desc[0].indexOf(". 降水"));
 probability = desc[0].substring(desc[0].indexOf("降水"));
 url = desc[0].substring(desc[0].indexOf('src="')+5,desc[0].indexOf("width")-2);
 
 document.getElementById("day").innerText = day;
 document.getElementById("image").src = url;
 document.getElementById("text").innerText = title;
 document.getElementById("max").innerHTML = max;
 document.getElementById("min").innerHTML = min;
 document.getElementById("prob").innerText = probability;
}

サンプルJavaScript1

ここでのポイントは、最高気温と最低気温の部分です。
抜き出す特に説明していなかったのですが、抜き出す文字列の中に"&#176;"があります。
これは、HTMLにおける特殊文字といわれるもので、”°”を表します。
当サイトのサンプルでは、「℃」という文字列を表示していましたが、MSN天気予報の天気情報では、特殊文字(°)と"C"を組み合わせて「°C」と表示しているんですね。
という訳で、特殊文字を特殊文字として表示させるために、"innerHTML"で表示しています

ページトップへ

サンプルスタイルシート
* {
   margin: 0px;
   padding: 0px;
   border: 0px;
}
body {
   width: 640px;
   height: 960px;
   background-color: white;
}
#weather {
   margin: 232px 0px;
}
p {
   font-size: 24px;
   color: black;
   text-shadow: 1px 1px 1px white;
}

サンプルスタイルシート1

次に、スタイルシート(style.css)を見ていきましょう。

こちらも相変わらずの書き方です。

ページトップへ

サンプル表示

ご覧の通り、MSN天気予報から天気情報が抜き出せていますね・・・と言いたい所なのですが、気温が表示されていませんね。

「なぜ?」と思いながら、実際の天気情報を確認してみると、気温データがありませんでした。
「データがないから表示されない」という正しい動きだったんですね。
取得するタイミングもあるかと思いますが、それにしても、どちらの気温も抜けているとは・・・




今回のサンプルファイルのダウンロードは、こちらからどうぞーー>ダウンロード

ページトップへ

整形する

たった1日の表示ですが、いつものように整形しましょう。

ただ、気温が表示されていないのも味気ないので、明日の天気予報に切り替えて整形しましょう。
切り替え方は、Javascriptのdesc[0]の部分を1にするだけですので、サンプルファイルで確認して下さい。




今回のサンプルファイルのダウンロードは、こちらからどうぞーー>ダウンロード

ページトップへ

サンプルスタイルシート
* {
   margin: 0px;
   padding: 0px;
   border: 0px;
}
body {
   width: 640px;
   height: 960px;
   background-color: white;
}
#weather {
   margin: 232px 0px;
   text-align: center;
}
p {
   margin-top: -10px;
   font-size: 36px;
   color: black;
   text-shadow: 1px 1px 1px white;
}
#city {
   font-size: 64px;
}
#day {
   font-size: 48px;
}
img {
   width: 240px;
}
#text {
   font-size: 24px;
}
#max {
   margin-top: 10px;
   float: left;
   width: 320px;
}
#min {
   margin-top: 10px;
   float: right;
   width: 320px;
}
#prob {
   clear: both;
}

サンプルスタイルシート3

今回の整形は、スタイルシートがメインです。

#weatherで、すべて中央表示を基本としています。
さらにpにおいて、文字サイズを36ピクセルにし、10ピクセル上へ詰めています。
これで全体の体裁が整ったので、個別の指定もしていきます。

地名は極力大きくするために、64ピクセルにしました。

天気画像は、元のサイズが小さいため、幅240ピクセルにしておきました。
ホントは幅いっぱいに表示させたいトコなんですけどね・・・

それとは対照的に、天気のテキスト情報は、文字サイズを小さくし、24ピクセルにしました。

気温は横並びにし、最高気温を左へ、最低気温を右へ配置しました。
メリハリを付けるために、気温から余白を設けました。
気温情報のバランスを取るために、それぞれの幅320ピクセルにしています。

降水確率は中央表示で良いので、気温で左右に配置するために指定したfloatを解除し、中央表示に戻します。
floatの解除は、clearで指定します。

ページトップへ

サンプル表示

では、実際に表示してみましょう。
ダウンロードはこちら ー> wf_173のダウンロード



それなりに整形したつもりですが、いかがでしょうか。

ページトップへ

背景を表示して仕上げる

仕上げは、相変わらずの背景表示です。
さらに相変わらずの、気温に色づけを施しましょう。
今回は、スタイルシートのみの変更で済みます。

ページトップへ

サンプルスタイルシート
body {
   width: 640px;
   height: 960px;
   background-image:url("/private/var/
      mobile/Library/SpringBoard/
      Converted-LockBackground.jpg");
   background-repeat: no-repeat;
}
p {
   margin-top: -10px;
   font-size: 36px;
   color: black;
   text-shadow: 0px 0px 10px white,
          0px 0px 10px white,
          0px 0px 10px white,
          0px 0px 10px white,
          0px 0px 10px white,
          0px 0px 10px white,
          0px 0px 10px white,
          0px 0px 10px white,
          0px 0px 10px white,
          0px 0px 10px white;
}

サンプルスタイルシート4

背景画像には、iPhoneのロック画面に設定してある画像を表示しますので、当サイト「脱獄アプリ」で紹介している「Wallpaper JPEGifier」をインストールしておいて下さい。

背景画像の表示はいつも通りですが、影の重ね方がいつもと違います。

ページトップへ

サンプル表示

まぁ、こんな感じでしょうか。

あれだけ入りまくっていた気合いが、見事に空回りした感じですね!



今回のサンプルファイルのダウンロードは、こちらからどうぞーー>ダウンロード

ページトップへ

2012/05/13