:Tips  Android で JSON を使おう 〜 後編 〜



 前回に引き続き「楽天ウェブサービス」で提供されている JSON 形式データを Android で扱う方法をみていきます。

JSON 形式データをオブジェクトとして扱う



 前回までの工程で「楽天ウェブサービス」を使って HTTP サーバから JSON 形式データを受け取り、文字列として保持するというところまでを見てきました。しかし、このままでは「単なる文字列」でしかありません。 JSON 形式データをオブジェクトとして扱うには org.json パッケージの JSONObjectJSONArray クラスを使います。



org.json.JSONObject とは・・・

JSON Data Format での「オブジェクト」に該当するのが JSONObject です。具体的には”{”から始まり”}”までの範囲を指して「オブジェクト」と呼んでいます。コンストラクタは幾つか用意されていますが、今回利用するのはこちらです。

public JSONObject (String json) 

コンストラクタの引数として渡す文字列は、前回 HTTP サーバから受け取った JSON 形式データの文字列です。出来上がった最上位の「オブジェクト」に名前は付いていませんが便宜上”ルート”と表現することにします。この「”ルート”オブジェクト」の構成がどのようになっているのかについては前回確認しましたが、改めて Android 上で再確認してみます。

public class RakutenRanking extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        String json;
        
        ///////// JSON 形式データの取得部分の処理は省略 ////////////
        
        String parsedText = "";
        
        try {
            // オブジェクトの生成
            JSONObject rootObject = new JSONObject(json);
            
            // JSON 形式データ文字列にインデントを加えた形に成形
            parsedText = rootObject.toString(4);
        }
        catch (JSONException e){
            // 例外処理
        }
           
        TextView textView = new TextView(this);
        textView.setHorizontallyScrolling(true);  // 行の折り返しをさせない
        textView.setText(parsedText);             // 成形した文字列を表示
        ScrollView scrollView = new ScrollView(this);
        scrollView.addView(textView);
        setContentView(scrollView, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
    }
}

JSON 形式データの取得部分の処理は長くなるので省略しました。もし実際に確認したい場合は前回のコードを参照してください。

まず最初に、 JSON 形式データ文字列をコンストラクタ引数として渡し JSONObject を初期化します。次に、そのインスタンスに対し、メソッド toString(int indentSpaces) を実行します。この引数 indentSpaces にはインデント(字下げ)する際の空白文字数を指定します。今回は4つとしました。戻り値の文字列には改行とインデントが施された文字列が返ってきます。後は TextView で表示させるわけですが、途中、文字の折り返しにで構造が見づらくならないように TextView#setHorizontallyScrolling() を true とすることで折り返し処理をさせないようにしています。

では表示してみます (図1)


”Body”までスクロールしてみます (図2)




図1が「”Header”オブジェクト」のツリー、図2が「”Body”オブジェクト」のツリー構造部になっているのが分かると思います。今回必要な情報は「個別の書籍情報」ですので、用いるのは「”Body”オブジェクトのツリー側ということになります。 JSONObject でオブジェクトの階層を下って情報を取りに行くには階層毎に JSONObject#getJSONObject() を実行し、直下の JSONObject インスタンスを取りに行くという作業の繰り返しが必要になります。

public JSONObject getJSONObject (String name) 

引数の name には「オブジェクト」の名前を指定します。オブジェクトの名前というのは "Name": {....} の Name 部分を指します(このメソッドを実行して該当する名前の「オブジェクト」が「直下の階層」に見当たらない場合は、JSONException という例外がスローされます)。戻り値は名前で指定された「オブジェクト」のインスタンスです。今回の JSON 形式データの階層構造は、”ルート(無名)”→”Body”→”BooksBookSearch”→”Items”→”Item”→”書籍情報・1(無名)”,”書籍情報・2(無名)”,..... となっていますので、この手順で階層を下りていく必要があります。

// 「”ルート”オブジェクト」
JSONObject rootObject = new JSONObject(json);
// 「”BooksBookSearch”オブジェクト」
JSONObject booksbooksearchObject = rootObject.getJSONObject("BooksBookSearch");
// 「”Items”オブジェクト」
JSONObject itemsObject = booksbooksearchObject.getJSONObject("Items");

この後一気に”Item”→”個別の書籍情報”と行きたいところですが、そうもいきません。”Item”は「オブジェクト」ではなく「配列」だからです。「配列」は JSONObject ではなく JSONArray というクラスを用います。



org.json.JSONArray とは・・・

JSON Data Format での「配列」に該当するのが JSONArray です。具体的には”[”から始まり”]”までの範囲を指して「配列」と呼んでいます。今回はコンストラクタは用いません。 JSONObject#getJSONArray() の戻り値として受け取ります。

public JSONArray getJSONArray (String name) 

引数には「配列」の名前を渡します。配列の名前というのは、具体的には "Name": [......] の Name 部分を指します(このメソッドを実行して該当する名前の「配列」が「直下の階層」に見当たらない場合は、JSONException という例外がスローされます)。

JSONArray itemArray = itemsObject.getJSONArray("Item");

これで「”Item”配列」まで取得できました。残るは個別の書籍情報のみです。



個別の書籍情報を取り出す・・・

「個別の書籍情報」といっても、「書籍名」や「著者名」などの様々なデータの集合体であり {.....} で囲われている限りにおいて「オブジェクト」であることに違いはありません。 JSONArray#getJSONObject() の戻り値として JSONObject のインスタンスとして受け取ります。

