JSONデータの解析
前回、天気情報を取得するWeb APIを解説しましたが、取得するデータがやや複雑なため、今回は、緯度と経度から都道府県を判別するシンプルなWeb APIを用いて、JSONデータの解析を説明します。
緯度と経度から都道府県を判別する
緯度と経度から都道府県を判別するのは、Web APIを利用しなくても可能です。ただし、都道府県の位置データを参照する必要があり、けっこう面倒な処理になってしまいます。このような場合、Web APIを利用するのも一つの解決策です。Web APIであれば、とても短いコードで判定することができます。
今回利用するWeb APIは、独立行政法人農業・食品産業技術総合研究機構から無料で提供されている「簡易逆ジオコーディングサービス」です。
ちなみに、ジオコーディングとは、地名や住所から緯度・経度を求めることです。対して、緯度と経度から住所を求めることを、逆ジオコーディング(リバースジオコーディング)と呼びます。
このWeb APIのURLは、http://www.finds.jp/ws/rgeocode.phpです。次に示すパラメータを用いて呼び出します。
パラメータ | 意味 |
---|---|
lat | 検索対象点の緯度(北緯を正とする10進の度) |
lon | 検索対象点の経度(東経を正とする10進の度) |
json | JSON形式にする場合に指定 |
例えば、皇居の緯度経度から住所を求めるには、次のようなURLです。
結果は、次のようなJSONデータです。東京都千代田区千代田1、という住所が取得できていることが、なんとなく分かるのではないでしょうか。
{ "status": 200, "result": { "prefecture": { "pcode": 13, "pname": "東京都" }, "municipality": { "mname": "千代田区", "mcode": 13101 }, "local": [ { "section": "千代田", "homenumber": "1", "distance": "155.674225497647", "latitude": "35.683934", "longitude": "139.75289" } ] }, "argument": { }, "meta": [ ] }
ただし、実際のデータには、空白や改行はありません。ここでは理解しやすいように、JSONデータを整形しています(また、一部データを省略しています)。
今回のアプリでは、このJSONデータを解析して、該当する地点の都道府県コードを取得します。
JSONデータを解析するには
JSON(JavaScript Object Notation)とは、その名前のとおりJavaScriptの表記法を元にした、軽量なデータ記述言語です。さきほどのサンプルから分かるように、文字列のキー(フィールド)と値(プロパティ)のペアが基本となっています。
XML同様JSONでも、多くのソフトウェアやプログラミング言語間でのデータ授受に利用されています。当然Android(Java)でも利用することができ、手軽にJSONが使えるようなオープンソースのライブラリが、いくつも公開されています。
Android SDKにも、org.jsonパッケージとして標準的なライブラリが含まれています。ただこのライブラリは、解析処理スピードが遅く、APIもやや低レベルなものしかないため、あまり評判がよくありません。
そこで今回は、パフォーマンスの点で評価の高いJackson(Jackson Java JSON-processor)を利用することにしました。Jackson以外では、JSONICや、google-gsonといったライブラリが有名です。
Jacksonとは
Jacksonは、オープンソースのJSONライブラリで、AndroidのJavaでも利用することができます。
Jacksonでは、おもに次の3種類の方法でJSONデータを扱うことが可能です。
- ストーミングAPIでのアクセス(XMLのStAXに相当にする)
- ツリーモデルでのアクセス(XMLのDOMに相当する)
- JSONとJavaオブジェクトとのデータバインディング
ストリーミングAPIは、データを先頭から順にアクセスする方法です。大きなデータであっても高速に動作しますが、特定のデータのみを取り出したい場合などには不向きです。そこで今回は、データ量も少ないので、ツリーモデルのAPIを利用することにします。
このツリーモデルのAPIは、いったんすべてのJSONデータを読み込んで、オブジェクトのツリーを生成するものです。そのため、目的のノードを指定することで、後から自由にデータを参照することができます。
なお、データバインディングとは、JSONオブジェクトをそのままJavaのオブジェクトに変換する方法です。JSONに含まれるデータをすべて使用する場合や、相互に変換する必要があれば便利ですが、今回は一部のデータしか参照しませんので、ツリーモデルAPIがもっともシンプルな実装になります。
Jacksonを利用する
Jacksonを利用するには、ダウンロードページから、以下のライブラリ(jarファイル)をダウンロードして、あらかじめプロジェクトのlibsフォルダにコピーしておきます。
ファイル名 | 内容 |
---|---|
jackson-core-2.2.0.jar | Coreライブラリ |
jackson-databind-2.2.0.jar | ツリーモデルライブラリ |
jackson-annotations-2.2.0.jar | データバインディング |
JacksonライブラリのツリーモデルAPIを利用するのは、とてもかんたんです。以下のコードは、先ほどの住所情報が含まれるJSON文字列を解析して、住所コードを求めるものです。
ParseJson.javaの一部] class ParseJson { protected String content; protected JsonNode getJsonNode(String str) { try { // JSON文字列を、JsonNodeオブジェクトに変換する(1) return new ObjectMapper().readTree(str); } catch (IOException e) { Log.d(getClass().getName(), e.getMessage()); } return null; } ~中略~ }
// JSON文字列から都道府県コードを取得する public class ParseFindsjp extends ParseJson { @Override public void loadJson(String str) { JsonNode root = getJsonNode(str); if (root != null){ // ツリーオブジェクトから都道府県コードを取得する(2) this.content = root.path("result").path("prefecture") .path("pcode").asText(); } } }
解析処理を、基本クラスと派生クラスに分割しています。今回は2種類のJSONデータを解析する必要がありますので、共通の処理を基本クラスとしてまとめました。
基本クラスでは、JSON文字列をJsonNodeオブジェクトに読み込み(getJsonNodeメソッド)、派生したクラスのメソッドで、そのツリーを解析しています。
オブジェクトのツリーを構築するには、Jacksonライブラリで提供されるObjectMapperというクラスを利用します(1)。このクラスのreadTreeメソッドは、引数のJSON文字列からツリーを生成するメソッドです。戻り値は、ツリー構造のルートを示すJsonNodeというオブジェクトになっています。
JsonNodeオブジェクトは、複数の子ノードと、それにひもづいたフィールドの情報を保持しています。
このサンプルで取得している都道府県コードは、以下のようなノードに含まれています。
result ─ prefecture ┬ pcode: 13 └ pname: 東京都
JsonNodeクラスのpathメソッドは、指定のノードのオブジェクトを返すメソッドです。このメソッドではメソッドチェーンが使えますので、直感的に理解しやすい実装が可能です(2)。asText()メソッドは、プロパティを文字列として取得します。ここでは、13という東京都のコードを、文字列として取得しています。
なおpathメソッドでは、存在しないノードを指定した場合、MissingNodeというオブジェクトを返します。このオブジェクトは、JsonNodeのメソッドをすべて実装していますので、どのようなデータに対しても例外が発生せず、メソッドチェーンが利用可能です。