Java按给定顺序读取JSON对象 按序提取键值父键列表
问题原因
顺序错乱的核心原因是你使用的org.json库默认JSONObject内部采用无序哈希表存储键值对,解析时不会保留JSON字符串中键的原始定义顺序,调用keys()遍历得到的是哈希排序后的结果,自然和原始JSON的书写顺序不匹配。另外你原有数组处理逻辑中提前将值转为字符串,会导致布尔、数字类型的值失真,也和预期输出不符。
修复方案
方案1:最小改动(继续使用org.json库)
org.json 从20180813版本开始,JSONObject提供了有序模式构造参数,传入true时会内部使用LinkedHashMap存储键值对,自动保留解析时的原始字段顺序,仅需少量修改原有代码即可:
import org.json.JSONArray; import org.json.JSONObject; import java.util.ArrayList; // 测试JSON字符串a和你原有定义完全一致,此处省略重复定义 public static ArrayList<Object> extractKeysValues(String test, String parentKey) throws Exception { ArrayList<Object> arraylist = new ArrayList<Object>(); if(test.charAt(0)=='{') { // 传入第二个参数true,启用有序存储,保留原始键顺序 JSONObject json_object = new JSONObject(test, true); for (String key : json_object.keySet()) { Object value = json_object.get(key); arraylist.add(key); arraylist.add(value); arraylist.add(parentKey); if(value instanceof JSONObject || value instanceof JSONArray) { arraylist.addAll(extractKeysValues(value.toString(), key)); } } } else if(test.charAt(0)=='[') { // JSONArray本身按索引有序,无需额外配置 JSONArray json_array = new JSONArray(test); int json_array_length = json_array.length(); for(int i=0;i<json_array_length;i++) { Object value = json_array.get(i); String idxKey = String.valueOf(i); arraylist.add(idxKey); arraylist.add(value); arraylist.add(parentKey); if(value instanceof JSONObject || value instanceof JSONArray) { arraylist.addAll(extractKeysValues(value.toString(), idxKey)); } } } return arraylist; }
如果你的org.json版本低于20180813,要么升级依赖版本,要么使用下面的方案2。
方案2:换用Jackson实现(兼容性更好)
如果不方便升级org.json版本,可以换用Jackson库做JSON解析,Jackson默认解析对象时就会用有序结构存储字段,自动保留原始定义顺序,不需要额外配置:
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.ArrayList; import java.util.Iterator; import java.util.Map; public static ArrayList<Object> extractKeysValues(String jsonStr, String parentKey) throws Exception { ArrayList<Object> list = new ArrayList<>(); ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(jsonStr); traverseNode(root, parentKey, list); return list; } private static void traverseNode(JsonNode node, String parentKey, ArrayList<Object> list) { if (node.isObject()) { Iterator<Map.Entry<String, JsonNode>> fields = node.fields(); while (fields.hasNext()) { Map.Entry<String, JsonNode> entry = fields.next(); String key = entry.getKey(); JsonNode value = entry.getValue(); list.add(key); list.add(value); list.add(parentKey); if (value.isObject() || value.isArray()) { traverseNode(value, key, list); } } } else if (node.isArray()) { for (int i = 0; i < node.size(); i++) { JsonNode value = node.get(i); String idxKey = String.valueOf(i); list.add(idxKey); list.add(value); list.add(parentKey); if (value.isObject() || value.isArray()) { traverseNode(value, idxKey, list); } } } }
两种方案执行后,遍历输出的字段顺序、值类型都会和你给出的预期结果完全匹配。
内容的提问来源于stack exchange,提问作者Praveen Samuel J
相关产品推荐
相关产品推荐

