JSON Schema中基于日期动态设置maxItems的问题排查与修正
问题原因
JSON Schema Draft-07不支持基于实例数据动态计算验证参数——你无法从period.label的yyyy_mm格式值中解析出年月、计算天数后再设置days.maxItems。你之前的写法要么错误尝试了非标准的动态引用(比如Draft-07未纳入规范的$data关键字,多数验证工具不支持),要么条件判断逻辑失效,导致所有数据都能通过验证。
修正方案
根据需求,有两种可行方案:
方案1:升级到JSON Schema Draft 2020-12(推荐)
Draft 2020-12支持更灵活的条件判断,结合正则匹配年月模式,可实现精准的动态验证。以下是完整Schema:
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "period": { "type": "object", "properties": { "label": { "type": "string", "pattern": "^\\d{4}_\\d{2}$" } }, "required": ["label"] }, "days": { "type": "array" } }, "required": ["period", "days"], "allOf": [ // 匹配闰年2月(29天):能被400整除,或能被4整除但不能被100整除的年份 { "if": { "properties": { "period": { "properties": { "label": { "pattern": "^((\\d{2}(0[48]|[2468][048]|[13579][26])|(0[48]|[2468][048]|[13579][26])00)_02)$" } } } } }, "then": { "properties": { "days": { "maxItems": 29 } } } }, // 匹配非闰年2月(28天) { "if": { "properties": { "period": { "properties": { "label": { "pattern": "^((\\d{2}(0[1235679]|[13579][13579]|[2468][026])|(0[13579]|[13579][13579]|[2468][026])00)_02)$" } } } } }, "then": { "properties": { "days": { "maxItems": 28 } } } }, // 匹配31天的月份:1、3、5、7、8、10、12月 { "if": { "properties": { "period": { "properties": { "label": { "pattern": "^\\d{4}_(0[13578]|1[02])$" } } } } }, "then": { "properties": { "days": { "maxItems": 31 } } } }, // 匹配30天的月份:4、6、9、11月 { "if": { "properties": { "period": { "properties": { "label": { "pattern": "^\\d{4}_(0[469]|11)$" } } } } }, "then": { "properties": { "days": { "maxItems": 30 } } } } ] }
这个Schema通过allOf组合4组if/then规则,用正则匹配不同年月模式,对应设置days数组的最大长度。测试时,2024_02(闰年2月)的days数组超过29个元素就会验证失败,符合预期。
方案2:继续使用Draft-07(枚举所有可能规则)
Draft-07支持if/then/allOf,但无法动态计算,只能枚举所有年月的匹配规则。写法和上面的Schema基本一致,只需将$schema字段改为Draft-07的地址:
"$schema": "http://json-schema.org/draft-07/schema#"
注意:如果年月范围很大,枚举规则会非常冗长,因此优先推荐方案1。
内容的提问来源于stack exchange,提问作者tok
相关产品推荐
相关产品推荐

