JSONパーサー「UtlJson」
2010/12/27 ページ作成
2011/09/05 最終更新
クロノス・クラウン合同会社
柳井政和
HP:http://crocro.com/
Twitter:http://twitter.com/ruten
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>