Home > googlemap

Web 酒 肴

«前へ || 1 || 次へ»

GoogleMapでマッシュアップの練習(Rails編) #7

では最終的に作ったソースをもとに解説していく。

main_controller.rb

require 'net/http'
require 'rexml/document'
require 'cgi'

class MainController < ApplicationController

  def index
  end
  def search
    #HTTP通信設定(rgoecode)
    site = Net::HTTP.start('refits.cgk.affrc.go.jp')

    #地名情報取得  ← 1
    response = site.get("/tsrv/jp/rgeocode.php?lon=#{params[:x]}&lat=#{params[:y]}")
    resXML = response.body
    site.finish

    #XML要素から都道府県名と都市名を取得する  ← 2
    @got, @pref, @munic = get_name_of_place(resXML)

    unless @got then   # ← 3 
      @resText = "Error!"
      render(:layout => false)
      return
    end

    #HTTP通信設定(郵便番号)
    site = Net::HTTP.start('webservice.est.co.jp')

    #郵便番号情報取得  ← 4 
    response = site.post("/zipcode/SearchEngine.asmx/FromAddress2", "Address=" + CGI.escape(@pref + @munic))
    @got, @zipcode = get_zipcode(response.body)  # ← 5 
    unless @got then  # ← 6
      response = site.post("/zipcode/SearchEngine.asmx/FromAddress2", "Address=" + CGI.escape(@pref))
      @got, @zipcode = get_zipcode(response.body)
    end
    site.finish

    #HTTP通信設定(旅行記)
    site = Net::HTTP.start('api.4travel.jp')

    #旅行記情報取得  ← 7 
    response = site.get("/Ver1/SearchAlbum.php?zip=#{@zipcode}&oc=utf8")
    @travel_info = TravelInfo.new response.body   # ← 8 
    site.finish

    #郵便番号に-(ハイフンを入れる)
    @zipcode.insert(3, "-")
  end

  def get_name_of_place xml
    #XMLツリー作成
    docTree = REXML::Document.new xml

    #ステータス取得(地名の取得が成功したかどうか)

    status = docTree.elements.each("/rgeocode/status"){}[0].text
    return false, "取得失敗", "取得失敗" if status != "true"

    #都道府県取得
    @pref = docTree.elements.each("/rgeocode/prefecture/pname"){}[0].text

    #都市名取得
    @munic = docTree.elements.each("/rgeocode/municipality/mname"){}[0].text

    return true, @pref, @munic
  end


  def get_zipcode xml
    #XMLツリー作成
    docTree = REXML::Document.new xml

    #ステータス取得(地名の取得が成功したかどうか)
    status = docTree.elements.each("/FindList/TotalFindCount"){}[0].text
    return false, "" if status == "0"

    #郵便番号取得
    zipcode = docTree.elements.each("/FindList/Item/FindItem/ZipCode"){}[0].text

    return true, zipcode
  end
end

メインはsearchメソッド。
これがGoogleMapの地図上をクリックしたときに呼び出されるメソッド。

番号をつけているあたりで以下の処理をしている。

  1. ジオコードから地名をXML形式で取得
  2. 取得したXMLから都市名、町名などを取得(get_name_of_placeメソッド呼び出し)
  3. 取得できなければ終了
  4. 地名をもとに郵便番号をXML形式で取得
  5. 取得したXMLから郵便番号を取得(get_zipcodeメソッド呼び出し)
  6. 取得に失敗したらリトライ(町名は外して県名のみで取得)
  7. 郵便番号をもとに旅行記をXML形式で取得
  8. 取得したXMLから旅行記の配列を取得(TravelInfoクラス ※ソースは下)

旅行記のXMLを解析し、Travelogueというクラスのインスタンスにする。
それを旅行記の配列をTravelInfoが保持している。
この2つのクラスはコントローラから呼び出せるようにhelpersの下に配備する。

travel_info.rb

require 'rexml/document'

