JSONパーサー「UtlJson」


2010/12/27 ページ作成
2011/09/05 最終更新
クロノス・クラウン合同会社
柳井政和
HP:http://crocro.com/
Twitter:http://twitter.com/ruten

はじめに

200行程度で動作する、JAVA製のJSONパーサー「UtlJson」です。

車輪の再発明っぽいものですが、作成する必要が生じたので、簡単なプログラムを書きました。短いプログラムですので、自由に改造して、ご利用いただければと思います。

作成の背景

拙作ゲームアプリ「Army & Maiden」の開発に伴い、AndroidとPCコンパチで動作するゲーム開発ライブラリを作成しました。

Army & Maiden PC版、Android版、アプレット版 まとめページ

そのため、PCとAndroidで、共通で動くJSONパースライブラリが必要になりましたので自作しました(既存のライブラリを使うという手もあったのですが、ProGuardに引っ掛かってしまい、上手く動作しませんでした)。

200行ほどの短いプログラムですので、全文をそのまま掲載します。自由にコピペしてご利用していただいて結構です。あまり検証はしていないので、バグなどがあるかもしれません。バグを修正された方はフィードバックをいただければと思います。反映したいと思います。

(2011/09/05 バグの報告を受けてバージョンアップ)

それでは以下、ソースコードと使い方を掲載します。

JSONパース用クラスのソースコード

package com.crocro.wrp.utl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

public class UtlJson {
    //------------------------------------------------------------
    //-- メンバー変数
    //------------------------------------------------------------

    // 解析
    private String mSrcStr;
    private int mPos;   // 解析位置
    private int mLen;   // 文字列長

    // デバッグ
    private static String NST_TB = "  ";    // ネスト用タブ

    //------------------------------------------------------------
    //-- prs | JSONのパース
    //------------------------------------------------------------
    /*
     * JSONのパース。なんちゃってパースなので、正確な処理は行っていないので注意。
     * 配列はArrayList、ハッシュはHashMapで作成する。
     * @param srcStr    元文字列
     * @return 解析後のオブジェクト
     */
    public Object prs(String srcStr) {
        // エラー対策
        if (srcStr == null || srcStr.length() == 0) return null;

        // 変数の初期化
        Object resObj = null;

        mSrcStr = srcStr;
        mPos = 0;
        mLen = srcStr.length();

        // 括弧の探索
        for (; mPos < mLen; mPos ++) {
            char c = srcStr.charAt(mPos);
            if (c == '[') {
                // 配列である
                resObj = prsArr();
            } else
            if (c == '{') {
                // ハッシュである
                resObj = prsHsh();
            }
        }

        // 戻り値を戻して終了
        return resObj;
    }

    //------------------------------------------------------------
    //-- prsArr | 配列のパース
    //------------------------------------------------------------
    /*
     * 配列のパース。
     * @return 解析後の配列
     */
    public Object prsArr() {
        // 変数の初期化
        ArrayList<Object> al = new ArrayList<Object>();

        // 内部の探索
        for (mPos ++; mPos < mLen; mPos ++) {
            char c = mSrcStr.charAt(mPos);
            if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
                continue;
            } else
            if (c == ']') {
                // 配列の終了
                break;
            } else
            if (c == '[') {
                // 配列である
                Object obj = prsArr();
                al.add(obj);
                nowKey = "";
                flgKey = !flgKey;
            } else
            if (c == '{') {
                // ハッシュである
                Object obj = prsHsh();
                al.add(obj);
                nowKey = "";
                flgKey = !flgKey;
            } else
            if (c == ',') {
                // カンマである
                continue;
            } else
            if (c == '"' || c == '\'') {
                // 括弧付き文字列である
                String str = prsStrDsh();
                al.add(str);
            } else {
                // 文字列である
                String str = prsStr();
                al.add(str);
            }
        }

