在基于另一个架构对象的json架构上使用条件语句 [英] Use conditional statements on json schema based on another schema object

查看:71
本文介绍了在基于另一个架构对象的json架构上使用条件语句的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个像这样的json对象:

I have a json object like:

{
  "session": {
    "session_id": "A",
    "start_timestamp": 1535619633301
  },
  "sdk": {
    "name": "android",
    "version": "21"
  }
}

sdk name可以是android or ios.并且session_id基于sdk json中的name field.我使用条件语句(使用草案7)编写了json schema,如下所示:

The sdk name can either be android or ios. And the session_id is based on name field in sdk json. I have written a json schema using conditional statement (Using draft 7) as follows:

但是它以一种意想不到的方式工作:

But it works in an unexpected manner:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$ref": "#/definitions/Base",
  "definitions": {
    "Base": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "session": {
          "$ref": "#/definitions/Session"
        },
        "sdk": {
          "$ref": "#/definitions/SDK"
        }
      },
      "title": "Base"
    },
    "Session": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "start_timestamp": {
          "type": "integer",
          "minimum": 0
        },
        "session_id": {
          "type": "string",
          "if": {
            "SDK": {
              "properties": {
                "name": {
                  "enum": "ios"
                }
              }
            }
          },
          "then": {
            "pattern": "A"
          },
          "else": {
            "pattern": "B"
          }
        }
      },
      "required": [
        "session_id",
        "start_timestamp"
      ],
      "title": "Session"
    },
    "SDK": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "version": {
          "type": "string"
        },
        "name": {
          "type": "string",
          "enum": [
            "ios",
            "android"
          ]
        }
      },
      "required": [
        "name",
        "version"
      ],
      "title": "SDK"
    }
  }
}

因此,以下JSON通过:

So the following JSON Passes:

{
      "session": {
        "session_id": "A",
        "start_timestamp": 1535619633301
      },
      "sdk": {
        "name": "ios",
        "version": "21"
      }
    }

但这失败了:

{
      "session": {
        "session_id": "B",
        "start_timestamp": 1535619633301
      },
      "sdk": {
        "name": "android",
        "version": "21"
      }
    }

有人可以解释y吗?.即使通过了:

can someone explain y?.. Even this passes:

{
      "session": {
        "session_id": "A",
        "start_timestamp": 1535619633301
      },
      "sdk": {
        "name": "android",
        "version": "21"
      }
    }

推荐答案

我认为您遇到的问题与此问题类似.

I think you're having a similar problem as in this question.

@Relequestual是正确的,因为您需要在SDK标注周围使用properties关键字.但是对于您想做的事情,您需要进行重组.

@Relequestual is right in that you need the properties keyword around your SDK callout. But for what you want to do, you need to reorganize.

子计划仅在实例级别运行,而不是在根级别运行.

Subschemas only operate on their level in the instance, not at the root.

将此模式考虑为包含onetwo属性的简单JSON对象实例:

Consider this schema for a simple JSON object instance containing a one and a two property:

{
  "properties": {
    "one": {
      "enum": ["yes", "no", "maybe"]
    },
    "two": {
      "if": {
        "properties": {
          "one": {"const": "yes"}
        }
      },
      "then": {
        ...       // do some assertions on the two property here
      },
      "else": {
        ...
      }
    }
  }
}

two属性下的if关键字只能考虑two属性下的实例部分(即two的值).它没有查看实例的根,因此根本看不到one属性.

The if keyword under the two property can only consider the portion of the instance under the two property (i.e. two's value). It's not looking at the root of the instance, so it can't see the one property at all.

要使其生效,以便two属性子模式下的子模式可以在实例中看到one属性,您必须将if移到properties关键字之外.

To make it so that the subschema under the two property subschema can see the one property in the instance, you have to move the if outside of the properties keyword.

{
  "if": {
    "properties": {
      "one": {"const" : "yes"}
    }
  },
  "then": {
    ...       // do some assertions on the two property here
  },
  "else": {
    ...       // assert two here, or have another if/then/else structure to test the one property some more
  }
}

对于one的两个可能值,这非常好.甚至三个可能的值也不错.但是,随着one可能值的增加,if的嵌套也会增加,这会使您的架构难以阅读(并可能使验证速度变慢).

For two possible values of one, this is pretty good. Even three possible values isn't bad. However, as the possible values of one increases, so does the nesting of ifs, which can make your schema horrible to read (and possibly make validation slower).

我建议使用anyOfoneOf,而不是使用if/then/else构造,其中每个子模式都代表实例的有效状态,并给出one的不同值

Instead of using the if/then/else construct, I suggest using an anyOf or oneOf where each subschema represents a valid state for the instance, given the varying values of one.

{
  "oneOf": [
    {
      "properties": {
        "one": {"const": "yes"},
        "two": ...         // do some assertions on the two property here
      }
    },
    {
      "properties": {
        "one": {"const": "no"},
        "two": ...         // do some assertions on the two property here
      }
    },
    {
      "properties": {
        "one": {"const": "maybe"},
        "two": ...         // do some assertions on the two property here
      }
    }
  ]
}

我认为这要干净得多.

希望这种解释有助于您重构架构,以允许其他实例通过.

Hopefully that explanation helps you reconstruct your schema to allow those other instances to pass.

这篇关于在基于另一个架构对象的json架构上使用条件语句的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