JSON模式属性取决于先前属性的值

编程入门 行业动态 更新时间:2024-10-27 08:24:44
本文介绍了JSON模式属性取决于先前属性的值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我希望能够编写JSON模式代码,该代码允许一个属性的值依赖于另一个属性的值.

I'd like to be able to write JSON schema code that allows one property's value to be dependent on the value of another property.

更具体地说,我有两个问题A和B.只有当问题A有特定答案时,问题B的答案才能为空.如果问题A没有该答案,则问题B的值必须为空.

More specifically, I have two questions A and B. Question B's answer can only be not null when question A has a specific answer. If question A does not have that answer, then the value to question B must be null.

例如

A: Do you like cars? Yes/No B: What is your favourite car?

仅当问题A的答案为是"时,才能回答问题B,否则必须将其保留为空.

Question B can only be answered if the answer to question A is "Yes", otherwise it must be left null.

经过一番研究,我发现了这个Stack Overflow线程,它描述了枚举和if-then-else回答这个问题的方法.枚举非常接近我的需要,定义如下:

After some research I have found this Stack Overflow thread, which describes the enum and if-then-else approaches to answering this question. The enum is very close to what I need and is defined as below:

{ "type": "object", "properties": { "foo": { "enum": ["bar", "baz"] }, "bar": { "type": "string" }, "baz": { "type": "string" } }, "anyOf": [ { "properties": { "foo": { "enum": ["bar"] } }, "required": ["bar"] }, { "properties": { "foo": { "enum": ["baz"] } }, "required": ["baz"] } ] }

在上面,当Foo的值为"Bar"时,则需要Bar属性.同样,值为"Baz".但是,我不需要将属性设置为必需,而是希望能够将属性的类型从null更改为string.或采取一些措施使B的答案有效.

In the above, when the value of Foo is "Bar", then the Bar property is required. Likewise with the value of "Baz". However instead of making the property required, I want to be able to change the type of the property from null to string. Or do something to be able to make the answer to B valid.

对此有何想法?

推荐答案