        // 戻り値を戻して終了
        return al;
    }

    //------------------------------------------------------------
    //-- prsStr | 文字列のパース
    //------------------------------------------------------------
    /*
     * 文字列のパース。
     * @return 解析後の配列
     */
    public String prsStr() {
        // 変数の初期化
        int strtPos = mPos;

        // 内部の探索
        for (mPos ++; mPos < mLen; mPos ++) {
            char c = mSrcStr.charAt(mPos);
            if (c == ',' || c == ':' || c == '}' || c == ']') {
                mPos --;
                break;
            }
        }

        // 戻り値を戻して終了
        if (mPos >= mLen) return mSrcStr.substring(strtPos); // エラー対策、通常は来ない
        return mSrcStr.substring(strtPos, mPos + 1);
    }

    //------------------------------------------------------------
    //-- prsStrDsh | ダッシュ付き文字列のパース
    //------------------------------------------------------------
    /*
     * ダッシュ付き文字列のパース。
     * @return 解析後の配列
     */
    public String prsStrDsh() {
        // 変数の初期化
        int strtPos = mPos;
        char strtChr = mSrcStr.charAt(mPos);
        boolean wDsh = (strtChr == '"')  ? true : false;
        boolean sDsh = (strtChr == '\'') ? true : false;

        // 内部の探索
        for (mPos ++; mPos < mLen; mPos ++) {
            char c = mSrcStr.charAt(mPos);
            if (wDsh && c == '"'  && mSrcStr.charAt(mPos - 1) != '\') break;
            if (sDsh && c == '\'' && mSrcStr.charAt(mPos - 1) != '\') break;
        }

        // 戻り値を戻して終了
        if (mPos >= mLen) return mSrcStr.substring(strtPos + 1); // エラー対策、通常は来ない
        return mSrcStr.substring(strtPos + 1, mPos);
    }

    //------------------------------------------------------------
    //-- prsHsh | ハッシュのパース
    //------------------------------------------------------------
    /*
     * ハッシュのパース。
     * @return 解析後の配列
     */
    public Object prsHsh() {
        // 変数の初期化
        HashMap<String, Object> hsh = new HashMap<String, Object>();
        String  nowKey = "";
        boolean flgKey = true;

        // 内部の探索
        for (mPos ++; mPos < mLen; mPos ++) {
            char c = mSrcStr.charAt(mPos);
            if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
                continue;
            } else
            if (c == '}') {
                // ハッシュの終了
                break;
            } else
            if (c == '[') {
                // 配列である
                Object obj = prsArr();
                hsh.put(nowKey, obj);
            } else
            if (c == '{') {
                // ハッシュである
                Object obj = prsHsh();
                hsh.put(nowKey, obj);
            } else
            if (c == ':' || c == ',') {
                // ハッシュの区切りか、カンマである
                continue;
            } else
            if (c == '"' || c == '\'') {
                // 括弧付き文字列である
                String str = prsStrDsh();
                if (! flgKey) {
                    hsh.put(nowKey, str);
                    nowKey = "";
                } else {
                    nowKey = str;
                }
                flgKey = !flgKey;
            } else {
                // 文字列である
                String str = prsStr();
                if (! flgKey) {
                    hsh.put(nowKey, str);
                    nowKey = "";
                } else {
                    nowKey = str;
                }
                flgKey = !flgKey;
            }
        }

        // 戻り値を戻して終了
        return hsh;
    }

    //------------------------------------------------------------
    //-- dump | ダンプ出力
    //------------------------------------------------------------
    /*
     * 解析後のオブジェクトを、文字列としてダンプ出力する。
     * @param srcObj    元オブジェクト。
     */
    public static void dump(Object srcObj) {
        dump(srcObj, 0);
    }

    private static void dump(Object srcObj, int nst) {
        // ネスト文字列
        String nstStr = "";
        for (int i = 0; i < nst; i ++) nstStr += NST_TB;

        if (srcObj.getClass().getSimpleName().equals("ArrayList")) {
            // 配列
            System.out.println(nstStr + "<Array>");
            ArrayList<?> al = (ArrayList<?>)srcObj;
            for (int i = 0; i < al.size(); i ++) {
                Object obj = al.get(i);
                if (obj.getClass().getSimpleName().equals("String")) {
                    System.out.println(nstStr + NST_TB + obj.toString());   // 文字列
                } else {
                    dump(obj, nst + 1);     // その他
                }
            }
            System.out.println(nstStr + "</Array>");
        } else
        if (srcObj.getClass().getSimpleName().equals("HashMap")) {
            // ハッシュ
            System.out.println(nstStr + "<Hash>");
            HashMap<?, ?> hsh = (HashMap<?, ?>)srcObj;
            Iterator<?> it = hsh.keySet().iterator();
            while (it.hasNext()) {
                String key = (String)it.next();
                Object obj = hsh.get(key);
                if (obj.getClass().getSimpleName().equals("String")) {
                    System.out.println(nstStr + NST_TB + "[" + key + "] : "
                        + obj.toString());  // 文字列
                } else {
                    System.out.println(nstStr + NST_TB + "[" + key + "] : ");
                    dump(obj, nst + 2);     // その他
                }
            }
            System.out.println(nstStr + "</Hash>");
        }
    }
}

使用例

以下、読み込むJSON文字列です。

[{cmnd:"setVar", key:"mvYMes",val:"-120"}
,{cmnd:"setVar", key:"mvYMesOut",val:"-150"}
,{cmnd:"setVar", key:"mvYNm", val:"120"}
,{cmnd:"setBck", pth:"gm/bck_grd.png", w:"fit", h:"img", bsX:"c", bsY:"c"}

,{cmnd:"rstImg"}
,{cmnd:"setMes", mes:"Stage 6\nBonus Stage 1\nStart!"}
,{cmnd:"wait"}
]

以下、プログラムです。「scrptStr」は、ファイルなどから読み取った、上記の文字列です。

    // UtlJsonの初期化
    UtlJson jsn = new UtlJson();

    // 元のJSONが配列なので、配列として取得
    ArrayList jsnArr = (ArrayList)jsn.prs(scrptStr);

    // ダンプ出力
    UtlJson.dump(jsnArr);

    // 配列の要素を処理
    for (int i = 0; i < jsnArr.size(); i ++) {
        // ハッシュを取り出し
        HashMap jsnHsh = (HashMap)jsnArr.get(i);
    }

以下、ダンプ出力結果です。

<Array>
  <Hash>
    [val] : -120
    [cmnd] : setVar
    [key] : mvYMes
  </Hash>
  <Hash>
    [val] : -150
    [cmnd] : setVar
    [key] : mvYMesOut
  </Hash>
  <Hash>
    [val] : 120
    [cmnd] : setVar
    [key] : mvYNm
  </Hash>
  <Hash>
    [bsY] : c
    [w] : fit
    [pth] : gm/bck_grd.png
    [cmnd] : setBck
    [h] : img
    [bsX] : c
  </Hash>
  <Hash>
    [cmnd] : rstImg
  </Hash>
  <Hash>
    [mes] : Stage 6\nBonus Stage 1\nStart!
    [cmnd] : setMes
  </Hash>
  <Hash>
    [cmnd] : wait
  </Hash>
</Array>
Cronus Crown(クロノス・クラウン)のトップページに戻る
(c)2002-2024 Cronus Crown (c)1997-2024 Masakazu Yanai
ご意見・お問い合わせはサイト情報 弊社への連絡までお願いします
個人情報の取り扱い、利用者情報の外部送信について