首页 > 其他分享 >多层JSON字符串对象的差异化比较

多层JSON字符串对象的差异化比较

时间:2024-03-28 22:23:28浏览次数:20  
标签:JsonNode String differences 差异化 多层 JSON fieldName node1 append

import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.*;

@Slf4j
public class JsonComparatorUtils {
    private static final ObjectMapper mapper = new ObjectMapper();

    public static void main(String[] args) throws IOException {


        String jsonBefore = "{"internal": false, "data": {"f8e37381-b7d6-4475-95d3-e763b64306e8": "33", "mw_instanceName": "kkkkkk", "flag": true}, "instanceName": "kkkkkk", "modelId": "104730838641410048", "groupId": "102706472617508864", "templateSearchParam": {"isExportTemp": false}, "type": "instance", "path": ["77170433597636608", "102706472617508864", "104730838641410048"], "itemName": "kkkkkk", "orgIds": [1]}";
        String jsonAfter = "{"internal": true, "data": {"f8e37381-b7d6-4475-95d3-e763b64306e8": "33", "mw_instanceName": "llllll", "flag": false}, "instanceName": "kkkkkk", "modelId": "104730838641410048", "groupId": "102706472617508864", "templateSearchParam": {"isExportTemp": false}, "type": "instance", "path": ["77170433597636608", "102706472617508864", "104730838641410048"], "itemName": "kkkkkk", "orgIds": [1]}";
        List<String> fieldsToMonitor = Arrays.asList("internal", "instanceName", "mw_instanceName");

        JsonNode jsonBeforeNode = mapper.readTree(jsonBefore);
        JsonNode jsonAfterNode = mapper.readTree(jsonAfter);

        DiffResult diffResult = generateHtmlWithHighlights(jsonBeforeNode, jsonAfterNode);

        System.out.println("HTML for json1Before: " + diffResult.getBefore());
        System.out.println("HTML for jsonAfter: " + diffResult.getAfter());
    }

    private static DiffResult generateHtmlWithHighlights(JsonNode jsonBeforeNode, JsonNode jsonAfterNode, List<String> fieldsToMonitor) {
        String jsonBefore = highlightDifference(jsonBeforeNode, jsonAfterNode, fieldsToMonitor);
        String jsonAfter = highlightDifference(jsonAfterNode, jsonBeforeNode, fieldsToMonitor);
        return new DiffResult(jsonBefore, jsonAfter);
    }

    private static String highlightDifference(JsonNode node1, JsonNode node2, List<String> fieldsToMonitor) {
        StringBuilder html = new StringBuilder();
        if (node1.isObject() && node2.isObject()) {
            ObjectNode objectNode1 = (ObjectNode) node1;
            ObjectNode objectNode2 = (ObjectNode) node2;
            for (String field : fieldsToMonitor) {
                JsonNode fieldNode1 = findField(objectNode1, field);
                JsonNode fieldNode2 = findField(objectNode2, field);
                if (fieldNode1 != null && fieldNode2 != null) {
                    if (!fieldNode1.equals(fieldNode2)) {
                        html.append("<span style='background-color: yellow;'>").append(field).append(": ").append(fieldNode1.asText()).append("</span><br>");
                    }
                } else if (fieldNode1 != null) {
                    html.append("<span style='background-color: yellow;'>").append(field).append(": ").append(fieldNode1.asText()).append("</span><br>");
                } else if (fieldNode2 != null) {
                    html.append("<span style='background-color: yellow;'>").append(field).append(": ").append(fieldNode2.asText()).append("</span><br>");
                }
            }
        }
        return html.toString();
    }

