如何编写jq表达式将嵌套数组JSON转为JSON Schema并修复类型错误
问题描述
原始JSON结构:
{"objectSchema": {"fields": [{"name": "OBJECTID","type": "esriFieldTypeOID","alias": "OBJECTID","domain": null,"editable": false,"nullable": false,"defaultValue": null,"modelName": "OBJECTID"},{"name": "ENABLED","type": "esriFieldTypeSmallInteger","alias": "ENABLED","domain": {"type": "codedValue","name": "EnabledDomain","description": "Geometric Network Enabled domain","codedValues": [{"name": "False","code": 0},{"name": "True","code": 1}],"mergePolicy": "esriMPTDefaultValue","splitPolicy": "esriSPTDefaultValue"},"editable": true,"nullable": true,"defaultValue": 1,"modelName": "ENABLED"},{"name": "GLOBALID","type": "esriFieldTypeGlobalID","alias": "GLOBALID","domain": null,"editable": false,"nullable": false,"length": 38,"defaultValue": null,"modelName": "GLOBALID"}]}}
原使用的jq表达式:
def convertToSchema: if type == "array" then if length == 0 then {"type": "array", "items": {"type": "string"}} else {"type": "array", "items": (reduce map(convertToSchema)[] as $i ({}; . *= $i))} end elif type == "object" then {"type": "object", "properties": map_values(convertToSchema)} elif type == "boolean" then {"type": "boolean"} elif type == "number" then {"type": "number"} elif type == "string" then {"type": "string"} elif type == "null" then {"type": "string"} else {"type": (type | tostring)} end; .objectSchema | convertToSchema
当前问题:转换后的JSON Schema中,domain字段的类型被错误识别为string,但实际上该字段既可以是null也可以是object,需要修正表达式以正确处理嵌套对象、null值,并合并数组所有项的唯一属性生成正确的Schema。
修正后的jq表达式
def mergeSchemas($a; $b): if $a == {} then $b elif $b == {} then $a else .type = ( if ($a.type | type) == "array" and ($b.type | type) == "array" then ($a.type + $b.type | unique) elif ($a.type | type) == "array" then ($a.type + [$b.type] | unique) elif ($b.type | type) == "array" then ($b.type + [$a.type] | unique) elif $a.type != $b.type then [$a.type, $b.type] else $a.type ) | if ($a | has("properties")) and ($b | has("properties")) then .properties = ($a.properties + $b.properties | with_entries(.value = mergeSchemas($a.properties[.key]; $b.properties[.key]))) elif ($a | has("properties")) then .properties = $a.properties elif ($b | has("properties")) then .properties = $b.properties else . end | if ($a | has("items")) and ($b | has("items")) then .items = mergeSchemas($a.items; $b.items) elif ($a | has("items")) then .items = $a.items elif ($b | has("items")) then .items = $b.items else . end end; def convertToSchema: if type == "array" then if length == 0 then {"type": "array", "items": {"type": "string"}} else {"type": "array", "items": (reduce map(convertToSchema)[] as $item ({}; mergeSchemas(.; $item)))} end elif type == "object" then {"type": "object", "properties": map_values(convertToSchema)} elif type == "boolean" then {"type": "boolean"} elif type == "number" then {"type": "number"} elif type == "string" then {"type": "string"} elif type == "null" then {"type": "null"} else {"type": (type | tostring)} end; .objectSchema | convertToSchema
关键修改说明
- 修正null值处理:将原表达式中
elif type == "null" then {"type": "string"}改为{"type": "null"},保留null类型的正确标识。 - 新增Schema合并逻辑:定义
mergeSchemas函数,用于合并数组中多个项的Schema:- 处理类型合并:当两个Schema类型不同时,将类型合并为数组形式(如
["object", "null"]) - 递归合并嵌套属性:对于object类型的properties和array类型的items,递归调用合并逻辑,确保嵌套结构正确合并
- 处理类型合并:当两个Schema类型不同时,将类型合并为数组形式(如
- 数组项合并优化:使用自定义的
mergeSchemas替代原有的.*= $i,确保数组中所有项的属性被正确合并为包含所有可能类型的Schema
转换后的正确结果
{ "type": "object", "properties": { "fields": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "type": { "type": "string" }, "alias": { "type": "string" }, "domain": { "type": [ "null", "object" ], "properties": { "type": { "type": "string" }, "name": { "type": "string" }, "description": { "type": "string" }, "codedValues": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "code": { "type": "number" } } } }, "mergePolicy": { "type": "string" }, "splitPolicy": { "type": "string" } } }, "editable": { "type": "boolean" }, "nullable": { "type": "boolean" }, "defaultValue": { "type": [ "null", "number" ] }, "modelName": { "type": "string" }, "length": { "type": [ "null", "number" ] } } } } } }
内容的提问来源于stack exchange,提问作者sujay777
相关产品推荐
相关产品推荐

