首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java 遞迴解析任意層級 JSON 字串通用工具類

     編輯:Java 程式設計入門

前言

處理動態 JSON 結構是後端開發常見需求:第三方 API 回傳欄位不固定、配置檔結構多變、或需將 JSON 統一轉為 Map/List 供通用邏輯處理。傳統做法需針對每種結構寫死對應的 POJO,維護成本高。本文介紹一套基於 org.json 與正則表達式的遞迴解析器,能自動處理任意層級的 JSONObject 與 JSONArray,輸出巢狀的 Map<String, Object>、List<Object> 或基本型別。

核心設計思路

策略模式擴充解析類型

定義 RegexPolicy 列舉,預留擴充點(如 HTML 圖片擷取、Email 提取):

public enum RegexPolicy {
    Json("Json"),
    Image("ImageFromHtml");

    private final String value;
    RegexPolicy(String value) { this.value = value; }
    @Override public String toString() { return value; }
}

遞迴下降解析演算法

regexJson() 為核心遞迴函式,流程如下:

  1. 型別判斷:嘗試建構 JSONObject 或 JSONArray,失敗則視為純量值直接回傳。
  2. 物件解析:使用正則 "([^\" ]+?):" 擷取所有鍵名,配合 JSONObject.opt() 取值,對值遞迴呼叫 regexJson()。
  3. 陣列解析:逐項遍歷 JSONArray,每個元素遞迴解析後加入 List<Object>。
  4. 正則游標修正:遇到巢狀陣列時,根據字串長度調整 Matcher.region() 避免重複匹配。

關鍵程式碼解析

進入點:統一解析介面

public static Object regex(final RegexPolicy policy, final String data) {
    switch (policy) {
        case Json: return regexJson(data);
        case Image: break; // 預留擴充
        default: break;
    }
    return null;
}

遞迴核心:regexJson()

private static Object regexJson(final String jsonStr) {
    if (jsonStr == null) throw new NullPointerException("JsonString shouldn't be null");
    try {
        if (isJsonObject(jsonStr)) {
            // 解析 JSONObject -> Map
            final Pattern pattern = Pattern.compile(REGULAR_JSON_ITEM_NAME);
            final Matcher matcher = pattern.matcher(jsonStr);
            final Map map = new HashMap<>();
            final JSONObject jsonObject = new JSONObject(jsonStr);

            for (; matcher.find(); ) {
                String key = matcher.group(1);
                Object value = jsonObject.opt(key);
                // 跳過巢狀陣列字串長度,避免正則重複匹配內部鍵名
                if (value != null && isJsonArray(value.toString())) {
                    matcher.region(matcher.end() + value.toString().replace("\\", "").length(), matcher.regionEnd());
                }
                if (value != null && !map.containsKey(key)) {
                    map.put(key, regexJson(value.toString()));
                }
            }
            return map;
        } else if (isJsonArray(jsonStr)) {
            // 解析 JSONArray -> List
            List list = new ArrayList<>();
            JSONArray jsonArray = new JSONArray(jsonStr);
            for (int i = 0; i < jsonArray.length(); i++) {
                Object element = jsonArray.opt(i);
                list.add(regexJson(element.toString()));
            }
            return list;
        }
    } catch (Exception e) {
        Log.e("RegexUtil--regexJson", e.getMessage());
    }
    // 純量值(String/Number/Boolean)直接回傳
    return jsonStr;
}

型別檢查輔助方法

private static boolean isJsonObject(final String jsonStr) {
    if (jsonStr == null) return false;
    try { new JSONObject(jsonStr); return true; }
    catch (JSONException e) { return false; }
}

private static boolean isJsonArray(final String jsonStr) {
    if (jsonStr == null) return false;
    try { new JSONArray(jsonStr); return true; }
    catch (JSONException e) { return false; }
}

使用範例

// 假設 jsonStr 為完整 JSON 字串,可能包含前後雜訊
String pureJson = jsonStr.substring(jsonStr.indexOf("{"), jsonStr.lastIndexOf("}") + 1);
Object result = RegexUtil.regex(RegexPolicy.Json, pureJson);

if (result instanceof String) {
    Log.e("scalar", result.toString());
} else if (result instanceof Map) {
    @SuppressWarnings("unchecked")
    Map map = (Map) result;
    for (Map.Entry entry : map.entrySet()) {
        Log.e(entry.getKey(), entry.getValue().toString());
    }
} else if (result instanceof List) {
    Log.e("list", result.toString());
}

適用場景與限制

優點注意事項
無需定義 POJO,動態結構自適應 大量資料時效能遜於 Jackson/Gson 流式解析
統一輸出 Map/List,便於通用邏輯處理 正則匹配鍵名假設無空格、無特殊字元,極端情況可能遺漏
依賴輕量 org.json,無額外重依賴 日期、二進位等特殊型別會序列化為字串,需自行後處理

進階改進方向

  • 引入 Jackson JsonNode 替代 org.json,支援更完整的 JSON 語法(如尾隨逗號、註解)。
  • 增加 TypeReference 機制,解析時自動轉換目標型別(LocalDate、BigDecimal 等)。
  • 支援 JSONPath 查詢,直接提取深層路徑而非全量解析。
  • 加入快取機制:相同結構的 JSON 重複解析時復用鍵名索引。

總結

這套遞迴解析器以「約定優於配置」的方式,將任意層級 JSON 統一映射為 Java 集合結構,極大降低動態資料處理的樣板程式碼。雖非高效能場景首選,但在配置解析、API 閘道轉發、測試資料生成等場景極具實用價值。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved