JSON模式:"allof"带有"additionalProperties"

lm.*_*lm. 54 javascript json jsonschema

假设我们有模式跟随模式(来自这里的教程):

{
  "$schema": "http://json-schema.org/draft-04/schema#",

  "definitions": {
    "address": {
      "type": "object",
      "properties": {
        "street_address": { "type": "string" },
        "city":           { "type": "string" },
        "state":          { "type": "string" }
      },
      "required": ["street_address", "city", "state"]
    }
  },

  "type": "object",

  "properties": {
    "billing_address": { "$ref": "#/definitions/address" },
    "shipping_address": {
      "allOf": [
        { "$ref": "#/definitions/address" },
        { "properties":
          { "type": { "enum": [ "residential", "business" ] } },
          "required": ["type"]
        }
      ]
    } 

  }
}
Run Code Online (Sandbox Code Playgroud)

这是有效的实例:

{
      "shipping_address": {
        "street_address": "1600 Pennsylvania Avenue NW",
        "city": "Washington",
        "state": "DC",
        "type": "business"
      }
}
Run Code Online (Sandbox Code Playgroud)

我需要确保任何其他字段shipping_address无效.我知道为此目的存在additionalProperties应该设置为"假".但是,当我"additionalProprties":false按以下方式设置时:

"shipping_address": {
          "allOf": [
            { "$ref": "#/definitions/address" },
            { "properties":
              { "type": { "enum": [ "residential", "business" ] } },
              "required": ["type"]
            }
          ],
          "additionalProperties":false
        } 
Run Code Online (Sandbox Code Playgroud)

我收到验证错误(在此处检查):

[ {
  "level" : "error",
  "schema" : {
    "loadingURI" : "#",
    "pointer" : "/properties/shipping_address"
  },
  "instance" : {
    "pointer" : "/shipping_address"
  },
  "domain" : "validation",
  "keyword" : "additionalProperties",
  "message" : "additional properties are not allowed",
  "unwanted" : [ "city", "state", "street_address", "type" ]
} ] 
Run Code Online (Sandbox Code Playgroud)

问题是:我该如何限制shipping_address零件的字段?提前致谢.

fge*_*fge 73

[v4验证规范草案的作者]

您偶然发现了JSON Schema中最常见的问题,即它根本无法像用户期望的那样进行继承; 但与此同时,它是其核心功能之一.

当你这样做时:

"allOf": [ { "schema1": "here" }, { "schema2": "here" } ]
Run Code Online (Sandbox Code Playgroud)

schema1schema2没有彼此的知识; 它们在自己的背景下进行评估.

在您的场景中,许多人遇到过,您期望定义的属性schema1将被知道schema2; 但情况并非如此,永远不会.

这个问题就是我为草案v5提出这两个建议的原因:

您的架构shipping_address将是:

