json 我如何需要一个字段或另一个字段或(其他两个字段之一)但不是所有字段?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24023536/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 17:20:25  来源:igfitidea点击:

How do I require one field or another or (one of two others) but not all of them?

jsonvalidationjsonschema

提问by user3486184

I am having trouble coming up with a JSON schema that will validate if the JSON contains either:

我在想出一个 JSON 模式时遇到了问题,该模式将验证 JSON 是否包含:

  • one field only
  • another field only
  • (one of two other fields) only
  • 只有一个领域
  • 只有另一个领域
  • (其他两个字段之一)仅

but not to match when multiples of those are present.

但当存在多个时不匹配。

In my case specifically, I want one of

就我而言,我想要其中之一

  • copyAll
  • fileNames
  • matchesFilesand/or doesntMatchFiles
  • copyAll
  • fileNames
  • matchesFiles和/或 doesntMatchFiles

to validate but I don't want to accept when more than that is there.

验证但我不想接受更多。

Here's what I've got so far:

这是我到目前为止所得到的:

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "required": [ "unrelatedA" ],
    "properties": {
    "unrelatedA": {
        "type": "string"
    },
    "fileNames": {
        "type": "array"
    },
    "copyAll": {
        "type": "boolean"
    },
    "matchesFiles": {
        "type": "array"
    },
    "doesntMatchFiles": {
        "type": "array"
        }
    },
    "oneOf": [
         {"required": ["copyAll"], "not":{"required":["matchesFiles"]}, "not":{"required":["doesntMatchFiles"]}, "not":{"required":["fileNames"]}},
         {"required": ["fileNames"], "not":{"required":["matchesFiles"]}, "not":{"required":["doesntMatchFiles"]}, "not":{"required":["copyAll"]}},
         {"anyOf": [
               {"required": ["matchesFiles"], "not":{"required":["copyAll"]}, "not":{"required":["fileNames"]}},
               {"required": ["doesntMatchFiles"], "not":{"required":["copyAll"]}, "not":{"required":["fileNames"]}}]}
    ]
} ;

This matches more than I want to. I want this to match all of the following:

这比我想要的更匹配。我希望它符合以下所有条件:

{"copyAll": true, "unrelatedA":"xxx"}
{"fileNames": ["aab", "cab"], "unrelatedA":"xxx"}
{"matchesFiles": ["a*"], "unrelatedA":"xxx"}
{"doesntMatchFiles": ["a*"], "unrelatedA":"xxx"}
{"matchesFiles": ["a*"], "doesntMatchFiles": ["*b"], "unrelatedA":"xxx"}

but not to match:

但不匹配:

{"copyAll": true, "matchesFiles":["a*"], "unrelatedA":"xxx"}
{"fileNames": ["a"], "matchesFiles":["a*"], "unrelatedA":"xxx"}
{"copyAll": true, "doesntMatchFiles": ["*b"], "matchesFiles":["a*"], "unrelatedA":"xxx"}
{"fileNames": ["a"], "matchesFiles":["a*"], "unrelatedA":"xxx"}
{"unrelatedA":"xxx"}

I'm guessing there's something obvious I'm missing - I'd like to know what it is.

我猜我遗漏了一些明显的东西 - 我想知道它是什么。

回答by jruizaranguren

The problem is the "not" semantics. "not required" does not mean "inclusion forbidden". It just means that you don't have to add it in order to validate that schema.

问题是“非”语义。“不需要”并不意味着“禁止包含”。这只是意味着您不必添加它来验证该架构。

However, you can use "oneOf" to satisfy your specification in a simpler way. Remember that it means that "just one of these schemas can validate". The following schema achieves the property switching you are attempting to solve:

但是,您可以使用“oneOf”以更简单的方式满足您的规范。请记住,这意味着“只有这些模式中的一个可以验证”。以下架构实现了您尝试解决的属性切换:

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "required": [
        "unrelatedA"
    ],
    "properties": {
        "unrelatedA": {
            "type": "string"
        },
        "fileNames": {
            "type": "array"
        },
        "copyAll": {
            "type": "boolean"
        },
        "matchesFiles": {
            "type": "array"
        },
        "doesntMatchFiles": {
            "type": "array"
        }
    },
    "oneOf": [
        {
            "required": [
                "copyAll"
            ]
        },
        {
            "required": [
                "fileNames"
            ]
        },
        {
            "anyOf": [
                {
                    "required": [
                        "matchesFiles"
                    ]
                },
                {
                    "required": [
                        "doesntMatchFiles"
                    ]
                }
            ]
        }
    ]
}

回答by Vadim Samokhin

This answer is not related to JSON schema, so it's a bit off the track, though it can bring another perspective on solving this problem, and json validation in general.

这个答案与 JSON 模式无关,所以它有点偏离轨道,尽管它可以带来解决这个问题的另一个视角,以及一般的 json 验证。

The point is to express declaratively exactly what you need as a result: a single field which is the only present. Consider the following json schema:

关键是要以声明方式准确表达您所需要的结果:唯一存在的单个字段。考虑以下 json 模式:

JsonElement json =
    new Gson().toJsonTree(
        Map.of(
            "first_field", "vasya",
            "second_field", false,
            "third_field", 777,
            "unrelated", "Rinse"
        )
    );

Let's say you need either one of the first_field, second_field, and third_field. The fourth field doesn't matter. Here is how the corresponding validation object looks like:

比方说,你需要的任何一个first_fieldsecond_fieldthird_field。第四个字段无关紧要。下面是相应的验证对象的样子:

Result<SomeTestStructure> result =
    new UnnamedBlocOfNameds<SomeTestStructure>(
        List.of(
            new OneOf(
                "global",
                new ErrorStub("Only one of the fields must be present"),
                new AsString(
                    new Required(
                        new IndexedValue("first_field", json)
                    )
                ),
                new AsBoolean(
                    new Required(
                        new IndexedValue("second_field", json)
                    )
                ),
                new AsInteger(
                    new Required(
                        new IndexedValue("third_field", json)
                    )
                )
            ),
            new AsString(
                new IndexedValue("unrelated", json)
            )
        ),
        SomeTestStructure.class
    )
        .result();

First, you declare an unnamed block consisting of named ones; then you say that you need a single successful validatable element out of the three ones. And finally, you declare what success means. In this case, to be successful is to be simply present. If json is valid, an object of SomeTestStructureclass is created:

首先,声明一个由命名块组成的未命名块;那么你说你需要三个元素中的一个成功的可验证元素。最后,你宣布成功意味着什么。在这种情况下,成功就是简单地存在。如果 json 有效,SomeTestStructure则创建类的对象:

assertTrue(result.isSuccessful());
assertEquals(
    new SomeTestStructure(777, "Rinse").thirdField(),
    result.value().raw().thirdField()
);

For more info about this approach and a library implementing it, check out a quick start entry.

有关此方法和实现它的库的更多信息,请查看快速入门条目