在基于另一个架构对象的 json 架构上使用条件语句

use*_*192 6 schema json jsonschema json-schema-validator

我有一个 json 对象,如:

{
  "session": {
    "session_id": "A",
    "start_timestamp": 1535619633301
  },
  "sdk": {
    "name": "android",
    "version": "21"
  }
}
Run Code Online (Sandbox Code Playgroud)

sdk name可以是android or ios。并且session_id基于name fieldin sdk json。我写了一个json schemausing 条件语句(使用草案 7)如下:

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

{
  "$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"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

所以下面的 JSON 传递:

{
      "session": {
        "session_id": "A",
        "start_timestamp": 1535619633301
      },
      "sdk": {
        "name": "ios",
        "version": "21"
      }
    }
Run Code Online (Sandbox Code Playgroud)

但这失败了:

{
      "session": {
        "session_id": "B",
        "start_timestamp": 1535619633301
      },
      "sdk": {
        "name": "android",
        "version": "21"
      }
    }
Run Code Online (Sandbox Code Playgroud)

有人可以解释一下吗?..即使这样通过:

{
      "session": {
        "session_id": "A",
        "start_timestamp": 1535619633301
      },
      "sdk": {
        "name": "android",
        "version": "21"
      }
    }
Run Code Online (Sandbox Code Playgroud)

gre*_*nis 8

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

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

子模式仅在实例中的级别上运行,而不是在根上运行。

考虑一个包含 aone和一个two属性的简单 JSON 对象实例的模式:

{
  "properties": {
    "one": {
      "enum": ["yes", "no", "maybe"]
    },
    "two": {
      "if": {
        "properties": {
          "one": {"const": "yes"}
        }
      },
      "then": {
        ...       // do some assertions on the two property here
      },
      "else": {
        ...
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

为了让two属性subschema 下的subschema 可以看到one实例中的属性,你必须将关键字移到if外面properties

{
  "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
  }
}
Run Code Online (Sandbox Code Playgroud)

对于 的两个可能值one,这是相当不错的。即使三个可能的值也不错。但是,随着 的可能值的one增加,ifs的嵌套也会增加,这会使您的架构难以阅读(并且可能使验证变慢)。

代替使用的if/ then/else构建体的话,建议使用anyOfoneOf其中每个子模式表示用于实例的有效状态,给定的变化值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
      }
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

在我看来,这要干净得多。

希望该解释可以帮助您重建架构以允许其他实例通过。