JSON Schema:能否将displayName默认值设为父级键及引用enum到required?
JSON Schema 核心问题求解
一、动态默认值:将displayName默认值设为父对象属性键
我有一个包含$defs的JSON Schema,用于验证类似"machines":{"FA23":{...}}的结构。$defs内定义了machine对象,其中displayName属性希望默认值自动匹配对应的机器键(如FA23),且我不想通过程序化方式生成Schema。
需求背景
- 避免单独维护存储默认值的额外结构,希望验证通过后直接解析Schema填充缺失的默认值
- 解析函数需具备通用性,可跨项目复用,因此默认值必须是确切值,或无需特定Schema逻辑的安全获取方式
- 当前使用draft-07版本,但不绑定特定版本;运行环境为Node.js v14(Node-RED),尽量避免使用额外模块或代码生成Schema
- 采用对象属性列表而非数组,因为这是运行时实际使用的结构,可直接写入文件无需转换
当前Schema子集
{ "$schema":"http://json-schema.org/draft-07/schema#", "title":"commonConfigSchema", "description":"global common config for this project", "$defs":{ "javascriptFalsy":{ "enum":[false, 0, null, ""] }, "macKey":{ "type":"string", "enum":["FA419","FA420","FA421","FA422","FA423","MO41","MO42","OMET"] }, "signalKey":{ "type":"string", "enum":["noop","A1","A2","A3","A4","B","C1","C2","D","E"], "default":"noop" }, "towerDevice":{ "type":"string", "enum":["redLight","greenLight","horn"] }, "machine":{ "type":"object", "properties":{ "displayName":{"type":"string", "default":"this.parent.key"}, "cellHeaderText":{"type":"string", "default":"Linea + this.displayName"}, "toA3Timeout":{"type":"integer", "minimum":0, "default":20000}, "toA4Timeout":{"type":"integer", "minimum":0, "default":"120*60*1000"}, "initCellSignalKey":{"$ref":"#/$defs/signalKey", "default":"noop"}, "initTowerBits":{ "type":"object", "propertyNames":{"$ref":"#/$defs/towerDevice"}, "patternProperties":{".":{"enum":[0, 1, true, false], "default":0}} } }, "$comment":"exactly all the props are required", "additionalProperties":false, "required":["displayName", "cellHeaderText", "toA3Timeout", "toA4Timeout", "initCellSignalKey", "initTowerBits"] } }, "type":"object", "properties":{ "machines":{ "$description": "holding machine-specific configs. Made up of macKey:config pairs", "type":"object", "propertyNames":{"$ref":"#/$defs/macKey"}, "patternProperties":{".":{"$ref":"#/$defs/machine"} }, //"required":{"$ref":"#/$defs/macKey/enum"}, "required":["FA419","FA420","FA421","FA422","FA423","MO41","MO42","OMET"], "additionalProperties":false } }, "required":["cellsLayout", "machines"], "additionalProperties":false }
我尝试在displayName的default字段中写入"this.parent.key",但这并非标准JSON Schema支持的语法,想了解有没有标准方式实现该需求?
二、能否引用enum数组作为required属性值
我尝试将machines的required数组绑定到macKey的enum定义,避免重复维护两份相同的键列表,但之前了解到$ref指向的是Schema而非字符串数组,旧回答称此方式不可行,想知道现在(包括后续draft版本)是否有变化?
问题解答
关于动态默认值
JSON Schema的default关键字仅支持静态值,不支持引用父对象属性键这类动态逻辑。可通过以下方式满足需求:
- 自定义通用解析逻辑:验证完成后,遍历
machines对象的键值对,若displayName缺失,直接将当前键赋值给它。可给displayName添加$comment标记(如"$comment": "default-to-parent-key"),让解析函数识别并处理,这种方式无需修改Schema核心结构,且解析逻辑可跨项目复用。 - 即使升级到draft-2020-12版本,仍无法直接实现动态默认值,核心的动态赋值逻辑仍需在解析层处理。
- 不要在
default中写入表达式,这不属于标准语法,没有通用解析器会识别。
关于引用enum作为required数组
截至目前(包括最新的draft-2020-12),JSON Schema仍然不支持直接引用另一个Schema的enum数组作为required的值。$ref只能指向完整的Schema节点,无法提取其中的enum数组内容。
避免冗余的可行方式:
- 程序化生成Schema:编写简单脚本,从
macKey的enum数组中提取值生成machines的required数组,后续仅需维护macKey的enum即可,一次性生成后无需重复执行。 - 使用JSON Schema预处理器:如自定义扩展
json-schema-ref-parser这类工具实现引用逻辑,但需要引入额外模块,可能不符合你的环境要求。
内容的提问来源于stack exchange,提问作者Andrea Bardelli
相关产品推荐
相关产品推荐

