今回の環境

Mac OS X Yosemite 10.10.2


$ uname -mrsv
Darwin 14.1.0 Darwin Kernel Version 14.1.0: Thu Feb 26 19:26:47 PST 2015; root:xnu-2782.10.73~1/RELEASE_X86_64 x86_64

Node.js はインストール済み。


$ node -v
v0.10.29

$ npm -v
1.4.14

プログラム開発の準備: package.json ファイルを用意する

package.json には今回開発するプログラムの内容について記述する。

npm init コマンドを打つと、対話形式で項目を入力していき、 package.json ファイルを生成してくれる。


$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sane defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (hoge) revgeo
version: (0.0.0) 
description: reverse geocoder
entry point: (index.js) 
test command: 
git repository: 
keywords: 
author: nilab
license: (ISC) 
About to write to /Users/alice/hoge/package.json:

{
  "name": "revgeo",
  "version": "0.0.0",
  "description": "reverse geocoder",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "nilab",
  "license": "ISC"
}


Is this ok? (yes)

生成された package.json には不要な項目もあるので、手動で修正してこんな感じに。


{
  "name": "revgeo",
  "version": "0.0.0",
  "description": "reverse geocoder",
  "main": "index.js",
  "author": "nilab"
}

プログラム開発の準備: xml2js モジュールをインストールする

今回は、 xml2js モジュールを使うので、 npm install コマンドでインストールする。

--save オプションを付けると、 package.json に xml2js の情報を追加してくれる。


$ npm install --save xml2js
npm WARN package.json revgeo@0.0.0 No repository field.
npm WARN package.json revgeo@0.0.0 No README data
xml2js@0.4.6 node_modules/xml2js
├── sax@0.6.1
└── xmlbuilder@2.6.2 (lodash@3.5.0)

package.json に dependencies の項目が追加された。


{
  "name": "revgeo",
  "version": "0.0.0",
  "description": "reverse geocoder",
  "main": "index.js",
  "author": "nilab",
  "dependencies": {
    "xml2js": "^0.4.6"
  }
}

バッチプログラムを開発する

今回は、緯度,経度を指定すると、住所を出力してくれるプログラムを作る。

緯度と経度から住所を求めるために、Web API を利用する。
YOLP(地図):Yahoo!リバースジオコーダAPI - Yahoo!デベロッパーネットワーク

プログラム自体は index.js と reverse_geocoder.js の2つのファイルを追加してそこに書く。

index.js ファイル:


var revgeo = require("./reverse_geocoder");

// process.argv[2]以降にコマンドライン引数が入る
for(var i=2; i<process.argv.length; i++){

  // パラメータを取得
  var p = process.argv[i];

  // 緯度・経度はカンマ区切りで指定
  var ll = p.split(",");

  // 緯度経度から場所の情報を取得する
  var geo = revgeo.reverse_geocoding(ll[0], ll[1], function(data){
    console.log("INPUT: " + ll[0] + "," + ll[1] + "\n");
    console.log("XML:\n" + data.xml + "\n");
    console.log("RESPONSE:\n");
    console.dir(data.data);
    console.log("\n");
    console.log("ADDRESS: " + data.address + "\n");
  });
}

reverse_geocoder.js ファイル:


var http = require("http");
var querystring = require("querystring");
var xml2js = require("xml2js");

// 住所文字列を返す
// lat: 緯度
// lon: 軽度
// callback: コールバック関数
function reverse_geocoding(lat, lon, callback){

  // クエリー文字列を組み立てる
  var qs = querystring.stringify({
    lat: lat,
    lon: lon,
    appid: "<YOUR APPLICATION ID>"
  });

  var path = "/OpenLocalPlatform/V1/reverseGeoCoder?" + qs;

  var opts = {
    host: "reverse.search.olp.yahooapis.jp",
    port: 80,
    path: path,
    method: "get"
  };

  // Web API をコールする
  var req = http.request(opts, function(res){

    console.log("STATUS: " + res.statusCode + "\n");
    console.log("HEADERS: " + JSON.stringify(res.headers) + "\n");

    var body = "";
    res.setEncoding('utf8');

    res.on('data', function (chunk) {
      body += chunk;
    });

    res.on('end', function () {

      var opts = {
        trim: true,
        explicitArray: false
      };

      // Web API のレスポンス XML を JavaScript オブジェクトへ変換
      xml2js.parseString(body, opts, function(err, result){

        // 結果のオブジェクトを生成
        var data = {
          xml: body,
          data: result,
          address: result.YDF.Feature.Property.Address
        };

        // コールバック関数を呼ぶ
        callback(data);
      });
    });

    res.on('error', function (e) {
      console.log("error: " + e.message);
    });
  });

  req.end();
}

