1

鉴于下面的 JSON 和 Schema,actor.mbox、actor.member[0].objectType 和 actor.member[0].mbox 都应该失败。他们不。我的架构一定有问题。我想我已将其范围缩小到处理 IdGroup 定义的内容,但我找不到问题所在。任何 json 架构大师都看到任何明显错误的东西吗?

JSON

{
  "actor": {
    "objectType": "Group",
    "name": "Group Identified",
    "mbox": "http://should.fail.com",
    "member": [
      {
        "objectType": "Agent_shouldfail",
        "name": "xAPI mbox",
        "mbox": "mailto:shouldfail"
      }
    ]
  },
  "verb": {
    "id": "http://adlnet.gov/expapi/verbs/attended",
    "display": {
      "en-GB": "attended",
      "en-US": "attended"
    }
  },
  "object": {
    "objectType": "Activity",
    "id": "http://www.example.com/meetings/occurances/34534"
  }
}

JSON Schema(精简)

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "xAPIValidator",
  "description": "Validation schema for xAPI tests",
  "type": "object",
  "allOf": [
    {
      "$ref": "#/definitions/Statement"
    }
  ],
  "statements": {
    "type": "array",
    "items": {
      "allOf": [
        {
          "$ref": "#/definitions/Statement"
        }
      ]
    }
  },
  "definitions": {
    "Statement": {
      "$id": "#Statement",
      "additionalProperties": false,
      "properties": {
        "objectType": {
          "type:": "string",
          "enum": [
            "Agent",
            "Activity",
            "Group",
            "SubStatement",
            "StatementRef"
          ]
        },
        "id": {
          "allOf": [
            {
              "$ref": "#/definitions/uuid"
            }
          ]
        },
        "timestamp": {
          "allOf": [
            {
              "$ref": "#/definitions/timestamp"
            }
          ]
        },
        "stored": {
          "allOf": [
            {
              "$ref": "#/definitions/timestamp"
            }
          ]
        },
        "version": {
          "allOf": [
            {
              "$ref": "#/definitions/semanticVersion"
            }
          ]
        },
        "actor": {
          "$id": "#actor",
          "allOf": [
            {
              "$ref": "#/definitions/allOfAgentGroup"
            }
          ]
        },
        "authority": {
          "allOf": [
            {
              "$ref": "#/definitions/allOfAgentGroup"
            }
          ]
        },
        "verb": {
          "$id": "#verb",
          "type": "object",
          "properties": {
            "id": {
              "allOf": [
                {
                  "$ref": "#/definitions/URI"
                }
              ]
            },
            "display": {
              "type": "object",
              "allOf": [
                {
                  "$ref": "#/definitions/lang5646"
                }
              ]
            }
          }
        },
        "object": {
          "$id": "#object",
          "type": "object",
          "additionalProperties": true,
          "properties": {
            "objectType": {
              "type:": "string",
              "enum": [
                "Activity",
                "Agent",
                "Group",
                "SubStatement",
                "StatementRef"
              ]
            }
          }
        }
      },
      "required": [
        "actor",
        "verb",
        "object"
      ]
    },
    "attachment": {
      "properties": {
        "usageType": {
          "allOf": [
            {
              "$ref": "#/definitions/URI"
            }
          ]
        },
        "display": {
          "allOf": [
            {
              "$ref": "#/definitions/lang5646"
            }
          ]
        },
        "description": {
          "allOf": [
            {
              "$ref": "#/definitions/lang5646"
            }
          ]
        },
        "contentType": {
          "type": "string",
          "pattern": "\\w+/[-+.\\w]+;?(\\w+.*=\\w+;?)*"
        },
        "length": {
          "type": "integer"
        },
        "sha2": {
          "type": "string"
        },
        "fileUrl": {
          "allOf": [
            {
              "$ref": "#/definitions/URI"
            }
          ]
        }
      }
    },
    "semanticVersion": {
      "type": [
        "string"
      ],
      "pattern": "^([0-9]+)\\.([0-9]+)\\\\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?(?:\\+[0-9A-Za-z-]+)?$"
    },
    "Agent": {
      "$id": "#Agent",
      "allOf": [
        {
          "$ref": "#/definitions/IFI"
        }
      ]
    },
    "AnonGroup": {
      "$id": "#AnonGroup",
      "maxProperties": 3,
      "properties": {
        "member": {
          "type": "array",
          "items": [
            {
              "allOf": [
                {
                  "$ref": "#/definitions/allOfAgentGroup"
                }
              ]
            }
          ]
        }
      },
      "dependencies": {
        "objectType": [
          "member"
        ]
      },
      "required": [
        "member"
      ],
      "not": {
        "required": [
          "mbox"
        ]
      },
      "not": {
        "required": [
          "mbox_sha1sum"
        ]
      },
      "not": {
        "required": [
          "openid"
        ]
      },
      "not": {
        "required": [
          "account"
        ]
      }
    },
    "IdGroup": {
      "$id": "#IdGroup",
      "properties": {
        "member": {
          "type": "array",
          "items": [
            {
              "allOf": [
                {
                  "$ref": "#/definitions/allOfAgentGroup"
                }
              ]
            }
          ]
        }
      },
      "allOf": [
        {
          "$ref": "#/definitions/IFI"
        }
      ]
    },
    "allOfAgentGroup": {
      "properties": {
        "objectType": {
          "type": "string",
          "enum": [
            "Agent",
            "Group"
          ]
        },
        "name": {
          "type": "string"
        }
      },
      "oneOf": [
        {
          "if": {
            "properties": {
              "objectType": {
                "const": "Agent"
              }
            }
          },
          "then": {
            "allOf": [
              {
                "$ref": "#/definitions/Agent"
              }
            ]
          }
        },
        {
          "if": {
            "properties": {
              "objectType": {
                "const": "Group"
              }
            }
          },
          "then": {
            "oneOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/definitions/IdGroup"
                  }
                ]
              },
              {
                "allOf": [
                  {
                    "$ref": "#/definitions/AnonGroup"
                  }
                ]
              }
            ]
          }
        }
      ]
    },
    "IFI": {
      "oneOf": [
        {
          "properties": {
            "mbox": {
              "allOf": [
                {
                  "$ref": "#/definitions/mailto"
                }
              ]
            }
          },
          "required": [
            "mbox"
          ]
        },
        {
          "properties": {
            "mbox_sha1sum": {
              "type": "string",
              "pattern": "\\b[0-9a-f]{5,40}\\b"
            }
          },
          "required": [
            "mbox_sha1sum"
          ]
        },
        {
          "properties": {
            "account": {
              "properties": {
                "homePage": {
                  "allOf": [
                    {
                      "$ref": "#/definitions/URI"
                    }
                  ]
                },
                "name": {
                  "type": "string"
                }
              },
              "required": [
                "homePage",
                "name"
              ]
            }
          },
          "required": [
            "account"
          ]
        },
        {
          "properties": {
            "openid": {
              "allOf": [
                {
                  "$ref": "#/definitions/URI"
                }
              ]
            }
          },
          "required": [
            "openid"
          ]
        }
      ]
    },
    "mailto": {
      "type": "string",
      "pattern": "(mailto:)(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"
    },
    "timestamp": {
      "type": "string",
      "pattern": "^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(.[0-9]+)?(Z)?$"
    },
    "URI": {
      "type": "string",
      "pattern": "^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]"
    },
    "uuid": {
      "type": "string",
      "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
    },
    "lang5646": {
      "type": "object",
      "patternProperties": {
        "^((?:(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang))|((?:([A-Za-z]{2,3}(-(?:[A-Za-z]{3}(-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8})(-(?:[A-Za-z]{4}))?(-(?:[A-Za-z]{2}|[0-9]{3}))?(-(?:[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(-(?:[0-9A-WY-Za-wy-z](-[A-Za-z0-9]{2,8})+))*(-(?:x(-[A-Za-z0-9]{1,8})+))?)|(?:x(-[A-Za-z0-9]{1,8})+))$": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "lang5646string": {
      "type": "string",
      "pattern": "^((?:(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang))|((?:([A-Za-z]{2,3}(-(?:[A-Za-z]{3}(-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8})(-(?:[A-Za-z]{4}))?(-(?:[A-Za-z]{2}|[0-9]{3}))?(-(?:[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(-(?:[0-9A-WY-Za-wy-z](-[A-Za-z0-9]{2,8})+))*(-(?:x(-[A-Za-z0-9]{1,8})+))?)|(?:x(-[A-Za-z0-9]{1,8})+))$"
    }
  }
}
4

