Java中如何判断一个通用JSON是否为另一个通用JSON的子集?
Java中判断一个JSON是否包含于另一个JSON的可靠方案
问题分析
你需要判断子JSON的所有键值对完全匹配父JSON中的对应键值(忽略父JSON的其他属性),但从Excel读取JSON时现有方案时灵时不灵,核心原因大概率是Excel读取的JSON字符串存在格式瑕疵(比如隐形空格、中文引号、转义不规范),或者原方案的递归逻辑未覆盖边界场景。
解决思路
- 先标准化Excel读取的JSON字符串:确保解析前格式合法,避免因格式问题导致解析失败或匹配错误。
- 基于成熟JSON库实现递归匹配:用Jackson/Gson这类工业级库处理JSON解析与遍历,比手写递归更稳定。
具体实现(以Jackson为例)
步骤1:依赖引入(Maven)
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> <!-- 使用最新稳定版 --> </dependency>
步骤2:JSON字符串预处理工具
处理Excel读取的字符串,修复常见格式问题:
import java.util.regex.Matcher; import java.util.regex.Pattern; public class JsonPreprocessor { public static String normalizeJson(String rawJson) { if (rawJson == null) return null; // 替换中文引号为英文引号 rawJson = rawJson.replaceAll("“|”", "\""); // 去除键值对前后的多余空格(比如" name ": " Michael " → "name": "Michael") rawJson = rawJson.replaceAll("\\s*([{}\\[\\],:])\\s*", "$1"); // 去除字符串值前后的多余空格(保留内部空格,比如" Michael Jordan " → "Michael Jordan") Pattern pattern = Pattern.compile("\"(.*?)\""); Matcher matcher = pattern.matcher(rawJson); StringBuilder sb = new StringBuilder(); while (matcher.find()) { matcher.appendReplacement(sb, "\"" + matcher.group(1).trim() + "\""); } matcher.appendTail(sb); return sb.toString(); } }
步骤3:递归判断JSON包含关系
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; public class JsonContainsChecker { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); // 判断子JSON是否包含于父JSON public static boolean isJsonContained(String childJsonStr, String parentJsonStr) throws IOException { // 先标准化JSON字符串 String normalizedChild = JsonPreprocessor.normalizeJson(childJsonStr); String normalizedParent = JsonPreprocessor.normalizeJson(parentJsonStr); JsonNode childNode = OBJECT_MAPPER.readTree(normalizedChild); JsonNode parentNode = OBJECT_MAPPER.readTree(normalizedParent); return isNodeContained(childNode, parentNode); } // 递归检查单个JsonNode的包含关系 private static boolean isNodeContained(JsonNode childNode, JsonNode parentNode) { // 如果子节点是对象类型 if (childNode.isObject() && parentNode.isObject()) { // 遍历子对象的所有键 for (String key : childNode.fieldNames()) { if (!parentNode.has(key)) { // 父JSON没有该键,直接返回false return false; } JsonNode childValue = childNode.get(key); JsonNode parentValue = parentNode.get(key); // 递归检查子值是否匹配 if (!isNodeContained(childValue, parentValue)) { return false; } } return true; } // 如果子节点是数组类型:默认要求子数组的每个元素按顺序匹配父数组对应位置(可按需调整为子集匹配) else if (childNode.isArray() && parentNode.isArray()) { if (childNode.size() > parentNode.size()) { return false; } for (int i = 0; i < childNode.size(); i++) { if (!isNodeContained(childNode.get(i), parentNode.get(i))) { return false; } } return true; } // 其他类型(字符串、数字、布尔、null)直接比较值 else { return childNode.equals(parentNode); } } // 测试示例 public static void main(String[] args) throws IOException { String parentJson = "{\"id\": \"1\",\"name\": \"Michael Jordan\",\"age\": \"50\"}"; String childJson = "{\"name\": \"Michael Jordan\"}"; // 模拟Excel读取的带格式问题的JSON String messyChildJson = "{ “name” : \" Michael Jordan \" }"; System.out.println(isJsonContained(childJson, parentJson)); // 输出true System.out.println(isJsonContained(messyChildJson, parentJson)); // 输出true(预处理后修复了格式) } }
关键说明
- 预处理的重要性:Excel单元格中的JSON常存在格式问题(比如用户输入时的空格、中文引号),预处理步骤能大幅降低解析失败概率,这是解决"时灵时不灵"的核心。
- 递归逻辑覆盖场景:不仅支持简单键值对,还支持嵌套JSON和数组的匹配(数组匹配逻辑可根据需求调整,比如改为父数组包含子数组的所有元素,而不要求顺序)。
- 成熟库的优势:Jackson的
JsonNode提供了完善的类型判断和值比较方法,比手写递归更稳定,能避免空指针、类型转换等隐藏问题。
内容的提问来源于stack exchange,提问作者Chiranjit Singh
相关产品推荐
相关产品推荐