module.exports = {
  reverse_geocoding: reverse_geocoding
}

開発したバッチプログラムを実行する

実行するには、node コマンドの引数に index.js を指定し、その後の引数に緯度,経度を指定する。

実行すると、住所が出力される。
また、Web API コール結果の XML などもデバッグ情報的に出力している。

実行結果:


$ node index.js 35.170914,136.882895
STATUS: 200

HEADERS: {"date":"Sat, 28 Mar 2015 10:19:03 GMT","x-frame-options":"SAMEORIGIN","cache-control":"private","vary":"Accept-Encoding","content-length":"1820","content-type":"application/xml; charset=UTF-8","age":"0","connection":"close"}

INPUT: 35.170914,136.882895

XML:
<?xml version="1.0" encoding="UTF-8"?>
<YDF firstResultPosition="1" totalResultsAvailable="1" totalResultsReturned="1" xmlns="http://olp.yahooapis.jp/ydf/1.0">
  <ResultInfo>
    <Count>1</Count>
    <Total>1</Total>
    <Start>1</Start>
    <Latency>0.0029189586639404</Latency>
    <Status>200</Status>
    <Description>指定の地点の住所情報を取得する機能を提供します。</Description>
    <Copyright>Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved.</Copyright>
    <CompressType />
  </ResultInfo>
  <Feature>
    <Property>
      <Country>
        <Code>JP</Code>
        <Name>日本</Name>
      </Country>
      <Address>愛知県名古屋市中村区名駅1丁目1-4</Address>
      <AddressElement>
        <Name>愛知県</Name>
        <Kana>あいちけん</Kana>
        <Level>prefecture</Level>
        <Code>23</Code>
      </AddressElement>
      <AddressElement>
        <Name>名古屋市中村区</Name>
        <Kana>なごやしなかむらく</Kana>
        <Level>city</Level>
        <Code>23105</Code>
      </AddressElement>
      <AddressElement>
        <Name>名駅</Name>
        <Kana>めいえき</Kana>
        <Level>oaza</Level>
      </AddressElement>
      <AddressElement>
        <Name>1丁目</Name>
        <Kana>1ちょうめ</Kana>
        <Level>aza</Level>
      </AddressElement>
      <AddressElement>
        <Name>1</Name>
        <Kana>1</Kana>
        <Level>detail1</Level>
      </AddressElement>
      <Building>
        <Id>B@2sMmGd9uz</Id>
        <Name>JRセントラルタワーズ</Name>
        <Floor>18</Floor>
        <Area>6284</Area>
      </Building>
    </Property>
    <Geometry>
      <Type>point</Type>
      <Coordinates>136.882895,35.170914</Coordinates>
    </Geometry>
  </Feature>
</YDF>

RESPONSE:

{ YDF: 
   { '$': 
      { firstResultPosition: '1',
        totalResultsAvailable: '1',
        totalResultsReturned: '1',
        xmlns: 'http://olp.yahooapis.jp/ydf/1.0' },
     ResultInfo: 
      { Count: '1',
        Total: '1',
        Start: '1',
        Latency: '0.0029189586639404',
        Status: '200',
        Description: '指定の地点の住所情報を取得する機能を提供します。',
        Copyright: 'Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved.',
        CompressType: '' },
     Feature: { Property: [Object], Geometry: [Object] } } }


ADDRESS: 愛知県名古屋市中村区名駅1丁目1-4

緯度 35.170914 経度 136.882895 の住所は「愛知県名古屋市中村区名駅1丁目1-4」と出力された。

開発したバッチプログラムを配布する

他の環境でも同様に実行したい場合、配布に必要なファイルは package.json, index.js, reverse_geocoder.js の3ファイル。

この3ファイルを実行したい環境の任意のディレクトリに置いて、 npm install コマンドを打つと、必要なモジュール (今回は xml2js モジュール) を自動的にインストールしてくれる。

npm install コマンドは package.json の dependencies を参照して、必要なモジュールを判断している。


$ npm install
npm WARN package.json revgeo@0.0.0 No repository field.
npm WARN package.json revgeo@0.0.0 No README data
xml2js@0.4.6 node_modules/xml2js
├── sax@0.6.1
└── xmlbuilder@2.6.2 (lodash@3.5.0)

これで、開発時と同じように「$ node index.js 緯度,経度」というようなコマンドで、バッチプログラムを実行できるようになる。

参考資料

tags: node.js

Posted by NI-Lab. (@nilab)