本格派エンジニアの工具箱

第28回 「Jackson Java JSON-processor」でJSONデータの読み書きを行う

この記事を読むのに必要な時間:およそ 3.5 分

ツリーモデルAPIでJSONデータを読み込む

前回は「Jackson Java JSON-processor」(以下,Jackson)のストリーミングAPIを利用して,JavaプログラムからJSON形式のデータにアクセスする方法を解説しました。今回はそれに引き続き,ツリーモデルのAPIを使う方法を紹介します。JacksonのツリーモデルAPIは,XMLのDOM APIに相当するもので,一度メモリ上に全てのデータを読み込んでオブジェクトのツリーを構築するため,先頭から順番にデータを読み込むストリーミングAPIに比べて柔軟なデータアクセスが可能です。

ツリーモデルの核になるのは,ブジェクトツリーのノードを表すJsonNodeクラスです。JsonNodeオブジェクトは,複数の子ノードと,それに紐付くフィールド名の情報を保持しています。子ノードを表すJsonNodeオブジェクトはget()メソッドで取得することができます。JsonNodeが配列のノードを表すものである場合には,get()メソッドの引数には取得したいノードのインデックスを整数で指定します。JsonNodeがオブジェクトを表すものである場合にはフィールド名を文字列で指定します。JsonNodeが文字列や数値などの値を持つものである場合には,getXxxxValue()というメソッドでその値を取得できます。文字列の値であればgetStringValue()メソッドです。なお,これらのノードの種類はorg.codehaus.jackson.nodeパッケージ以下のXxxxNodeクラスで区別されます。

// 配列のノードから2番目の子ノードを取得
JsonNode secondNode = node.get(2);

// オブジェクトのノードからフィールド名「name」のノードを取得
JsonNode nameNode = node.get("name");

// ノードから文字列値を取得
String value = node.getStringValue();

ファイルかデータを読み込んでツリーを構築するにはObjectMapperクラスを利用します。まず,ObjectMapperのreadValue()メソッドを用いてルートノードのJsonNodeオブジェクトを取得しましょう。readValue()の第一引数には読込み元のFileオブジェクトや入力ストリームを,第二引数にはJsonNodeのClassオブジェクトを指定します。

// ObjectMapperを作成
ObjectMapper mapper = new ObjectMapper();
// mydata.jsonからルートノードを取得
JsonNode rootNode = mapper.readValue(new File("mydata.json"), JsonNode.class);

今回は,次のようなJSONデータを読み込むケースを考えてみます。

[{
  "name" : { "first" : "太郎", "last" : "技評" }, 
  "mail" : "taro@example.jp"
}, 
{
  "name" : { "first" : "次郎", "last" : "技術" }, 
  "mail" : "jiro@example.jp"
}, 
{
  "name" : { "first" : "花子", "last" : "評論" }, 
  "mail" : "hanako@example.jp"
}]

このデータを読み込んで,その内容を表示するコードの例は次のようになります。

// ObjectMapperを作成
ObjectMapper mapper = new ObjectMapper();
// ルートノードを取得
JsonNode rootNode = mapper.readValue(new File("mydata.json"), JsonNode.class);
      
JsonNode current;
for (int i=0; (current = rootNode.get(i)) != null; i++) {
    // "name"オブジェクトのノードを取得
    JsonNode nameNode = current.get("name");
    System.out.println("name: ");
    // "name"オブジェクトのフィールドデータを取得して表示
    Iterator<String> nameNodeFields = nameNode.getFieldNames();
    while (nameNodeFields.hasNext()) {
	String nameNodeField = nameNodeFields.next();
	System.out.println("    " + nameNodeField + ": " + nameNode.get(nameNodeField));
    }
    
    // "mail"フィールドのノードを取得してデータを表示
    JsonNode mailNode = current.get("mail");
    System.out.println("mail: " + mailNode.getTextValue());
}

この例では,ルートノードと"name"オブジェクトには子ノードがいくつあっても走査できるようになっています。配列ノードに対するget()メソッドは,対象のノードが存在しない場合にはnullを返すので,これを終了条件にしています。オブジェクトノードからは,getFieldNames()メソッドでフィールド名のリストがIteratorオブジェクトとして取得できるため,すべての子ノードを走査する場合に利用できます。

name: 
    first: "太郎"
    last: "技評"
mail: taro@example.jp
name: 
    first: "次郎"
    last: "技術"
mail: jiro@example.jp
name: 
    first: "花子"
    last: "評論"
mail: hanako@example.jp

このコードを実行すると,コンソールには次のように表示されて,データが読み込めていることが確認できます。

著者プロフィール

杉山貴章(すぎやまたかあき)

ONGS Inc.所属のプログラマ兼テクニカルライター。雑誌,書籍,Webメディアで多数の著作をもつ。

著書

コメント

コメントの記入