public JSONObject getJSONObject (int index)

JSONObject#getJSONObject() との違いは引数の違いにあります。こちらは「名前」ではなく「インデックス」を指定します。「インデックス」の番号は Java の配列同様に 0 〜 n-1 の値であり、 "Name": [ 0: {..}, 1: {..}, ,... n-1: {..} ] と左側から記述された順番に昇順となります。「配列」に幾つの「オブジェクト(または「配列」または「データ」)」があるのかは、 JSONArray#length() で求めることが出来ます。これをループカウンターにして「配列」内の全ての「”書籍情報”オブジェクト」を取り出します。

int count = itemArray.length();
JSONObject[] bookObject = new JSONObject[count];
for (int i=0; i<count; i++){
    bookObject[i] = itemArray.getJSONObject(i);
}

これで情報(「データ」)を取るための準備が整いました。ちなみに、今取り出した bookObject[0] は、今回の検索条件の下では「売り上げ第1位の書籍」ということになります。



個別の書籍情報の「データ」を取り出す・・・

「データ」とは "name": value という形で表された情報を指します。図2でいえば、bookObject[0] の "title": "ONE PIECE (巻58)", や "author": "尾田栄一郎", 等が「データ」です。左側 name の部分は必ず文字列になっており、対の右側は文字列や数値やブール値などがあります( "" で括られていれば数値だけが記述されていてもそれも「文字列」です)。「データ」を取り出すメソッドは其々右側 value 部分の型ごとに用意されています。

public String getString (String name)
public int getInt (String name) 
public long getLong (String name) 
public double getDouble (String name) 
public boolean getBoolean (String name) 

戻り値の型は其々ですが、引数は「データ」の name 、戻り値は「データ」の value です。

それでは「個別の書籍情報」の「売り上げ順位」と「書籍名」を TextView に表示する簡単なサンプルです。

public class RakutenRanking extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        String scheme = "http";
        String authority = "api.rakuten.co.jp";
        String path = "/rws/3.0/json";
        
        String developerId = "??????????";
        String operation = "BooksBookSearch";
        String version = "2010-03-18";
        String size = "0";
        String hits = "10";
        String sort = "sales";
        
        Uri.Builder uriBuilder = new Uri.Builder();
        
        uriBuilder.scheme(scheme);
        uriBuilder.authority(authority);
        uriBuilder.path(path);
        uriBuilder.appendQueryParameter("developerId", developerId);
        uriBuilder.appendQueryParameter("operation", operation);
        uriBuilder.appendQueryParameter("version", version);
        uriBuilder.appendQueryParameter("size", size);
        uriBuilder.appendQueryParameter("hits", hits);
        uriBuilder.appendQueryParameter("sort", sort);
        
        String uri = uriBuilder.toString();
        
        HttpClient httpClient = new DefaultHttpClient();
        HttpParams params = httpClient.getParams();
        HttpConnectionParams.setConnectionTimeout(params, 1000);
        HttpConnectionParams.setSoTimeout(params, 1000);
        
        HttpUriRequest httpRequest = new HttpGet(uri);
        
        HttpResponse httpResponse = null;
        
        try {
            httpResponse = httpClient.execute(httpRequest);
        }
        catch (ClientProtocolException e) {
            //例外処理
        }
        catch (IOException e){
            //例外処理
        }
        
        String json = null;
        
        if (httpResponse != null && httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
            HttpEntity httpEntity = httpResponse.getEntity();
            try {
                json = EntityUtils.toString(httpEntity);
            }
            catch (ParseException e) {
                //例外処理
            }
            catch (IOException e) {
                //例外処理
            }
            finally {
                try {
                    httpEntity.consumeContent();
                }
                catch (IOException e) {
                    //例外処理
                }
            }
        }
        
        httpClient.getConnectionManager().shutdown();
        
        // TextView 表示用のテキストバッファ
        StringBuffer stringBuffer = new StringBuffer();
        
        try {
            JSONObject rootObject = new JSONObject(json);
        	   JSONObject bodyObject = rootObject.getJSONObject("Body");
            JSONObject booksbooksearchObject = bodyObject.getJSONObject("BooksBookSearch");
            JSONObject itemsObject = booksbooksearchObject.getJSONObject("Items");
            JSONArray  itemArray = itemsObject.getJSONArray("Item");
            
            int count = itemArray.length();
            
            JSONObject[] bookObject = new JSONObject[count];
            
            for (int i=0; i<count; i++){
            	bookObject[i] = itemArray.getJSONObject(i);
            }
            
            for (int i=0; i<bookObject.length; i++){
                  // 書籍の売り上げランキング
            	int rank = i + 1 ;
                  // 書籍名のデータを取得
            	String title = bookObject[i].getString("title");
            	// 「売り上げランキング」+「書籍名」をテキストに追加
            	stringBuffer.append(rank + "位" + "\n");
            	stringBuffer.append(title + "\n");
            }
        } 
        catch (JSONException e) {
            // 例外処理
        }
        
        TextView textView = new TextView(this);
        textView.setHorizontallyScrolling(true);
        textView.setText(stringBuffer);
        ScrollView scrollView = new ScrollView(this);
        scrollView.addView(textView);
        setContentView(scrollView, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
    }
}

実際に動かしてみます。


以上です。



次回は・・・

ようやく下準備が出来たので。本題の ListView の表示の話をします。