{
    "merge": {
        "source": { "$ref": "#/definitions/address" },
        "with": {
            "properties": {
                "type": { "enum": [ "residential", "business" ] }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

随着定义strictProperties,以trueaddress.


顺便说一句,我也是您所指的网站的作者.

现在,让我回顾起草v3.草案v3确实定义了extends,它的值是模式或模式数组.通过此关键字的定义,它意味着实例必须对当前模式指定的所有模式有效extends; 基本上,草案v4 allOf是草案v3的extends.

考虑一下(草案v3):

{
    "extends": { "type": "null" },
    "type": "string"
}
Run Code Online (Sandbox Code Playgroud)

而现在,那:

{
    "allOf": [ { "type": "string" }, { "type": "null" } ]
}
Run Code Online (Sandbox Code Playgroud)

他们是一样的.或许那个?

{
    "anyOf": [ { "type": "string" }, { "type": "null" } ]
}
Run Code Online (Sandbox Code Playgroud)

或者那个?

{
    "oneOf": [ { "type": "string" }, { "type": "null" } ]
}
Run Code Online (Sandbox Code Playgroud)

总而言之,这意味着extends在草案v3中从未真正做过人们期望它做的事情.对于草案v4,*Of明确定义了关键字.

但到目前为止,您遇到的问题是最常遇到的问题.因此,我的建议将一劳永逸地解决这一误解的根源!

  • 目前在v7,我没有看到任何`merge`或`strictProperties`.现在可以做OP正在谈论的事情吗? (18认同)
  • 从 2019-09 开始,“unevaluatedProperties”可以设置为 false。这样终于可以解决这里的问题了。 (8认同)
  • 这两个属性不是任何规范的一部分 - 它们是@fge*提议*的特性,因此无法保证它们将在任何未来的版本中. (3认同)
  • @fge-在您的回答中似乎并不明显,这些关键字不是规范的一部分,而是您建议的扩展名。呈现它们的方式使它们看起来像是官方解决方案,而没有任何警告说v5不断变化,我认为这是误导性的。 (2认同)
  • @JulianHonma,2019 年 1 月,“strictProperties”和“merge”不是规范草案 v7 的一部分。 (2认同)
  • 它们现在处于版本 [2019-09](https://json-schema.org/draft/2019-09/release-notes.html),并且在该领域仍然没有改进的迹象。 (2认同)

clo*_*eet 8

additionalProperties适用于未由立即架构propertiespatternProperties立即架构中计算的所有属性.

这意味着当你有:

    {
      "allOf": [
        { "$ref": "#/definitions/address" },
        { "properties":
          { "type": { "enum": [ "residential", "business" ] } },
          "required": ["type"]
        }
      ],
      "additionalProperties":false
    }
Run Code Online (Sandbox Code Playgroud)

additionalProperties这里适用于所有属性,因为没有兄弟级别的properties条目 - 里面的条目allOf不计算.

您可以做的一件事是将properties定义向上移动一级,并为要导入的属性提供存根条目:

    {
      "allOf": [{"$ref": "#/definitions/address"}],
      "properties": {
        "type": {"enum": ["residential", "business"]},
        "addressProp1": {},
        "addressProp2": {},
        ...
      },
      "required": ["type"],
      "additionalProperties":false
    }
Run Code Online (Sandbox Code Playgroud)

这意味着它additionalProperties不适用于您想要的属性.


Ted*_*ein 5

这是Yves-M解决方案的略微简化版本:

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "definitions": {
    "address": {
      "type": "object",
      "properties": {
        "street_address": {
          "type": "string"
        },
        "city": {
          "type": "string"
        },
        "state": {
          "type": "string"
        }
      },
      "required": [
        "street_address",
        "city",
        "state"
      ]
    }
  },
  "type": "object",
  "properties": {
    "billing_address": {
      "$ref": "#/definitions/address"
    },
    "shipping_address": {
      "allOf": [
        {
          "$ref": "#/definitions/address"
        }
      ],
      "properties": {
        "type": {
          "enum": [
            "residential",
            "business"
          ]
        },
        "street_address": {},
        "city": {},
        "state": {}
      },
      "required": [
        "type"
      ],
      "additionalProperties": false
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这样可以保留基本address模式中所需属性的验证,只需添加所需的type属性即可shipping_address.

不幸的是,additionalProperties只考虑了直接的兄弟级属性.也许这是有原因的.但这就是为什么我们需要重复继承的属性.

在这里,我们使用空对象语法以简化形式重复继承的属性.这意味着具有这些名称的属性无论它们包含什么类型的值都是有效的.但是我们可以依赖allOf关键字来强制执行基础address模式中声明的类型约束(以及任何其他约束).


myo*_*yol 5

由于没有人发布2019-09及以上规范的有效答案,我几乎错过了 Andreas H. 的评论;

{
  "$schema": "http://json-schema.org/2019-09/schema#",

  "definitions": {
    "address": {
      "type": "object",
      "properties": {
        "street_address": { "type": "string" },
        "city":           { "type": "string" },
        "state":          { "type": "string" }
      },
      "required": ["street_address", "city", "state"]
      // additionalProperties: false    // <-- Remove completely if present 
    }
  },

  "type": "object",

  "properties": {
    "billing_address": { "$ref": "#/definitions/address" },
    "shipping_address": {
      "unevaluatedProperties": false,   // <-- Add to same level as allOf as false
      "allOf": [
        { "$ref": "#/definitions/address" },
        { "properties":
          { "type": { "enum": [ "residential", "business" ] } },
          "required": ["type"]
        }
      ]
    } 
  }
}
Run Code Online (Sandbox Code Playgroud)

作者在这里可以找到一个非常清晰和简洁的解释;