1 回答 1

1

if/then/else不像你预期的那样工作。

在您的架构定义allOfAgentGroup中有一个oneOf部分。让我们自己看一下。

在您应该失败的示例数据中,让我们也使用它自己的“演员”对象。

架构:

{
  "oneOf": [
    {
      "if": {
        "properties": {
          "objectType": {
            "const": "Agent"
          }
        }
      },
      "then": false
      }
    },
    false
  ]
}

实例数据:

{
  "objectType": "Group",
  "name": "Group Identified",
  "mbox": "http://should.fail.com",
  "member": [
    {
      "objectType": "Agent_shouldfail",
      "name": "xAPI mbox",
      "mbox": "mailto:shouldfail"
    }
  ]
}

我们知道您希望数组中的第二部分项oneOf验证失败。出于调试和演示的目的,我们假设它确实失败了,并将其更改为false(这是一个有效的“JSON Schema”,总是导致该分支上的验证失败)。

现在,鉴于上述模式和实例,您会期望 JSON 实例数据验证失败,对吧?它没有,实际上验证通过了。

请记住,每个 JSON Schema 关键字都会为您的验证要求添加约束。让我们看看做什么ifthen实际做什么。

if

此关键字的子模式的验证结果对整体验证结果没有直接影响。相反,它控制评估“then”或“else”关键字中的哪一个。

成功验证此关键字的子模式的实例也必须对“then”关键字的子模式值有效(如果存在)。

http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.6

好的,所以如果if成功验证的模式,then则应用来自的模式。

实例数据未通过 if 条件验证,因此...then未应用来自的架构,您最终会得到有效的“空架构”,这意味着oneOf/0. 这导致您oneOf断言验证成功,因为oneOf/0通过和oneOf/1失败。

为了解决这个问题,您需要添加"then": false到包含ifand的对象中,如果不满足条件then,您希望该架构项验证失败。if

于 2019-05-02T09:10:49.320 回答