如何为引用JSON Schema定义的属性添加自定义配置?
JSON Schema引用扩展问题解决方案
为什么你的写法无效
当使用$ref时,JSON Schema会完全采用引用目标的内容,当前对象中与$ref同级的所有属性(比如required、title)都会被忽略,所以你添加的required: ['path']不会生效。
解决方案
根据你的场景(大量引用+多种变体),推荐以下几种方案:
方案1:用allOf组合引用与扩展规则
将$ref放入allOf数组,同时在同级添加差异化配置,两个规则会合并生效:
const schema = { $schema: "https://json-schema.org/draft/2020-12/schema", type: 'object', properties: { title:{ title:"Item title", allOf: [ { $ref:"#/$defs/selector" }, { required: ['path'] } ] }, image:{ title:"Item image", $ref:"#/$defs/selector" } }, $defs:{ // 2020-12版本推荐用$defs替代旧的definitions selector:{ type:"object", description:"Selectors used to extract datas.", properties:{ path:{ type:"string", title:"Selector path" }, attr:{ type:"string", title:"HTML attribute", examples:["src"] }, regex:{ type:"string", title:"Regex pattern", format:"regex" } } } } }
方案2:预定义常用变体
如果存在多种重复的变体(比如必填path、必填attr等),可以在$defs中提前定义这些变体,后续直接引用即可,减少重复代码:
const schema = { $schema: "https://json-schema.org/draft/2020-12/schema", type: 'object', properties: { title:{ title:"Item title", $ref:"#/$defs/selector-with-required-path" }, image:{ title:"Item image", $ref:"#/$defs/selector" }, content:{ title:"Content selector", $ref:"#/$defs/selector-with-required-attr" } }, $defs:{ selector:{ type:"object", description:"Selectors used to extract datas.", properties:{ path:{ type:"string", title:"Selector path" }, attr:{ type:"string", title:"HTML attribute", examples:["src"] }, regex:{ type:"string", title:"Regex pattern", format:"regex" } } }, selector-with-required-path:{ allOf: [ { $ref:"#/$defs/selector" }, { required: ['path'] } ] }, selector-with-required-attr:{ allOf: [ { $ref:"#/$defs/selector" }, { required: ['attr'] } ] } } }
方案3:用动态引用$dynamicRef(2020-12+版本)
如果需要更灵活的动态扩展,JSON Schema 2020-12引入的$dynamicRef和$dynamicAnchor允许直接在引用节点添加属性,无需allOf,会自动合并规则:
const schema = { $schema: "https://json-schema.org/draft/2020-12/schema", type: 'object', properties: { title:{ title:"Item title", $dynamicRef:"#/$defs/selector", required: ['path'] }, image:{ title:"Item image", $dynamicRef:"#/$defs/selector" }, excerpt:{ title:"Excerpt selector", $dynamicRef:"#/$defs/selector", properties: { regex: { type: "string", minLength: 5 } } } }, $defs:{ selector:{ $dynamicAnchor: "selector", // 标记动态锚点 type:"object", description:"Selectors used to extract datas.", properties:{ path:{ type:"string", title:"Selector path" }, attr:{ type:"string", title:"HTML attribute", examples:["src"] }, regex:{ type:"string", title:"Regex pattern", format:"regex" } } } } }
总结
- 直接在
$ref同级加属性无效,因为$ref会完全替换当前节点内容 - 少量差异化用
allOf组合;固定变体多就预定义;需要高度灵活的动态扩展用$dynamicRef(注意版本兼容)
内容的提问来源于stack exchange,提问作者gordie
相关产品推荐
相关产品推荐

