比较两个 JSON 时忽略特定节点/属性

新手上路,请多包涵

我想比较两个 JSON 字符串,这是一个巨大的层次结构,并且想知道它们在值上的不同之处。但是有些值是在运行时生成的并且是动态的。我想从我的比较中忽略那些特定的节点。

我目前正在使用 org.SkyScreamer 中的 JSONAssert 进行比较。它给了我很好的控制台输出但不忽略任何属性。

例如。

 java.lang.AssertionError messageHeader.sentTime
expected:null
got:09082016 18:49:41.123

现在这是动态的,应该被忽略。就像是

JSONAssert.assertEquals(expectedJSONString, actualJSONString,JSONCompareMode, *list of attributes to be ignored*)

如果有人在 JSONAssert 中提出解决方案,那就太好了。但是,也欢迎使用其他方式。

原文由 Prateik 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.2k
2 个回答

您可以为此使用自定义。例如,如果您需要忽略名为“timestamp”的顶级属性,请使用:

 JSONAssert.assertEquals(expectedResponseBody, responseBody,
            new CustomComparator(JSONCompareMode.LENIENT,
                new Customization("timestamp", (o1, o2) -> true)));

也可以使用像“entry.id”这样的路径表达式。在您的自定义中,您可以使用任何您喜欢的方法来比较这两个值。上面的例子总是返回 true,不管期望值和实际值是多少。如果需要,您可以在那里做更复杂的事情。

忽略多个属性的值是完全没问题的,例如:

 @Test
public void ignoringMultipleAttributesWorks() throws JSONException {
    String expected = "{\"timestamp\":1234567, \"a\":5, \"b\":3 }";
    String actual = "{\"timestamp\":987654, \"a\":1, \"b\":3 }";

    JSONAssert.assertEquals(expected, actual,
            new CustomComparator(JSONCompareMode.LENIENT,
                    new Customization("timestamp", (o1, o2) -> true),
                    new Customization("a", (o1, o2) -> true)
            ));
}

使用自定义时有一个警告:要以自定义方式比较其值的属性必须存在于实际的 JSON 中。如果您希望比较成功,即使该属性根本不存在,您也必须重写 CustomComparator,例如:

 @Test
public void extendingCustomComparatorToAllowToCompletelyIgnoreCertainAttributes() throws JSONException {
    // AttributeIgnoringComparator completely ignores some of the expected attributes
    class AttributeIgnoringComparator extends CustomComparator{
        private final Set<String> attributesToIgnore;

        private AttributeIgnoringComparator(JSONCompareMode mode, Set<String> attributesToIgnore, Customization... customizations) {
            super(mode, customizations);
            this.attributesToIgnore = attributesToIgnore;
        }

        protected void checkJsonObjectKeysExpectedInActual(String prefix, JSONObject expected, JSONObject actual, JSONCompareResult result) throws JSONException {
            Set<String> expectedKeys = getKeys(expected);
            expectedKeys.removeAll(attributesToIgnore);
            for (String key : expectedKeys) {
                Object expectedValue = expected.get(key);
                if (actual.has(key)) {
                    Object actualValue = actual.get(key);
                    compareValues(qualify(prefix, key), expectedValue, actualValue, result);
                } else {
                    result.missing(prefix, key);
                }
            }
        }
    }

    String expected = "{\"timestamp\":1234567, \"a\":5}";
    String actual = "{\"a\":5}";

    JSONAssert.assertEquals(expected, actual,
            new AttributeIgnoringComparator(JSONCompareMode.LENIENT,
                    new HashSet<>(Arrays.asList("timestamp")))
            );
}

(通过这种方法,您仍然可以使用自定义以您想要的方式比较其他属性的值。)

原文由 dknaus 发布,翻译遵循 CC BY-SA 4.0 许可协议

您可以使用 JsonUnit 它具有您正在寻找的功能,我们可以忽略字段、路径和空值等。查看它以获取更多信息。至于示例,您可以忽略这样的路径

assertJsonEquals(
     "{\"root\":{\"test\":1, \"ignored\": 2}}",
     "{\"root\":{\"test\":1, \"ignored\": 1}}",
     whenIgnoringPaths("root.ignored")
);

有时您需要在比较时忽略某些值。可以像这样使用 ${json-unit.ignore} 占位符

assertJsonEquals("{\"test\":\"${json-unit.ignore}\"}",
    "{\n\"test\": {\"object\" : {\"another\" : 1}}}");

原文由 Srikar 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题