JSON Schema时区选择验证需求:单时区选择需判定为合法
问题描述
我需要一个用于输入字段验证的JSON Schema,实现时区选择功能,所有可选时区都要存在Schema里。现在遇到的问题是:当某个大洲(比如Africa)下有多个时区时,只选该大洲下的单个时区会被判定无效,但下面这段JSON应该是有效的:
{ "continents": [ { "continent": "Africa", "timezones": [ { "timezone": "Africa/Abidjan", "utc_offset": "+00:00", "dst_offset": "+00:00" } ] } ] }
而当大洲下只有一个时区(比如UTC)时,当前Schema能正确判定有效性。以下是我目前用的简化版Schema:
{ "$schema": "http://json-schema.org/draft-07/schema#", "title": "Continents Timezones", "type": "object", "properties": { "continents": { "type": "array", "items": { "type": "object", "properties": { "continent": { "type": "string" }, "timezones": { "type": "array", "items": { "type": "object", "properties": { "timezone": { "type": "string" }, "utc_offset": { "type": "string" }, "dst_offset": { "type": "string" } }, "required": [ "timezone", "utc_offset", "dst_offset" ] } } }, "required": [ "continent", "timezones" ], "enum": [ { "continent": "Africa", "timezones": [ { "timezone": "Africa/Abidjan", "utc_offset": "+00:00", "dst_offset": "+00:00" }, { "timezone": "Africa/Accra", "utc_offset": "+00:00", "dst_offset": "+00:00" }, { "timezone": "Africa/Addis_Ababa", "utc_offset": "+03:00", "dst_offset": "+03:00" }, { "timezone": "Africa/Algiers", "utc_offset": "+01:00", "dst_offset": "+01:00" }, { "timezone": "Africa/Asmara", "utc_offset": "+03:00", "dst_offset": "+03:00" }, { "timezone": "Africa/Bamako", "utc_offset": "+00:00", "dst_offset": "+00:00" } ] }, { "continent": "UTC", "timezones": [ { "timezone": "UTC", "utc_offset": "+00:00", "dst_offset": "+00:00" } ] } ] } } }, "required": [ "continents" ] }
问题原因
当前Schema用enum限定每个大洲对象的完整结构,这意味着输入的大洲对象必须和enum里的某一项完全匹配。对于Africa来说,enum里的项包含了所有6个时区的数组,所以当输入只包含单个时区时,整个对象和enum项不匹配,导致验证失败。而UTC的enum项只有一个时区,输入和它完全匹配时就能通过验证。
解决方案
要实现“选择某大洲下任意数量(至少1个)的合法时区”的需求,需要把enum替换为oneOf,针对每个大洲单独定义规则:
- 指定
continent字段的固定值(比如"Africa"或"UTC") - 限定
timezones数组里的每个时区必须是该大洲允许的选项之一 - 确保
timezones数组至少有一个元素
修正后的JSON Schema
{ "$schema": "http://json-schema.org/draft-07/schema#", "title": "Continents Timezones", "type": "object", "properties": { "continents": { "type": "array", "items": { "type": "object", "required": ["continent", "timezones"], "oneOf": [ { "properties": { "continent": { "const": "Africa" }, "timezones": { "type": "array", "minItems": 1, "items": { "type": "object", "required": ["timezone", "utc_offset", "dst_offset"], "properties": { "timezone": { "enum": [ "Africa/Abidjan", "Africa/Accra", "Africa/Addis_Ababa", "Africa/Algiers", "Africa/Asmara", "Africa/Bamako" ] }, "utc_offset": { "type": "string" }, "dst_offset": { "type": "string" } }, "additionalProperties": false } } }, "additionalProperties": false }, { "properties": { "continent": { "const": "UTC" }, "timezones": { "type": "array", "minItems": 1, "items": { "type": "object", "required": ["timezone", "utc_offset", "dst_offset"], "properties": { "timezone": { "const": "UTC" }, "utc_offset": { "const": "+00:00" }, "dst_offset": { "const": "+00:00" } }, "additionalProperties": false } } }, "additionalProperties": false } ] } } }, "required": ["continents"] }
额外优化(可选)
如果需要确保时区和对应的UTC/DST偏移量完全匹配,避免用户输入错误的偏移值,可以为每个时区单独定义oneOf规则,确保时区和偏移量一一对应:
// 替换Africa的timezones.items部分 "items": { "type": "object", "required": ["timezone", "utc_offset", "dst_offset"], "oneOf": [ { "properties": { "timezone": {"const": "Africa/Abidjan"}, "utc_offset": {"const": "+00:00"}, "dst_offset": {"const": "+00:00"} }, "additionalProperties": false }, { "properties": { "timezone": {"const": "Africa/Accra"}, "utc_offset": {"const": "+00:00"}, "dst_offset": {"const": "+00:00"} }, "additionalProperties": false }, // 其他Africa时区依次类推 ] }
内容的提问来源于stack exchange,提问作者klausk
相关产品推荐
相关产品推荐