您是否考虑

  • 未定义 B型预付款
  • 在架构中使用"dependencies"关键字,或针对问题A做出包含答案是"的适当定义
  • 仅由于这种依赖性而定义问题B的类型?
  • not defining type of B upfront
  • using "dependencies" keyword for your schema or making appropriate definition containing answer 'Yes' for question A
  • and defining question B type only as a result of such dependency?
  • 让我们来总结一下

    "questionA": { "type": "object", "properties": { "answer": { "type": "string", "minLength": 1, "enum": ["Yes", "No"] } } } "questionB": { "type": "object", "properties": { "answer": { "type": null, } } } "questions": { "type": "object", "properties": { "A": {"$ref": "#/definitions/questionA"}, "B": {"$ref": "#/definitions/questionB"} }, "if": { "properties" : { "A": {"enum": ["Yes"]} } }, "then": { "B": //Type = string and min length = 1 <-- Unsure what to put here to change the type of QuestionB }

    如果我正确理解您的问题,那么您想要达到的效果是:

    If I understand correctly your question, the effect you want to achieve is:

    如果受访者喜欢汽车,请向他询问最喜欢的汽车并获取答案,否则不要打扰最喜欢的汽车(最好将答案强制为空).

    正如Relequestual在他的评论中正确指出的那样,JSON Schema使其很难重新定义"类型.此外,每个if-then-else内容本身都必须是有效的架构.

    As Relequestual correctly ponted out in his comment, JSON Schema makes it hard to 'redefine' type. Moreover, each if-then-else content must be a valid schema on it's own.

    为了达到此效果,您可能需要考虑以下方法:

    In order to achieve this effect, you may want to consider following approach:

  • 像您一样将问题A定义为枚举
  • 为问题B保留属性未预先定义
  • 定义两个可能的模式,它们可以用作问题B的属性定义,并且可以作为依赖项的结果使用
  • 根据问题A的值使用适当的问题B定义
  • 下面列出了一些解决您的情况的示例架构(兼容draft07).架构下方还提供了一些说明.

    Some sample schema (draft07 compliant) which solves your case is listed below. Also some explanations provided below the schema.

    { "$schema": "json-schema/draft-07/schema#", "type" : "object", "propertyNames" : { "enum" : [ "questionA", "questionB", ] }, "properties" : { "questionA" : { "$ref" : "#/questionA" }, "questionB" : { "$ref" : "#/questionB" }, }, "dependencies" : { "questionA" : { "$ref" : "#/definitions/valid-combinations-of-qA-qB" } }, "definitions" : { "does-like-cars":{ "properties" : { "questionA" : { "properties" : { "answer" : { "enum" : ["Yes","y"] } } }, "questionB" : { "properties" : { "answer" : { "$comment" : "Here #/questionB/answer becomes a type:string...", "$ref" : "#/questionB/definitions/answer-def/string" } } } }, "required" : ["questionB"] }, "doesnt-like-cars" :{ "properties" : { "questionA" : { "properties" : { "answer" : { "enum" : ["No","n"] } } }, "questionB" : { "properties" : { "answer" : { "$comment" : "Here #/questionB/answer becomes a type:null...", "$ref" : "#/questionB/definitions/answer-def/null" } } } } }, "valid-combinations-of-qA-qB" : { "anyOf" : [ { "$ref" : "#/definitions/doesnt-like-cars" }, { "$ref" : "#/definitions/does-like-cars" } ] }, }, "examples" : [ { "questionA" : { "answer" : "Yes", }, "questionB" : { "answer" : "Ass-kicking roadster", }, }, { "questionA" : { "answer" : "No", }, "questionB" : { "answer" : null, }, }, { }, ], "questionA" : { "$id" : "#/questionA", "type" : "object", "propertyNames" : { "enum" : ["answer"] }, "properties" : { "answer" : {"$ref" : "#/questionA/definitions/answer-def"} }, "definitions" : { "answer-def" : { "$comment" : "Consider using pattern instead of enum if case insensitiveness is required", "type" : "string", "enum" : ["Yes", "y", "No", "n"] } } }, "questionB" : { "$id" : "#/questionB", "$comment" : "Please note no properties definitions here aside from propertyNames", "type" : "object", "propertyNames" : { "enum" : ["answer"] }, "definitions" : { "answer-def" : { "string" : { "type" : "string", "minLength" : 1, }, "null" : { "type" : "null" } } } }, }

    为什么这么复杂?

    因为您的要旨是这样;-)更严重的是,这是因为:

    Why so complicated?

    Because your gist made it so ;-) And more seriously, this is because:

    • 在要点中,您将两个问题都定义为对象.可能有 它背后的正当理由,所以我一直保持这种方式(但是无论何时平放 可以使用属性列表,例如"questionA-answer", 我希望使用"questionB-answer",这样可以减少架构规则的嵌套, 因此更具可读性且易于创建).

    • In your gist you define both questions as objects. There might be valid reason behind it, so I kept it that way (however whenever flat list of properties could be used, like "questionA-answer", "questionB-answer" I'd prefer it so to keep schema rules less nested, thus more readable and easy to create).

    从您的问题和要点看来,这对您很重要 "questionB/answer"为null而不是未通过验证 反对/忽略不相关的内容,因此我将其保留为

    It seems from your question and gist, that this is important for you that "questionB/answer" is null instead of not being validated against/ignored when it's not relevant, thus I kept it so

    请注意,我已经为"questionA"和"questionB"创建了单独的子模式.这是我的个人喜好,没有什么可以阻止您将所有内容放入主模式的"definitions"模式中,但是我通常这样做是因为:

    Please note, that I've created separate subschemas for "questionA" and "questionB". This is my personal preference and nothing stops you from getting everything inside "definitions" schema of main schema, however I do it usually that way because:

    • 在使一切都按其应有的方式工作之后,将大型模式拆分为多个较小的文件会更容易(鼓励重用子模式,如果有人在我的模式之后想建立自己的数据模型,则可以帮助以编程语言构造模型)
    • 保持对象模式/子方案的正确封装并保持良好,相对引用通常对于读者来说也更清楚
    • 帮助在处理JSON语法的编辑器中查看复杂的模式

    因为我们在这里处理"type":"object",所以我使用了"propertyNames"关键字来定义允许的属性名称的架构(因为编程语言中的类通常具有静态属性集).尝试在每个对象中输入此集合之外的属性-模式验证失败.这样可以防止对象中出现垃圾.如果不希望出现这种情况,只需从每个对象中删除"propertyNames"模式.

    Since we're working here on "type" : "object" I used "propertyNames" keyword to define schema for allowed property names (since classess in programming languages usually have static sets of properties). Try to enter in each object a property outside of this set - schema valdiation fails. This prevents garbage in your objects. Should it be not desired behaviour, just remove "propertyNames" schemas from each object.

    诀窍是:不要预先定义属性类型和其他相关的架构规则.请注意,"questionB"模式中没有属性"模式.相反,我使用"definitions"为"questionB"对象中的"answer"属性准备了两种可能的定义.我将根据"questionA"答案值来使用它们.

    The trick is: do not define property type and other relevant schema rules upfront. Please note how there's no "properties" schema in "questionB" schema. Instead, I used "definitions" to prepare two possible definitions of "answer" property inside "questionB" object. I will use them depending on "questionA" answer value.

    一些对象,应该说明架构的工作方式.试一试答案值,属性的存在等.请注意,空对象也将通过验证,因为不需要属性(如您的要点),并且只有一个依赖项-如果出现"questionA",则"questionB"也必须出现.

    Some objects, that should illustrate how schema works. Play around with answer values, presence of properties etc. Please note, that an empty object will also pass validation, as no property is required (as in your gist) and there's only one dependency - if "questionA" appears, a "questionB" must show up as well.

    好的. 因此,主模式可以具有两个属性:

    Sure. So the main schema can have two properties:

    • questionA(一个包含属性"answer"的对象)

    • questionA (an object containing property "answer")

    questionB(包含属性"answer"的对象)

    questionB (an object containing property "answer")

    是否需要#/questionA"? ->不,至少要根据您的要旨.

    Is "#/questionA" required? -> No, at least based on your gist.

    是否需要"questionB"? ->仅当出现#/questionA"时.为了增加侮辱性伤害,请:-)#/questionB/answer"的类型和允许的值严格取决于#/questionA/answer"的值.

    Is "questionB" required? -> Only if "#/questionA" appears. To add insult to injury :-) the type and allowed values of "#/questionB/answer" strictly depend on the value of "#/questionA/answer".

    ->我可以安全地预定义主要对象,问题对象的基础,并且需要定义依赖项

    --> I can safely pre-define main object, foundation for questions objects and will need to define dependency

    { "$schema": "json-schema/draft-07/schema#", "type" : "object", "propertyNames" : { "enum" : [ "questionA", "questionB", ] }, "properties" : { "questionA" : { "$ref" : "#/questionA" }, "questionB" : { "$ref" : "#/questionB" }, }, "dependencies" : { "questionA" : { "$comment" : "when questionA prop appears in validated entity, do something to enforce questionB to be what it wants to be! (like Lady Gaga in Machette...)" } }, "questionA" : { "$id" : "#/questionA", "type" : "object", "propertyNames" : { "enum" : ["answer"] }, }, "questionB" : { "$id" : "#/questionB", "type" : "object", "propertyNames" : { "enum" : ["answer"] }, }, }

    请注意:我正在通过"$ id"关键字有意识地为问题子方案设置相对基本引用,以便能够将架构拆分为多个较小的文件,并具有可读性.

    Please note I am conciously setting relative base reference via "$id" keyword for question sub-schemas to be able to split schema into multiple smaller files and also for read-ability.

    ->我可以安全地预定义"questionA/answer"属性:类型,允许的值等.

    --> I can safely pre-define "questionA/answer" property: type, allowed values etc.

    "questionA" : { "$id" : "#/questionA", "type" : "object", "propertyNames" : { "enum" : ["answer"] }, "properties" : { "answer" : {"$ref" : "#/questionA/definitions/answer-def"} }, "definitions" : { "answer-def" : { "$comment" : "Consider using pattern instead of enum if case insensitiveness is required", "type" : "string", "enum" : ["Yes", "y", "No", "n"] } } },

    注意::我使用定义"来定义特定属性的架构.以防万一我需要在其他地方重用该定义...(是的,对我的偏执)

    Note: I used "definitions" to, well, define schema for specific property. Just in case I'd need to re-use that definition somewhere else... (yep, paranoid about that I am)

    ->如上所述,我无法安全地预定义#/questionB/answer"属性,必须在#/questionB"子模式中执行技巧"部分

    --> I can't safely pre-define "#/questionB/answer" property as mentioned above and must do the "trick" part in "#/questionB" sub-schema

    "questionB" : { "$id" : "#/questionB", "$comment" : "Please note no properties definitions here aside from propertyNames", "type" : "object", "propertyNames" : { "enum" : ["answer"] }, "definitions" : { "answer-def" : { "string" : { "type" : "string", "minLength" : 1, }, "null" : { "type" : "null" } } } },

    注意:是否看到#/definitions/answer-def"?有两个子节点,即#/definitions/answer-def/string"和#/definitions/answer-def/null".我目前尚不确定该怎么做,但我知道我绝对需要最后具有#/questionB/answer"属性模式的功能.

    NOTE: See "#/definitions/answer-def"? There are two sub-nodes to that, "#/definitions/answer-def/string" and "#/definitions/answer-def/null" . I wasn't entirely sure how I'll do it at the moment, yet I knew I definitely will need that capability of juggle with "#/questionB/answer" property schema in the end.

    ->我必须为两个答案的有效组合定义规则,因为#/questionB/answer"必须始终存在;我正在主模式中执行此操作,该模式使用问题子方案,因为这是对问题的限制,从逻辑上讲,它是定义此类规则的好地方.

    --> I must define rules for valid combinations of both answers and since "#/questionB/answer" must be always present; I'm doing that in main schema, which uses questions sub-schemas as it's a cap over them that logically makes a good place to define such rule.

    "definitions" : { "does-like-cars":{ "properties" : { "questionA" : { "properties" : { "answer" : { "enum" : ["Yes","y"] } } }, "questionB" : { "properties" : { "answer" : { "$comment" : "Here #/questionB/answer becomes a type:string...", "$ref" : "#/questionB/definitions/answer-def/string" } } } }, "required" : ["questionB"] }, "doesnt-like-cars" :{ "properties" : { "questionA" : { "properties" : { "answer" : { "enum" : ["No","n"] } } }, "questionB" : { "properties" : { "answer" : { "$comment" : "Here #/questionB/answer becomes a type:null...", "$ref" : "#/questionB/definitions/answer-def/null" } } } } }, "valid-combinations-of-qA-qB" : { "anyOf" : [ { "$ref" : "#/definitions/doesnt-like-cars" }, { "$ref" : "#/definitions/does-like-cars" } ] },

    所以有些人喜欢汽车-我基本上定义了#/questionA/answer"的允许值和#/questionB/answer"的属性的相关定义.由于这是模式,因此两个集合必须匹配才能满足此定义.请注意,为了不验证针对模式仅包含"questionA"属性键的JSON,我已按要求将"questionB"属性键标记为必需.

    So there are those, who like cars - I basically define allowed values of "#/questionA/answer" and relevant definition of property of "#/questionB/answer". Since this is the schema, both sets must match to fulfill this definition. Please note I marked "questionB" property key as required in order to not validate JSON that contains only "questionA" property key against schema.

    我对那些不喜欢汽车的人做了类似的事情(怎么可能不喜欢汽车?邪恶的时代...),最后我在"valid-combinations-qa-qB"中说:要么,要么人.您要么喜欢汽车,然后给我答案,要么您不喜欢汽车,并且答案必须为空. "XOR"("oneOf")会自动出现,但是由于我已经定义了喜欢汽车AND answer 和不喜欢汽车AND answer = null 作为完整的模式,逻辑OR完全足够->"anyOf".

    I did similar thing for those, who don't like cars (how one cannot like cars?! Wicked times...) and at the end I said in "valid-combinations-of-qA-qB": It's either or, people. Either you like cars and give me the answer or you don't like cars and the answer must be null. "XOR" ("oneOf") comes to mind automatically but since I've defined like cars AND answer and doesn't like cars AND answer = null as a complete schemas, logical OR is completely sufficient -> "anyOf".

    最后,画龙点睛的是在主架构的依赖项"部分中使用该规则,该规则翻译为:如果"questionA"出现在经过验证的实例中,则...或...

    At the end the finishing touch was to use that rule in "dependencies" section of main schema, which translates to: if "questionA" appears in validated instance, either... or...

    "dependencies" : { "questionA" : { "$ref" : "#/definitions/valid-combinations-of-qA-qB" } },

    希望它能澄清您的情况并为您提供帮助.

    Hope it clarifies and helps with your case.

    为什么不使用对象答案"具有反映每个问题答案的属性,并使用键来标识问题?就答案之间的依赖性而言,它可以简化一些规则和参考(少键入,是的,我是个懒惰的小伙子).

    Why not use object "answers" with properties reflecting each question answer, with key identifying the question? It could simplify a bit rules and references with regards to dependencies between answers (less typing, yep, I'm a lazy lad).

    为什么#/questionB/答案"必须为空,而不是如果#/questionA/answer":{枚举":[否"]}}忽略它?

    Why "#/questionB/answer" must be null instead just ignoring it if "#/questionA/answer" : { "enum" : ["No"] } ?

    请参阅了解JSON模式": json-schema /understanding-json-schema/index.html

    See "Understanding JSON Schema" : json-schema/understanding-json-schema/index.html

    一些基本示例: json-schema/learn/

    JSON模式验证参考: json-schema/latest /json-schema-validation.html

    JSON schema validation reference: json-schema/latest/json-schema-validation.html

    大量StackOverflow问答对如何使用JSON模式管理不同案例提供了很好的见识.

    A lot of StackOverflow Q&A provides nice insight in how to manage different cases with JSON Schema.

    有时,检查相对的JSON指针RFC也可能会有所帮助.

    Also it might be helpful at occasion to check for relative JSON Pointers RFC.

    更多推荐

    JSON模式属性取决于先前属性的值

    本文发布于:2023-11-04 10:28:50,感谢您对本站的认可!
    本文链接:https://www.elefans.com/category/jswz/34/1557682.html
    版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
    本文标签:属性   先前   模式   JSON

    发布评论

    评论列表 (有 0 条评论)
    草根站长

    >www.elefans.com

    编程频道|电子爱好者 - 技术资讯及电子产品介绍!