【问题标题】:Parse JSON object recursively - Java递归解析 JSON 对象 - Java
【发布时间】:2016-10-17 07:35:48
【问题描述】:

我有一个带有对象列表的 JSON,并且列表中的任何项目都可以具有 null 或与键的值相同的对象。我正在寻找一种更快的方法来解析 json 以得出我的最终结果。 数据结构看起来像 -

[
    {
        "firstName": "Bruce",
        "familyMembers": null
    },
    {
        "firstName": "Gates Family",
        "familyMembers": [
            {
                "firstName": "Bill",
                "familyMembers": null
            },
            {
                "firstName": "Steve",
                "familyMembers": null
            }
        ]
    },
    {
        "firstName": "Lee",
        "familyMembers": null
    },
    {
        "firstName": "Chan",
        "familyMembers": null
    }
]

输出应该是一个集合 = ("Bruce", "Bill", "Steve", "Lee", "Chan")。

我正在寻找一种在 Java 中执行此操作的最佳方法,这样我就不会因为陷入这个解析地狱而增加我的响应时间。 感谢您在这方面的时间。

【问题讨论】:

  • 使用jackson的流解析器。
  • 附注。您在那里的文件不符合 JSON 标准,因为内容应以 { } 子句开头。例如。 { 成员:[ {1:2}, {3:4} ] }
  • 另外,字符串“GatesFamily”是否应该包含在集合中?因为这反映为“firstName”属性。

标签: java json performance parsing recursion


【解决方案1】:

正如我在评论中提到的那样。

您的第一个问题是 JSON 文件中的内容。根据标准,它应该用一组 { } 包裹起来。

例子

{ 
    "members": [
        {
            "firstName": "Bruce",
            "familyMembers": null
        },
        {
            "firstName": "Gates Family",
            "familyMembers": [
                {
                    "firstName": "Bill",
                    "familyMembers": null
                },
                {
                    "firstName": "Steve",
                    "familyMembers": null
                }
            ]
        },
        {
            "firstName": "Lee",
            "familyMembers": null
        },
        {
            "firstName": "Chan",
            "familyMembers": null
        }
    ]
}

另外,我认为“盖茨家族”的价值应该是输出的一部分?因为它在“FirstName”属性下。

无论如何,这是我基于org.json 库的解决方案。它还使用了 Goggle 的 GSon 库,我用它来读取 JSON 文件。

import org.json.*;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import com.google.common.base.Charsets;
import com.google.common.io.Files;

public class solution {

    public static final String JSON_DATA_FILE_PATH = "./data/source_37848106.json";

    private static boolean hasMoreFamilyName(JSONObject json) {
        return json.has("familyMembers") && json.get("familyMembers") != JSONObject.NULL;
    }

    private static void trackFirstName(Map<String, Integer> nameTracker, JSONObject json) {
        if (!nameTracker.containsKey(json.getString("firstName"))) {
            nameTracker.put(json.getString("firstName"), /*DUMMY VALUE =*/1);
        }
    }

    private static void getNames(Map<String,Integer> nameTracker, JSONArray jsonArr) {
        for (int i = 0; i< jsonArr.length(); i++) {
            JSONObject item = jsonArr.getJSONObject(i);
            if (hasMoreFamilyName(item)) {
                getNames(nameTracker, item.getJSONArray("familyMembers"));
            }
            trackFirstName(nameTracker, item);
        }
    }

    public static void main(String[] args) {
        Map<String, Integer> nameTracker = new HashMap<>();

        try {
            String text = Files.toString(new File(JSON_DATA_FILE_PATH), Charsets.UTF_8);
            JSONObject json = new JSONObject(text);
            getNames(nameTracker, json.getJSONArray("members"));
        }
        catch (Exception ex) {
            System.out.println("Something is wrong.");
        }

        for (Map.Entry<String,Integer> entry : nameTracker.entrySet()) {
        System.out.println(entry.getKey());
    }
}

【讨论】:

    【解决方案2】:

    试试我的递归实现。

    public static void jsonArrayToSet(JSONArray jAry, Set<String> result, String targetKey, String subArrayKey, boolean includeNode){
        try {
            for (int i = 0; i < jAry.length(); i++) {
                JSONObject jObj = jAry.getJSONObject(i);
                boolean hasSubArray = false;
                JSONArray subArray = null;
                if(jObj.has(subArrayKey)){
                    Object possibleSubArray = jObj.get(subArrayKey);
                    if(possibleSubArray instanceof JSONArray){
                        hasSubArray = true;
                        subArray = (JSONArray) possibleSubArray;
                    }
                }
                if(hasSubArray){
                    if(includeNode){
                        result.add(jObj.getString(targetKey));
                    }
                    jsonArrayToSet(subArray, result, targetKey, subArrayKey, includeNode);
                } else {
                    result.add(jObj.getString(targetKey));
                }
            }
        } catch (JSONException e){
            e.printStackTrace();
        }
    }
    

    jAry:来源JSONArray

    result:你想写的Set

    targetKey:映射到要添加到result 的条目的键。

    subArrayKey:映射到子JSONArray的键。

    includeNode:当当前JSONOnject是包含子数组的节点时,是否添加到result

    根据您的情况,您可以致电:

    jsonArrayToSet(yourJsonArray, yourSet, "firstName", "familyMembers", false);
    

    【讨论】:

      【解决方案3】:

      可以使用jackson-databind-2.6.5.jar中定义的ObjectMapper

      定义一个带有类似于 json 模式的字段的 java 类,然后像这样绑定它们:

      import com.fasterxml.jackson.databind.DeserializationFeature;
      import com.fasterxml.jackson.databind.ObjectMapper;   
      
       ObjectMapper objectMapper = new ObjectMapper();
       objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
       objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
       Family family=objectMapper.readValue(jsonString, Family.class);
      

      现在您将拥有一个类似于您的 json 字符串模式的 java 对象,您可以按照自己喜欢的方式打印它。

      【讨论】:

        猜你喜欢
        • 2020-02-27
        • 1970-01-01
        • 1970-01-01
        • 2011-05-05
        • 2012-07-21
        • 2018-09-30
        • 2012-01-17
        • 2014-10-17
        • 2016-10-27
        相关资源
        最近更新 更多