ウェブアプリケーション,インジェクション,コマンドインジェクション

Androidアプリ開発 ネットワークプログラミング

JSONウェブサービスを実行

Consuming JSON Web Services

XMLウェブサービスは別として、
他のウェブサービスのタイプとして、JSON、
(JavaScript Object Notation)が一般的になってきています。
JSONは人間とコンピュータで処理させやすいように設計された
データを強調する交換フォーマットです。
XMLドキュメントではデータの意味を表現するためにタグを使いますが、
JSONでは波カッコ”{”、”}”、コロン”,”、角カッコ”[”、"]"を
名前/値のペアや配列でデータを編成します。
ここでは、開発するAndroidアプリケーションで
JSONウェブサービスをどのように消費するかを示します。
これから2つのJSONウェブサービスを使っていきます。
●GeoNames JSONウェブサービス
ロケーションが与えられているかどうかを返すサービスを提供します。
JSON文字列として結果が返されます。
●GeoNames 郵便番号検索
検索で与えられた郵便番号と一致している市町村のリストを
返すサービスを提供します。


ちょっと注釈

この例はサードパーティのウェブサービスが動くプロパティに
依ります。この例では、geoname.orgのポリシーを使い
アクセスできる元で、デモアカウントを使います。
すべてのアカウントと同じように、デモアカウントはそれぞれの
24時間ごとにどのくらい検索語がサービスされているか制限されています。
もしここにあるコードを試したときに説明のないエラーを受け取ったと
したら、デモアカウントは制限いっぱいに達したと考えられます。
開発者自身のデモアカウントのサイトで登録していれば、
この問題を回避できます。
登録や追加の情報はhttp://www.geoname.org/loginで入手可能です。


ウェブサービスに接続し、帰ってくるJSON文字列を取得するためには、
単純にHTTP GETかPOSTを使ってサーバに接続します。
(より簡単にするために、この例ではHTTP GETを使っています。
HTTP GETのことはHTTP GETでサーバに接続する
見てください。)
そしてその時JSONフォーマットで返ってくる文字列を取得します。
JSONオブジェクトを取得するためのreadJSONFeed()メソッドは
以下の様になります。

public String readJSONFeed(String URL){
  StringBuilder stringBuilder = new StringBuilder();
  HttpClient httpClient = new DefaultHttpClient();
  HttpGet httpGet = new HttpGet(URL);
  try{
   HttpResponse response = httpClient.execute(httpGet);
   StatusLine statusLine = response.getStatusLine();
   int statusCode = statusLine.getStatusCode();
   if (statusCode == 200){
    HttpEntity entity = response.getEntity();
    InputStream inputStream = entity.getContent();
    BufferedReader reader = new BufferedReader(
        new InputStreamReader(inputStream));
    String line;
    while ((line = reader.readLine()) != null){
     stringBuilder.append(line);
    }
    inputStream.close();
   }else{
    Log.d("readJSONFeed", "Failed to download file");
   }
  }catch (Exception e){
   Log.d("readJSONFeed", e.getLocalizedMessage());
  }
  return stringBuilder.toString();
}

JSONウェブサービスを実行することで最適な残りの課題は、
返って来たJSON文字列を構文解析していることです。
最初に使っていくサービスで対となる緯度、経度の値を渡し、
位置に関する情報かどうかを返します。
例えば以下のような結果が返って来ます。

{
  "weatherObservation":{
   "clouds": "scattered clouds",
   "weatherCondition": "n/a",
   "observation":"KCFV 09852Z AUTO 06005KT 10SM
   SCT030 SCT110 24/20 A3000 RMK A02 SLO148 T02390200 53002",
   windDirection":60,
   ICAO":"KCFV",
   "seaLevelPressure":1014.8,
   "elevation":225,
   "lng":-95.56666666666666,
   "temperature":"23.9",
   "dewPoint":"20",
   "windSped":"05",
   "humidity":78,
   "stationName":"Coffeyville, Coffeyville Municipal Airport",
   "datetime":"2012-07-09-08:52:00",
   lat":37.08333333333336
  }
}

ウェブサービスに接続しJSONの結果を構文解析するために、
以下のようなクラスを作ることができます。

private class ReadWeatherJSONFeedTask extends AsyncTask<String, Void, String>{
  protected String doInVackground{
   return readJSONFeed(urls[0]);
  }

  protected void onPostExecute(String result){
   try{
    JSONObject jsonObject = new JSONObject(result);
    JSONObject weatherObservationItems =new JSONObject(
       jsonObject.getString("weatherObservation"));

    Toast.makkeText(getBaseContext(),
     weatherObservationItems.getString("clouds") +
     " - " + weatherObservationItems.getString("stationName"),
     Toast.LENGTH_LONG).show();
   }catch(Exception e){
    Log.d("ReadWeatherJSONFeedTask", e.getLocalizedMessage());
   }
  }
}

以下のようなことに注目することが重要です。
●キー/値の地図作成でJSONオブジェクトの中で
JSON文字列を変換するためのJSONObjectクラスを使うこと。
●JSONObjectクラスのgetString()メソッドは、
キーで指定された値を返します。この例では、
weatherObservationキーの値を返しています。
この返ってくる結果はその時にJSONオブジェクトに変換されます。
●JSONオブジェクト内部のそれぞれ個々のキーの値を検索できます。
上の例での、clouds、stationNameなどのように。
ReadWeatherJSONFeedTaskクラスを使うためには、
以下のようなステートメントを使います。

new ReadWeatherJSONFeedTask().execute{
  "http://ws.geonames.org/findNearByWeatherJSON?lat=" +
    txtLat.getEditableText().toString() + "&lng=" +
    txtLong.getText().toString());

他の例を見ていきます。
2番目のウェブサービスは郵便番号で指定された市町村リストを返します。
ウェブサービスからの結果は次の様になります。

{
  "postlCodes": [
   {
    "adminCode3":"3203",
    "adminName2":"Wahlkreis St.Gallen",
    "adminName3":St.Gallen",
    "adminName2":"1721",
    "adminName1":"SG",
    "postalCode":"9011",
    "countryCode":"CH",
    "lng":9.399858534040646,
    "placeName":"St. Gallen",
    "lat":47.414775328611945,
    "adminName1":"Kanton St. Gallen"
   },
   {
    "adminCode1":"GS",
    "postalCode":"9011",
    "countryCode":"HU",
    "lng":17.781944437499998,
    "placeName":"Gyor",
    "lat":47.607638900000005,
    adminName1":"Gyor-Moson-Sopron"
   },
   {
    "adminName2":"TromsΘ",
    "adminCode2":"1902",
    "adminCode1":"19",
    "postalCode":"9011",
    "countryCode":"NO",
    "lng":18.95508,
    "placeName":"Troms",
    "lat":69.6489,
    #adminName1":"Troms"
   },
   {
    .........
   }
  }
}

ウェブサービスを使うためには、以下のようなクラスを作ることができます。

private class ReadPlacesFeedTask extends AsyncTask<String, Void, String>{
  protected String doInBackground(Stringd... this){
   return readJSONFeed(urls[0]);
  }

  protexted void onPostExecute(String result){
   try{
    JSONObject jsonObject = new JSONObject(result);
    JSONArray postalCodesItems = new
     JSONArray(jsonObject.getString("postalCodes"));

    //---print out the content of the json feed---
    for (int i = 0; i < postalCodesItems.length(); i++){
     JSONObject postalCodesItem =
      postalCodesItems.getJSONObject(i);
     Toast.makeText(getBaseContext(),
      postalCodesItem.getString("postalCode") + " - " +
      postalCodesItem.getString("placeName") + ", " +
      postlCodesItem.getString("countryCode"),
      Toast.LENGTH_SHORT).show();
     }
    } catch(Exception e){
     Log.d("ReadPlacesFeedTask", e.getLocalizedMessage());
    }
   }
  }

上のコードでは以下のような所に注目するのが重要です。
●キー/値の地図作成でJSONオブジェクトの中に
JSON文字列を変換するためにJSONObjectクラスを使います。
●JSONObjectクラスのgetString()メソッドは
キーで指定された値を返します。この例では、
このメソッドはpostalCodesキーの値を返してます。
返ってくる結果はその時にJSONArrayオブジェクトに変換され、
変換されたものはJSONオブジェクトの配列に格納されます。
●JSONArray中を繰り返し、個々のキーの値を
それぞれのJSONオブジェクトが引き出します。
postalCode、placeName、countryCodeなどがそうです。
ReadPlacesFeedTaskクラスを使うために、
以下のようなステートメントを使います。

new ReadPlacesFeedTask().execute{
  "http://api.geonames.org/postalCodeSearchJSON?postalcode=" +
  txtPostalCode.getEditableText().toString() +
  "&maxRows=10&username=demo");
ホーム
便利堂ロゴ
inserted by FC2 system