class Travelogue
  attr_accessor :album_title, :album_url, :traveler, :traveler_url, :picture_url, :picture_link, :area, :area_url, :description
  def initialize(doc)
    @album_title = doc.elements.each("albumtitle"){}[0].text
    @album_url = doc.elements.each("albumurl"){}[0].text
    @traveler = doc.elements.each("traveler"){}[0].text
    @traveler_url = doc.elements.each("travelerurl"){}[0].text
    picture_url = doc.elements.each("picture"){}
    picture_url = doc.elements.each("pictlist/picturl"){} unless picture_url
    @picture_url = picture_url[0].text if picture_url.size > 0
    picture_link = doc.elements.each("pictlist/pictlink"){}
    @picture_link = picture_link[0].text if picture_link.size > 0
    area = doc.elements.each("area"){}
    @area = area[0].text if area.size > 0
    area_url = doc.elements.each("areaurl"){}
    @area_url = area_url[0].text if area_url.size > 0
    description = doc.elements.each("description"){}
    @description = description[0].text.split(//u)[0..100].join.gsub /\r?\n/, "<br />\r\n" if description.size > 0
  end
end

class TravelInfo
  attr_accessor :num_of_results, :travelogue_array
  def initialize(xml)
    #XMLツリー作成
    docTree = REXML::Document.new xml

    #検索結果件数取得(旅行記の取得が成功したかどうか)
    num_of_results = docTree.elements.each("/results/numofresult"){}
    if num_of_results.size > 0
      @num_of_results = num_of_results[0].text 
    else
      @num_of_results = 0
    end
    @travelogue_array = []

    if @num_of_results != 0 then
      docTree.elements.each("/results/travelogue/item"){|travelogue|
        @travelogue_array << Travelogue.new(travelogue)
      }
    end
  end
end

さて、これで必要な情報は取得できたわけだが、それを画面上に表示できるようにHTMLに変換してやる必要がある。
これはsearchメソッドと結びつくviews/main/search.rhtmlを作成すれば自動的に呼び出される。

search.rhtml

<div id="search_area">
  <div class="search_info">
    <h3>検索条件</h3>
    <div class="search_parts">
      <div class="search_lable">都道府県名</div>
      <div class="search_word"><%= @pref %></div>
    </div>
    <div class="search_parts">
      <div class="search_lable">都市名</div>
      <div class="search_word"><%= @munic %></div>
    </div>
    <div class="search_parts">
  <%
    if @got then
  -%>
      <div class="search_lable">郵便番号</div>
      <div class="search_word"><%= @zipcode %></div>
  <% else -%>
      <div class="search_lable">郵便番号</div>
      <div class="search_word">取得失敗</div>
  <% end -%>
    </div>
  </div>
  <div id="search_result">
<%
    if @travel_info != nil && @travel_info.num_of_results != 0 then
      @travel_info.travelogue_array.each{|t|
-%>
    <div class="an_result">
      <div class="travel_title">
        <a href="<%= t.album_url %>" target="_blank"><%= t.album_title %></a>
        <% if t.area %>
        (<a href="<%= t.area_url %>" target="_blank"><%= t.area %></a>)
        <% end %>
      </div>
      <div class="travel_description">
      <% if t.picture_url %>
      <a href="<%= t.album_url %>" target="_blank"><img src="<%= t.picture_url %>" align="left"/></a>
      <% end %>
      <% if t.description %>
      <%= t.description %>
      <% end %>
      </div>
      <div class="traveller">
        <a href="<%= t.traveler_url %>" target="_blank"><%= t.traveler %></a>
      </div>
      <br style="clear: both;" />
    </div>
  <% } %>
  <% else %>
  見つかりませんでした.
  <% end %>
  </div>
</div>

eRubyがわかれば特に難しい事はしていない。
検索情報と、検索結果をHTMLにしているだけだ。
ただし、作る方はこういうデザインに一番時間がかかるんだけどね。
そしてそれっぽく見えるスタイルシートをフリー配布のところからダウンロードしてきて適用。
最終的にこんな感じになりました。

旅行記検索サイト

GoogleMapでマッシュアップの練習(Rails編) #6

エマージェンシー発生

フォートラベルのAPIを再確認してみたところ、地名からの旅行記取得の仕様が期待していたものと違う。「北海道」とかいうパラメータで旅行記が取得できると思っていたけど、それは無理。「hokkaido」というアルファベット形式で送信しなくてはならない。漢字の地名をいちいちアルファベットに変換なんて面倒だしやりたくない。ということで別の方法を考えなくては。こういう見切り発車な性格は災いもおおいけど、勢いがなくては何も始められない。と肯定的に捉えてみる。

調査を続けるとフォートラベルでは残された方法は一つしかなかった。それは郵便番号による検索。

ということで住所から郵便番号を取得する処理を一つ追加する。APIはぽすたんというサービスを見つけた。さっそく組み込んでみる。

処理内容はこういうふうになる。

[修正前]

  1. GoogleMAP上をクリック
  2. 住所取得(京都市など)
  3. 旅行記取得(これができない)

[修正後]

  1. GoogleMAP上をクリック
  2. 住所取得(京都市など)
  3. 郵便番号取得(605xxxxなど)
  4. 旅行記取得

上記処理を実装するのに、あれやこれやと結構時間を食ってしまって。
その経緯をブログに残すのを忘れてた・・・。
突然だけど、急転直下で次回完成!!!
(テキトーですみません)

GoogleMapでマッシュアップの練習(Rails編) #5

4travelにパラメータとして地名を送信するには、返されたXMLの中から地名だけを取りだす必要がある。難しいことはしないけどRubyでXMLをいじった経験はなし。きっとそういうライブラリがあるはず、と思って探すとREXMLというものを発見。日本語情報が少なくここを参考になんとかやってみた。

REXML:RubyによるXML処理

どうもREXMLの日本語情報が少ないようで、これ以上調べるのも時間がかかりそうな気がしたので、見よう見まねでかなり強引に作ってみた。きっともっとスマートな方法があるはず。main_controller.rbにget_name_of_placeというメソッドを追加し、そこにXMLのデータを渡すと都道府県名と都市名を別々にようにした。取得失敗時は取得失敗という文字を返す。

main_controller.rb

require 'net/http'
require 'rexml/document'

class MainController < ApplicationController

  def index
  end
  def search
    #HTTP通信設定
    site = Net::HTTP.start('refits.cgk.affrc.go.jp')

    #地名情報取得
    response = site.get("/tsrv/jp/rgeocode.php?lon=#{params[:x]}&lat=#{params[:y]}")
    resXML = response.body
    site.finish

    #XML要素から都道府県名と都市名を取得する
    pref, munic = get_name_of_place(resXML)

    #画面表示用のテキスト整形
    @resText = "都道府県名:#{pref}  都市名:#{munic}"

    render(:layout => false)
  end

  def get_name_of_place xml
    #XMLツリー作成
    docTree = REXML::Document.new xml

    #ステータス取得(地名の取得が成功したかどうか)
    status = docTree.elements.each("/rgeocode/status"){}[0].text
    return "取得失敗", "取得失敗" if status != "true"

    #都道府県取得
    pref = docTree.elements.each("/rgeocode/prefecture/pname"){}[0].text

    #都市名取得
    munic = docTree.elements.each("/rgeocode/municipality/mname"){}[0].text

    return pref, munic
  end
end

今回もサーバサイドのみの変更なのでそのまま地図をクリック。よし、成功!僕の住んでる近辺を狙って何度かクリックするものの、なかなか難しい。よし、面白くなってきたぞ。

家からは少し離れてるけど・・・

GoogleMapでマッシュアップの練習(Rails編) #4

今度はダミーの文字ではなくて実際にデータを取得しましょう。4travelの旅行記取得APIの仕様を調べたところ、緯度と経度から取得はできないようです。残念。終了。。。。。。。

というわけにもいかないので、何とか実現可能な方法を模索します。地名から旅行記は取得できるようですので地名を取得する方法を考えましょう。Google検索でこんな素晴らしい質問がヒットしました。僕も人力検索使おうかな。

人力検索はてな 緯度経度からだいだいの地名(○県○市くらいの精度で十分です)を得る方法を教えてください。

ここの回答No9の方が紹介されているサイトがこちら(URLは変更されてた。)

逆ジオコーディングサービス

これで方針決定。以下のような2段階処理をすることにしよう。

  • 緯度、経度から地名(都道府県、都市名)を取得
  • その地名で旅行記を取得

まずは1つ目、地名を取得する処理をサーバ側で実装。これはmain_controller.rbのsearchメソッドを修正。ブラウザから送信されたx, yのパラメータを逆ジオコーディングのlon, latパラメータに代入してリクエスト送信でOK。とりあえず返ってきた文字列をそのまま表示するため@resXMLに全文字列を代入。

main_controller.rb

require 'net/http'

class MainController < ApplicationController

  def index
  end

  def search
    #HTTP通信設定
    site = Net::HTTP.start('refits.cgk.affrc.go.jp')

    #地名情報取得
    response = site.get("/tsrv/jp/rgeocode.php?lon=#{params[:x]}&lat=#{params[:y]}")
    @resXML = response.body #とりあえず全結果文字列を表示させる
    site.finish

    render(:layout => false)
  end

  def getNameOfPlace
    #XML要素から都道府県名と都市名を取得する

  end
end

resXMLを返信するためにviewを変更

app/views/main/search.rhtml

<%= @resXML %>

今度の修正はサーバ上のみなのでブラウザの再読み込みは必要なし。そのまま先ほどと同じように地図上をクリック。マジで動いた・・・・。すげぇ。

成功図

GoogleMapでマッシュアップの練習(Rails編) #3

クリックしたら場所をサーバに送信して旅行情報を取得・表示を行う。まずはサーバと通信するところだけを作ってみよう。どこぞのGoogleMapのサンプルで以下のようなコードを拾ってきた。ほぼそのまま使っている。

サーバとの通信部分

function xmlRpc(point){
  var req = GXmlHttp.create();
  req.open("GET", "main/search?x=" + point.x + "&y=" + point.y, true);
  req.onreadystatechange = function(){
    if(req.readyState == 4){
      //dummy
      alert(req.responseXML);
    }
  }

  req.setRequestHeader("Content-Type", "text/html; charset=UTF-8");
  req.send(null);
}

これをトップページに組み込んでクリック時のリスナ関数から呼び出すようにする。

GEvent.addListener(map, 'click', function(overlay, point) {
if (point) {
    alert("x = " + point.x + ", y = " + point.y);
    xmlRpc(point);
  }
});

全体としてこうなった。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google Mapテスト</title>
<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=ABQIAAAABWYMASZTPMzQMXu2alSa6xTvcRCYKSpWpPqDL-sNMuxVdHFI_BTd8zF9kdpV97QhhvGd0NWsQckXsw"
  type="text/javascript"></script>
</head>
<body>
<div id="map" style="width: 500px; height: 500px"></div>
<script type="text/javascript">
//<![CDATA[

if (GBrowserIsCompatible()) {
    var map = new GMap2(document.getElementById("map"));
    map.addControl(new GLargeMapControl());
    map.addControl(new GMapTypeControl());
    map.setCenter(new GLatLng(38, 138), 5);
    map.disableDragging();
}

GEvent.addListener(map, 'click', function(overlay, point) {
    if (point) {
        alert("x = " + point.x + ", y = " + point.y);
        //map.openInfoWindow(point,
        //document.createTextNode("openInfoWindow Test"));

        xmlRpc(point);
    }
});

function xmlRpc(point){
    var req = GXmlHttp.create();
    req.open("GET", "main/search?x=" + point.x + "&y=" + point.y, true); //app/controllers/main_controller.rb のsearchメソッドが呼び出される(パラメータはxが経度、yが緯度)
    req.onreadystatechange = function(){
        if(req.readyState == 4){
            //dummy
            alert(req.responseXML); (←とりあえず結果を表示させるだけ)
        }
    }

    req.setRequestHeader("Content-Type", "text/html; charset=UTF-8");
    req.send(null);
}
//]]>
</script>
</body>
</html>

次はサーバ側の処理。app/controllers/main_controller.rbにsearchメソッドを追加。

class MainController < ApplicationController

    def index
    end

    def search
        render(:layout => false)
    end
end

レイアウトは使用してないけど、画面表示をさせないということから念の為に無効化しています。次にviewを作成。app/views/main/search.rhtmlを以下のように作成します。

dummyString!!

で、ページを再読み込みして地図上をクリック。 緯度、経度が表示された後、「dummyString!!」が表示されれば・・・・

されない・・・

nullが表示されます。なぜだ?と調査開始。サーバのログを見るとsearchメソッドは正常に呼び出されてHTTPレスポンスコードも200。つまりサーバに問題はない。それならクライアント側ってことで、JavaScript部分を見直していると気になったのはこの部分。

alert(req.responseXML);

メソッド名から察するに結果XMLを取得しているわけだが、今回は結果は単なる文字列であってXMLではない。そう思って調査していると以下のページを見つけた。予想は正しくreq.responseTextじゃないというメソッドもあるようだ。

XMLHttpRequest入門【メソッド等の確認とシンプルなコード】

修正後、ページを再読み込みして画面クリックすると、見ごとに「dummyString!!」が表示された。今回はここまで。

GoogleMapでマッシュアップの練習(Rails編) #2

環境

  • Windows上でVMwareにFedoraCore4 + Ruby On Rails(Rubyともにバージョンは現在2007/09/17の最新←テキトーだな)
  • Puttyで接続してvimで開発
  • Googleでキー取得のときに申請したホスト名は本番環境用なので、暫定的にHostsファイルをいじってローカルのFedoraのIPを割り当てる。

Rails でアプリ作成(アプリ名:map)

[obanetty@fedora ~]$rails map

トップページ用のmainコントローラとindexページ作成

 
[obanetty@fedora ~]$script/generate controller main index
 

トップページであるapp/views/main/index.rhtmlにGoogleMapを設置

もう、このサイトの言う通りにやったらすぐにできました。 素晴らしいです。

Geekなぺーじ - Google MAPS APIプログラミング

app/views/main/index.rhtmlの内容


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <title>Google Mapテスト</title>
    <script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=ABQIAAAABWYMASZTPMzQMXu2alSa6xTvcRCYKSpWpPqDL-sNMuxVdHFI_BTd8zF9kdpV97QhhvGd0NWsQckXsw"
      type="text/javascript"></script>
  </head>
  <body>
    <div id="map" style="width: 500px; height: 500px"></div>
    <script type="text/javascript">
    //<![CDATA[
    if (GBrowserIsCompatible()) {
      var map = new GMap2(document.getElementById("map"));
      map.addControl(new GLargeMapControl());
      map.addControl(new GMapTypeControl());
      map.setCenter(new GLatLng(38, 138), 5);
      map.disableDragging();
    }
    GEvent.addListener(map, 'click', function(overlay, point) {
      if (point) {
          alert("x = " + point.x + ", y = " + point.y);
          map.openInfoWindow(point,
          document.createTextNode("openInfoWindow Test"));
      }
    });
    //]]>
    </script>
  </body>
</html>

設定内容は以下(日本列島だけを表示するようにした) + 初期化位置を指定する + コントロールボタンを表示する + 地図をドラッグで移動できないようにする + クリック処理

クリックしたポイントの緯度と経度をalert表示させる処理も入れておいた。alertのスペルを忘れてて2、3度苦戦。

 サーバ起動

[obanetty@fedora map]$ script/server -p 80

80番ポートで起動しないと申請した内容と変わるため。んで80番ポートを使用するには管理者権限が必要だった。

以降はサーバ起動したままで別のPutty窓からアプリを編集。この方がサーバの再起動が必要ないから楽。これはRailのWebrickサーバがデフォルト指定ではdevelopmentモードで起動し、サーバの再起動なしに動的にアプリケーションを読み込んでくれるから。

GoogleMapでマッシュアップの練習(Rails編) #1

マッシュアップをしてみたい。とりあえずGoogleMapでやってみたい。Ruby On Railsも使ってみたい。でもどっちもあんまりやったことない。備忘録程度にその軌跡を残しておこう。

使うもの

  • RubyOnRails
  • GoogleMap
  • 4travel.jp 旅行記検索API

地図上の場所をクリックしたら、その近辺の旅行記が表示されるものでも作ってみる。多分、そんなのすでにどこかにあるだろう。それはわかってる。何事も最初は模倣から。ありきたりなものを作って基礎体力を作る。これが大事なのだと思う今日この頃。

必要な知識

  • JavaScript(Ajax)
  • GoogleMap
  • Ruby On Rails
  • WEB API
  • Linuxサーバ

僕のスペック

  • Java歴・・・5年
  • JavaScript(Ajax)・・・入門
  • GoogleMap・・・初めて
  • Ruby ( On Rails )・・・ だらだらと1年
  • WEB API・・・初めて

上記の知識をある程度前提として、自分が知らなかった部分を中心にメモしているので、このブログを見て同じことをしてもらおうというつもりでは書いていません。部分的にでも誰かの役に立てば、というつもりで書いています。

まとめ記事としてはまた別の場所に書くつもり。では、次回より構築します

«前へ || 1 || 次へ»

Home > googlemap

Search
Feeds

Page Top