提问人: 提问时间:9/14/2023 更新时间:9/14/2023 访问量:21
如何在 groovy/java 脚本中比较两个 json 并获得原始输入 json 格式的差异
How to compare two json and get difference as original input json format in groovy/java script
问:
我必须比较两个 json 对象,并且需要以与输入 json 相同的格式获取它们的差异。 例如,我输入了 json 1,如下所示:
{
"entities": [
{
"L1_Entity_Id": 7004,
"L1_Entity_Nm": "AcademicAdministration",
"visibility": false,
"L2_Entities": [
{
"L2_Entity_Id": 8003,
"L2_Entity_Nm": "DesktopSoftware",
"visibility": true,
"primary_triage": "EAAS",
"markham_triage": "MK_Team1",
"Faculty_Support": "Faculty1,Faculty2,Faculty4",
"hasReference": true
}
],
"hasReference": true
},
{
"L1_Entity_Id": 7005,
"L1_Entity_Nm": "Websites",
"visibility": false,
"L2_Entities": [
{
"L2_Entity_Id": 8013,
"L2_Entity_Nm": "CampusMaps",
"visibility": false,
"Faculty_Support": "Faculty3,Faculty2",
"hasReference": false
},
{
"L2_Entity_Id": 8014,
"L2_Entity_Nm": "WebGeneral",
"visibility": false,
"Faculty_Support": "Faculty4",
"hasReference": false
}
],
"hasReference": false
}
]
}
我的输入json 2如下:
{
"entities": [
{
"L1_Entity_Id": 7004,
"L1_Entity_Nm": "AcademicAdministration",
"visibility": false,
"L2_Entities": [
{
"L2_Entity_Id": 8003,
"L2_Entity_Nm": "DesktopSoftware",
"visibility": true,
"primary_triage": "EAAS",
"markham_triage": "MK_Team1",
"Faculty_Support": "Faculty1,Faculty2,Faculty4",
"hasReference": true
}
],
"hasReference": true
},
{
"L1_Entity_Id": 7005,
"L1_Entity_Nm": "Websites",
"visibility": false,
"L2_Entities": [
{
"L2_Entity_Id": 8013,
"L2_Entity_Nm": "CampusMaps2",
"visibility": false,
"Faculty_Support": "Faculty3,Faculty2",
"hasReference": false
},
{
"L2_Entity_Id": 8014,
"L2_Entity_Nm": "WebGeneral",
"visibility": false,
"Faculty_Support": "Faculty4",
"hasReference": false
}
],
"hasReference": false
}
]
}
我刚刚将L2_Entity_Nm从 CampusMaps 更改为 CampusMaps2。
现在脚本的预期输出如下: 即保持与输入json相同的格式,并在子数组中添加操作字段为“operation”: “UPDATED”L2_Entities。
{
"entities": [
{
"L1_Entity_Id": 7005,
"L1_Entity_Nm": "Websites",
"visibility": false,
"L2_Entities": [
{
"L2_Entity_Id": 8013,
"L2_Entity_Nm": "CampusMaps2",
"visibility": false,
"Faculty_Support": "Faculty3,Faculty2",
"hasReference": false
"operation": "UPDATED"
}
],
"hasReference": false
}
]
}
我从这里参考了 - https://smyachenkov.com/posts/json-difference-in-java/ 并创建了以下脚本:
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.*;
System.out.println("@@ Initialization START----------------------------------> ");
var from = toJson(
"{\"entities\":[{\"L1_Entity_Id\":7004,\"L1_Entity_Nm\":\"AcademicAdministration\",\"visibility\":false,\"L2_Entities\":[{\"L2_Entity_Id\":8003,\"L2_Entity_Nm\":\"DesktopSoftware\",\"visibility\":true,\"primary_triage\":\"EAAS\",\"markham_triage\":\"MK_Team1\",\"Faculty_Support\":\"Faculty1,Faculty2,Faculty4\",\"hasReference\":true}],\"hasReference\":true},{\"L1_Entity_Id\":7005,\"L1_Entity_Nm\":\"Websites\",\"visibility\":false,\"L2_Entities\":[{\"L2_Entity_Id\":8013,\"L2_Entity_Nm\":\"CampusMaps\",\"visibility\":false,\"Faculty_Support\":\"Faculty3,Faculty2\",\"hasReference\":false},{\"L2_Entity_Id\":8014,\"L2_Entity_Nm\":\"WebGeneral\",\"visibility\":false,\"Faculty_Support\":\"Faculty4\",\"hasReference\":false}],\"hasReference\":false}]}" );
var to = toJson(
"{\"entities\":[{\"L1_Entity_Id\":7004,\"L1_Entity_Nm\":\"AcademicAdministration2\",\"visibility\":false,\"L2_Entities\":[{\"L2_Entity_Id\":8003,\"L2_Entity_Nm\":\"DesktopSoftware\",\"visibility\":true,\"primary_triage\":\"EAAS\",\"markham_triage\":\"MK_Team1\",\"Faculty_Support\":\"Faculty1,Faculty2,Faculty4\",\"hasReference\":true}],\"hasReference\":true},{\"L1_Entity_Id\":7005,\"L1_Entity_Nm\":\"Websites\",\"visibility\":false,\"L2_Entities\":[{\"L2_Entity_Id\":8013,\"L2_Entity_Nm\":\"CampusMaps\",\"visibility\":false,\"Faculty_Support\":\"Faculty3,Faculty2\",\"hasReference\":false},{\"L2_Entity_Id\":8014,\"L2_Entity_Nm\":\"WebGeneral\",\"visibility\":false,\"Faculty_Support\":\"Faculty4\",\"hasReference\":false}],\"hasReference\":false}]}" );
var result = new JsonDiff().diff(from, to);
System.out.println("@@@ result = "+result);
private LinkedHashMap<String, Object> toJson(String json) {
try {
return new ObjectMapper().readValue(json, LinkedHashMap.class);
} catch (Exception e) {
return null;
}
}
/***************************************************************************
Supporting Classes
****************************************************************************/
public enum Operation {
ADDED, REMOVED, UPDATED
}
public class Difference {
private Object value;
private String path;
private Operation operation;
public Difference(Object value, String path, Operation operation) {
this.value = value;
this.path = path;
this.operation = operation;
}
public Object getValue() {
return value;
}
public String getPath() {
return path;
}
public Operation getOperation() {
return operation;
}
@Override
public String toString() {
return "Difference{" +
"value=" + value +
", path='" + path + '\'' +
", operation=" + operation +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Difference that = (Difference) o;
return Objects.equals(value, that.value) &&
Objects.equals(path, that.path) &&
operation == that.operation;
}
@Override
public int hashCode() {
return Objects.hash(value, path, operation);
}
}
public class JsonDiff {
ObjectMapper mapper = new ObjectMapper();
ObjectNode output = mapper.createObjectNode();
ArrayNode changeEntities = output.putArray("changeEntities");
private static final Set<Class<?>> JSON_PRIMITIVES = Set.of(
Integer.class,
Long.class,
Double.class,
String.class,
Boolean.class
);
public List<Difference> diff(Map<String, Object> from,
Map<String, Object> to) {
return diff(from, to, "/");
}
public List<Difference> diff(Map<String, Object> from,
Map<String, Object> to,
String path) {
if (from == to) {
return List.of();
}
List<Difference> differences = new ArrayList<>();
Set<String> keys = new HashSet<>();
println("from keys=" + from.keySet());
println("to keys=" + to.keySet());
keys.addAll(from.keySet());
keys.addAll(to.keySet());
keys.forEach(key -> {
// key is removed
if (!to.containsKey(key) && from.containsKey(key)) {
differences.add(new Difference(from.get(key), path + key, Operation.REMOVED));
// new key is added
} else if (to.containsKey(key) && !from.containsKey(key)) {
differences.add(new Difference(to.get(key), path + key, Operation.ADDED));
// existing key is modified
} else {
println("existing key is modified");
differences.addAll(compare(from.get(key), to.get(key), path + key + "/"));
}
});
System.out.println("@@@ output = "+output);
return differences;
}
private List<Difference> compare(Object from, Object to, String path) {
println("path="+ path)
println("from="+ from)
println("to="+ to)
var differences = new ArrayList<Difference>();
var fromClass = from.getClass();
var toClass = to.getClass();
if (oneIsPrimitive(fromClass, toClass)) {
if (!from.equals(to)) {
changeEntities.add(to);
println("oneIsPrimitive To="+to);
differences.add(new Difference(to, path, Operation.UPDATED));
}
} else if (bothAreObjects(from, to)) {
println("both are object")
differences.addAll(diff((Map<String, Object>) from, (Map<String, Object>) to, path));
} else if (bothAreArrays(fromClass, toClass)) {
println("bothAreArrays")
var fromArray = (ArrayList<Object>) from;
var toArray = (ArrayList<Object>) to;
var arrayDiffs = new ArrayList<Difference>();
for (int i = 0; i < Math.min(fromArray.size(), toArray.size()); i++) {
println("changed json=" + toArray.get(i))
arrayDiffs.addAll(compare(fromArray.get(i), toArray.get(i), path + i + "/"));
}
// add new to fromArray
if (toArray.size() > fromArray.size()) {
for (int i = fromArray.size(); i < toArray.size(); i++) {
arrayDiffs.add(new Difference(toArray.get(i), path + i, Operation.ADDED));
}
}
// remove extra from fromArray
if (toArray.size() < fromArray.size()) {
for (int i = toArray.size(); i < fromArray.size(); i++) {
arrayDiffs.add(new Difference(fromArray.get(i), path + i, Operation.REMOVED));
}
}
differences.addAll(arrayDiffs);
}
return differences;
}
private boolean oneIsPrimitive(Class<?> from, Class<?> to) {
return JSON_PRIMITIVES.contains(to) || JSON_PRIMITIVES.contains(from);
}
private boolean bothAreObjects(Object from, Object to) {
return from instanceof Map && to instanceof Map;
}
private boolean bothAreArrays(Class<?> from, Class<?> to) {
return from == ArrayList.class && to == ArrayList.class;
}
}
System.out.println("@@Initialization END----------------------------------- ");
which you can run online at - https://www.jdoodle.com/execute-groovy-online/
Once executed you will see it gives result as [Difference{value=AcademicAdministration2, path='/entities/0/L1_Entity_Nm/', operation=UPDATED}] format but I want as given above my expected output.
Thank in advance for your time!
答: 暂无答案
评论