    private static JsonNode findField(ObjectNode node, String fieldName) {
        if (node.has(fieldName)) {
            return node.get(fieldName);
        }
        for (Iterator<String> it = node.fieldNames(); it.hasNext(); ) {
            String key = it.next();
            JsonNode childNode = node.get(key);
            if (childNode.isObject()) {
                JsonNode result = findField((ObjectNode) childNode, fieldName);
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }


    public static DiffResult generateHtmlWithHighlights(JsonNode node1, JsonNode node2) {
        try {
            // 获取差异并进行高亮处理
            Map<String, String> differences = getDifferences(node1, node2);
            ObjectMapper newMapper = new ObjectMapper();
            ObjectNode highlightedNode = newMapper.createObjectNode();
            highlightDifference(node1, differences, highlightedNode, "");
            // 将差异节点转换为字符串
            String beforeStr = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(highlightedNode);

            highlightedNode = newMapper.createObjectNode();
            highlightDifference(node2, differences, highlightedNode, "");
            // 将差异节点转换为字符串
            String afterStr = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(highlightedNode);
            // 创建 DiffResult 对象并返回
            return new DiffResult(beforeStr, afterStr);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取两个 JSON 对象的差异
     * @param node1 before 节点
     * @param node2 after 节点
     * @return
     */
    private static Map<String, String> getDifferences(JsonNode node1, JsonNode node2) {
        Map<String, String> differences = new LinkedHashMap<>();
        compareJsonNodes(node1, node2, differences);
        return differences;
    }

    /**
     * 递归比较两个 JSON 节点的差异
     * @param node1 before 节点
     * @param node2 after 节点
     * @param differences  差异字段
     */
    private static void compareJsonNodes(JsonNode node1, JsonNode node2, Map<String, String> differences) {
        Iterator<String> fieldNames = node1.fieldNames();
        while (fieldNames.hasNext()) {
            String fieldName = fieldNames.next();
            JsonNode fieldValue1 = node1.get(fieldName);
            JsonNode fieldValue2 = node2.get(fieldName);

            // 如果是对象类型,则继续比较
            if (fieldValue1.isObject() && fieldValue2.isObject()) {
                compareJsonNodes(fieldValue1, fieldValue2, differences);
                // 跳过本次后续操作
                continue;
            }

            if (!Objects.equals(fieldValue1, fieldValue2)) {
                differences.put(fieldName, fieldValue1.toString());
            }

        }
    }

    private static void highlightDifference(JsonNode node, Map<String, String> differences,
                                            ObjectNode highlightedNode, String key) {
        try {
            Iterator<Map.Entry<String, JsonNode>> fields = node.fields();
            ObjectNode objectNode = null;
            while (fields.hasNext()) {
                Map.Entry<String, JsonNode> field = fields.next();
                String fieldName = field.getKey();
                JsonNode fieldValue = field.getValue();

                if (fieldValue.isObject()) {
                    // 如果是对象,递归查看内部属性;TODO 其实可以将内部value转map,查看是否存在differences中的字段。是则递归
                    log.info("key: {}, fieldName: {}", key, fieldName);
                    highlightDifference(fieldValue, differences, highlightedNode, fieldName);
                }
                if (StrUtil.isNotEmpty(key)) {
                    if (ObjUtil.isEmpty(objectNode)) {
                        // 初始化 objectNode
                        objectNode = new ObjectMapper().createObjectNode();
                    }
                    // 差异化包含 fieldName 设置html元素
                    if (differences.containsKey(fieldName)) {
                        objectNode.put(fieldName,
                                "<span style='background-color: yellow;'>" + differences.get(fieldName) + "</font>");
                    } else {
                        // 差异化不包含正常添加数据
                        objectNode.set(fieldName, fieldValue);
                    }
                } else {
                    if (differences.containsKey(fieldName)) {
                        highlightedNode.put(fieldName,
                                "<span style='background-color: yellow;'>" + differences.get(fieldName) + "</font>");
                    } else {
                        // 避免原生对象数据后期替换掉之前设置的 objectNode
                        if (highlightedNode.get(fieldName) == null) {
                            highlightedNode.set(fieldName, fieldValue);
                        }
                    }
                }
            }
            if (ObjUtil.isNotEmpty(objectNode) && StrUtil.isNotEmpty(key)) {
                highlightedNode.set(key, objectNode);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Data
    public static class DiffResult {
        private String before;
        private String after;

        public DiffResult(String before, String after) {
            this.before = before;
            this.after = after;
        }

    }
}

 

标签:JsonNode,String,differences,差异化,多层,JSON,fieldName,node1,append
From: https://www.cnblogs.com/xxsdnol/p/18102758

相关文章

  • 探索多种数据格式:JSON、YAML、XML、CSV等数据格式详解与比较
    1.数据格式介绍数据格式是用于组织和存储数据的规范化结构,不同的数据格式适用于不同的场景。常见的数据格式包括JSON、YAML、XML、CSV等。数据可视化|一个覆盖广泛主题工具的高效在线平台(amd794.com)https://amd794.com/jsonformat2.JSON(JavaScriptObjectNotation)......
  • Fastjson反序列化分析
    依赖先研究1.2.24版本的,版本高了就有waf了,不过也能绕,高版本以后再说<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.24</version></dependency><dependency><groupId&g......
  • python-json数据、pyecharts的入门使用(折线图)
    目录1. json数据格式 1.1 json.dumps()1.2 json.loads()2. pyecharts的入门使用(折线图)2.1  pyecharts使用的简单示例2.1.1 导包2.1.2 创建对象2.1.3 添加x轴数据2.1.4 添加y轴数据2.1.5 设置全局配置项2.1.6 render()方法,生成图像3. ......
  • JackJson对象转化
    当接受jsonKey首字母为大写的时候需要用JSONProperty配合JsonIngore处理packagecom.example.demoboot.dto;importcom.example.demoboot.entity.Person;importjava.util.List;/***封装response返回的data对象对象太多可以用宽对象,把所有需要的都写一起**......
  • 最详细爬虫零基础教程10——json格式提取之jsonpath
    文章目录一、json数据解析二、案例演示1.解析获得数据2.简化代码3.豆瓣json数据解析总结一、json数据解析用来解析多层嵌套的json数据;JsonPath是一种信息抽取类库,是从JSON文档中抽取指定信息的工具,提供多种语言实现版本,包括:Javascript,Python,PHP和Java。语......
  • C#JsonConvert.DeserializeObject反序列化与JsonConvert.SerializeObject序列化
    原文链接:https://blog.csdn.net/qq_45451847/article/details/120434797JSONJSON序列化是将对象转换为JSON格式的字符串,而JSON反序列化是将JSON格式的字符串转换为对象。对于JSON大家都了解,JSON是一种轻量级的文本数据交换格式而非编程语言,既然是数据交换格式,那就需要不断的进......
  • 【御控】JavaScript JSON结构转换(1):对象To对象——键值互换
    文章目录一、JSON是什么?二、JSON结构转换是什么?三、核心构件之转换映射四、案例之《JSON对象ToJSON对象》五、代码实现六、在线转换工具七、技术资料一、JSON是什么?Json(JavaScriptObjectNotation)产生于20世纪90年代初,最初由道格拉斯·克罗克福特(DouglasCrockfo......
  • .netcore获得swagger对象信息(解析swagger的json文件)
    以下代码未经测试,谨慎使用!!! varreader=newMicrosoft.OpenApi.Readers.OpenApiStringReader();vardoc=reader.Read(System.IO.File.ReadAllText(_webHostEnvironment.WebRootPath+"/a.json"),outvardiagnostic);vardoc1=_swaggerGenerator.GetSwagger(versio......
  • Ajax 发送json格式数据以及发送文件(FormData)和自带的序列化组件: serializers
    前后端传输数据的编码格式(contentType)get请求数据就是直接放在url?后面的url?usernmae=junjie&password=123...可以向后端发送post请求的方式form请求ajax请求前后端传输数据的编码格式urlencodedformdatajson研究form表单:默认的数据编码格式是(urlencod......
  • python + playwright 非无痕模式打开网页下载json数据
    使用python从网页下载资料,生成一些图表使用,因为json数据需要SSO验证,不然没有Token是无权限获取的,所以使用playwright无痕模式打开不行,要使用非无痕模式。从网页报表上把json数据转成Excel保存代码没有多华丽,只是满足了那时候需要這一操作的需求。点击查看代码fromplaywrig......