使ってみよう! Windows Live SDK/API

第5回Virtual Earth、VECollection and GeoRSS

はじめに

Virtual Earth Map Controlは、Live Search MapsのコレクションやGeoRSS、KMLといったXMLで表現された位置情報を取り込むことができます。前回の最後にプッシュピンの追加を紹介しましが、これらのデータ形式を用いると、まとまりのある位置情報をプッシュピンとして一度にマップに追加することも可能になります。今回はこれらのデータ形式の利用を取り上げます。また、WCF(Windows Communication Foundation)によるサービスも作成します。

コレクションの表示

Live Search Mapsにはプッシュピンのグループや経路情報を作成して管理できるコレクションという機能があります図1⁠。Live Search Mapsにサインイン後、ツールバーの「コレクション」から「マイコレクションを開く」を選択するとコレクション一覧を表示したり新しくコレクションを追加したりできます。詳しくはLive Search Mapsのヘルプを確認してください。図1のように作成したプッシュピンのコレクションをVirtual Earth Map Controlから取り込み(インポートし⁠⁠、表示してみましょう。

図1 コレクション機能
図1 コレクション機能

まずは単純にマップを表示するだけのページを作成します。本連載の第4回目も参考にしてください[1]⁠。Virtual Earth JavaScript Intellisense Helperを使用する場合は、スクリプト部分を外部JavaScriptファイルに記述します。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<script type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.1&amp;mkt=ja-jp"></script>
<script type="text/javascript">
    var map = null;
    function pageLoaded() {
        map = new VEMap("myMap");
        map.LoadMap();
    }
</script>
</head>
<body onload="pageLoaded();">
<div id='myMap' style="position:absolute; width:400px; height:400px;"></div>
</body>
</html>

コレクションのインポートはVEMapクラスのImportShapeLayerDataメソッドを使用します。

VEMap.ImportShapeLayerData(shapeSource, callback, setBestView);

戻り値はありません。ImportShapeLayerDataの引数には次のものを渡します。

パラメータ 説明
shapeSource VEShapeSourceSpecificationオブジェクト。
callback データのインポート後に呼ばれるコールバック関数。VEShapeLayerオブジェクトが渡されます。
setBestView trueまたはfalseのブール値。trueの場合、インポートしたデータを表示するのに最適なマップの位置とズーム値に設定されます。

VEShapeSourceSpecificationというクラスが出てきました。このクラスはインポートするデータの形式・場所や追加先のVEShapeLayerオブジェクトの情報を持っています。このクラスのコンストラクタには次の値を順に指定しインスタンスを生成します。

パラメータ 説明
dataType VEDataType列挙体。GeoRSS、VECollection、ImportXMLの3種類があります。
dataSource GeoRSS、KMLのURL。または、Live Mapsのコレクションを示すGUIDと呼ばれる値。
layer VEShapeとしてデータをインポートする先のVEShapeLayerオブジェクト。

以上をまとめるとコレクションを表示するコードは次のようになります。先ほどのコードのpageLoaded関数の変更と新たにonFeedLoaded関数を追加しています。

function pageLoaded() {
    map = new VEMap("myMap");
    map.LoadMap();
    
    var layer = new VEShapeLayer();
    var spec = new VEShapeSourceSpecification(VEDataType.VECollection, 'AFE8504AA8CD166F!368', layer);
    map.ImportShapeLayerData(spec, onFeedLoaded, true);
}

function onFeedLoaded(layer) {
    alert(layer.GetShapeCount() + ' 個のアイテムをインポートしました。');
}

pageLoaded関数の中では、データのインポート先として新たにVEShapeLayerオブジェクトを生成し、VEShapeSourceSpecificationのコンストラクタに指定しています。 コールバック関数のonFeedLoadedではVEShapeLayerクラスのGetShapeCountメソッドを使いレイヤ内のプッシュピンの数を表示しています。

コレクションの場合、VEShapeSourceSpecificatioクラスのコンストラクタの引数にコレクションのGUID(globally-unique identifier)を指定することになりますが、この値はLive Search Mapsで知ることができます。図1のように表示されたコレクションの管理(マイコレクション)ウィンドウの中にある「操作」から「お気に入りに追加」を選択すると、新たにウィンドウが開きます図2⁠。アドレスのcid=以降の値がGUIDになります。

図2 お気に入りの追加
図2 お気に入りの追加

変更したコードをWebブラウザで表示すると図1のようになったと思います。プッシュピン上に数字は描かれませんが、マウスポインタを合わせると駅名の情報も取り込まれていることがわかります。

GeoRSS

GeoRSSとはRSSフィードに位置情報を含めた簡単なデータ形式です。RSSという名前が付いていますがAtomフィードにも情報を含めることができます。最もシンプルなGeoRSS-Simpleと呼ばれる形式で1点の位置情報を表す場合は以下のタグをRSS1.0/2.0のitemタグの中、またはAtom1.0のentryタグの中に追加します。

<georss:point>43.062089 141.354507</georss:point>

また、georss:という接頭辞を使用するためにfeedやrssタグの属性にxmlns属性を追加しておく必要があります。

xmlns:georss="http://www.georss.org/georss"

Virtual Earth Map Controlは、このGeoRSSのインポートにも対応しています。次はこのGeoRSSのインポートをしてみましょう。GeoRSSを配信するサービス自体をWCFサービスとして作り、そのGeoRSSをインポートします。

WCF配信サービス

配信サービスの作成にはVisual Studio 2008を使用します。Visual Studio 2008にはWCFの配信サービスライブラリのテンプレートが用意されており、簡単にRSSおよびAtomを配信するサービスが作れます。新しいプロジェクトからVisual Basicの配信サービスライブラリを選択します図3⁠。

図3 WCF配信サービスライブラリ
図3 WCF配信サービスライブラリ

プロジェクトを作成した時点で、RSSおよびAtomを配信するサービスができています。実行するとWebブラウザが起動しサービスで作成されたフィードが確認できます図4⁠。起動した時点ではRSS2.0のフィードが配信されています。Atom1.0のフィードはアドレスの末尾に「?format=atom」を付けると取得できます。

図4 フィードの表示
図4 フィードの表示

作成されたプロジェクトにはWCFサービスのみ含まれています。そのためサービスを利用するためにはサービスをホストする必要があります。実行時にサービスが確認できたのはWCFサービスホスト(WcfSvcHost.exe)と呼ばれる自動的にサービスをホストするテスト用のプログラムも起動したためです。本記事ではサービスのホストについては説明しません。

プロジェクトにあるIFeed1.vbにサービス内容の定義が、Feed1.vbにその実装が記述されています。Feed1.vbの内容を変更してGeoRSSのサービスを作成します。

GeoRSSサービスの作成

作成するGeoRSSのサービス内容を考えます。livedoor天気情報では天気予報用に拡張されたRSSフィードが提供されています。このフィードに経緯度の情報を付加したものはどうでしょうか。⁠全国の天気(主要14ヵ所⁠⁠」のRSSを利用してGeoRSSサービスを作成してみましょう。提供されているフィードの各項目の構造は次のようになっています。

<item>
        <title>[ 今日の天気 ] 札幌 - 晴れ - 最高気温14℃ - 4月6日(日)</title>
        <ldWeather:lwws id="4" />
        <link>http://weather.livedoor.com/area/1b/4.html?r=rss</link>
        <date>Sun, 06 Apr 2008 00:00:00 +0900</date>
        <category type="forecast">天気予報</category>
        <day>Sunday</day>
        <telop>晴れ</telop>
        <image>
                <title>晴れ - livedoor 天気情報</title>
                <link>http://weather.livedoor.com/area/1b/4.html?r=rss</link>
                <url>http://image.weather.livedoor.com/img/icon/1.gif</url>
                <width>50</width>
                <height>31</height>
        </image>
        <description>06日(日)の天気は晴れ、最高気温は14℃ 最低気温は2℃でしょう。</description>
        <source url="http://weather.livedoor.com/forecast/rss/1b/4.xml" />
        <pubDate>Sun, 06 Apr 2008 11:00:00 +0900</pubDate>
</item>

まず、拡張された要素に使用されているXMLの名前空間をインポートします。Feed1.vbの先頭に以下を記述します。

Imports <xmlns:ldWeather="http://weather.livedoor.com/ns/rss/2.0">

ここからはCreateFeedメソッドの内容を変更していきます。最初にメソッドの内容を一度すべて削除してから取り掛かります。フィードを抽象的に表すSyndicationFeedオブジェクトを作成し、それをシリアル化するSyndicationFeedFormatterオブジェクトを返すことがCreateFeedメソッドの処理になります。実際には、SyndicationFeedFormatterは抽象クラスのため派生クラスであるAtom10FeedFormatterまたはRss20FeedFormatterオブジェクトを返します。

提供されているフィードには地域を表すIDが付いています(<ldWeather:lwws id="4" />など⁠⁠。そのIDと経緯度を関連付けるコレクションを作成しておきます。

Dim latlongs = New Dictionary(Of String, String)
latlongs.Add("4", "43.062089 141.354507")   ' 札幌
latlongs.Add("11", "42.984906 144.381688")  ' 釧路
latlongs.Add("20", "39.72158 140.115595")   ' 秋田
latlongs.Add("25", "38.269993 140.874038")  ' 仙台
latlongs.Add("50", "37.910211 139.05241")   ' 新潟
latlongs.Add("63", "35.68693 139.701805")   ' 東京
latlongs.Add("72", "36.65225 138.180861")   ' 長野
latlongs.Add("38", "35.180508 136.913896")  ' 名古屋
latlongs.Add("81", "34.695755 135.530262")  ' 大阪
latlongs.Add("107", "33.560315 133.535428") ' 高知
latlongs.Add("90", "34.397225 132.461579")  ' 広島
latlongs.Add("110", "33.607543 130.429516") ' 福岡
latlongs.Add("132", "31.52997 130.604439")  ' 鹿児島
latlongs.Add("136", "26.212319 127.685938") ' 那覇

次にRSSフィードのURLからXMLドキュメントの作成とSyndicationFeedオブジェクトを生成します。フィードに含まれる各項目を表すSyndicationItemオブジェクトを格納するコレクションも作成します。

Dim doc = XDocument.Load("http://weather.livedoor.com/forecast/rss/index.xml")
Dim feed = New SyndicationFeed("Weather GeoRSS", "", Nothing)
Dim items = New List(Of SyndicationItem)

XMLドキュメントから各<item>要素を取得します。<category>要素の値が⁠PR⁠の場合、天気情報が含まれていませんので処理を飛ばします。

For Each e In doc...<item>
    If e.<category>.Value = "PR" Then
        Continue For
    End If
    ' ここにSyndicationItemオブジェクト作成する処理を記述
Next

SyndicationItemクラスのコンストラクタには、項目のタイトル・説明・リンクを指定できます。基本的にはフィードの値をそのまま使用していますが、GeoRSSを取得したときに利用できるように説明の中に画像のURLを含めています。

Dim item = New SyndicationItem(e.<title>.Value, _
                               e.<description>.Value & e.<image>.<url>.Value, _
                               New Uri(e.<link>.Value))
item.PublishDate = New DateTimeOffset(DateTime.Parse(e.<pubDate>.Value))

<georss:point>のようにSyndicationItemの要素として用意されてないものを追加する場合は、ElementExtensionsプロパティを使います。作成したSyndicationItemオブジェクトをコレクションに追加してForループ内の処理は完了です。

Dim id = e.<ldWeather:lwws>.@id
Dim point = <georss:point xmlns:georss="http://www.georss.org/georss">
                <%= latlongs(id) %></georss:point>
item.ElementExtensions.Add(point)

items.Add(item) ' コレクションへ追加

最後にURLのパラメータに応じてAtomまたはRSS用のSyndicationFeedFormatterオブジェクトを返します。

Dim query As String = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters.Get("format")
If (query = "atom") Then
    Return New Atom10FeedFormatter(feed)
Else
    Return New Rss20FeedFormatter(feed)
End If

以上でGeoRSSサービスの完成です。実行してフィードが表示されたでしょうか? 上記のコードをまとめたものは以下のファイル(Feed1.vb)をダウンロードして確認してください。

GeoRSSの表示

作成したサービスをVirtual Earth Map Controlからインポートしましょう。ここで注意点ですが、これから作成するマップを表示するページもWCFサービスも同じドメイン上にある必要があります。またInternet Explorerではローカルコンピュータ上のスクリプト実行に制限があり、通常ではGeoRSSのXMLデータにアクセスできません。http://localhostのアドレスでアクセスできるようにするなど工夫が必要になります。

環境さえできれば後は簡単です。コレクションの表示のときに使用したコードを変更します。VEShapeSourceSpecificationオブジェクトの生成時にVEDataType.GeoRSSとGUIDの代わりにGeoRSSサービスへのURLを指定します。

function pageLoaded() {
    map = new VEMap("myMap");
    map.LoadMap();
    
    var layer = new VEShapeLayer();
    var spec = new VEShapeSourceSpecification(VEDataType.GeoRSS, 'http://localhost/weather/georss/', layer);
    map.ImportShapeLayerData(spec, onFeedLoaded, true);
}

onFeedLoaded関数の中でプッシュピンの画像の代わりに、天気を示す画像を表示する処理を記述します。説明の中に画像のURLを含めるようにしていたので、その部分を切り出します。画像を変更するためにSetCustomIconメソッドを使用しています。

function onFeedLoaded(layer) {
    for (var i = 0; i < layer.GetShapeCount(); ++i) {
        var s = layer.GetShapeByIndex(i);
        var desc = s.GetDescription();
        var url = desc.match(/http:\/\/.*/); // 説明に含まれているURLを取得
        s.SetDescription(desc.replace(url, ''));
        s.SetCustomIcon('<img src="' + url + '" />');
    }
}

実行した結果は図5のようになります。うまくできたでしょうか? 以上で今回の内容は終了です。GeoRSSと同様にKMLと呼ばれるXML形式のデータもインポートができます。そちらについても是非試してみてください。

図5 GeoRSSのインポート
図5 GeoRSSのインポート

おすすめ記事

記事・ニュース一覧