前言:我对以下解决方案进行了优化和改进,并在此处将其作为库发布:github.com/icza/dyno。以下convert() 函数可作为dyno.ConvertMapI2MapS() 使用。
问题在于,如果您使用最通用的interface{} 类型来解组,则github.com/go-yaml/yaml 包用于解组键值对的默认类型将是map[interface{}]interface{}。
第一个想法是使用map[string]interface{}:
var body map[string]interface{}
但如果 yaml 配置的深度大于 1,则此尝试会失败,因为此 body 映射将包含其他类型将再次为 map[interface{}]interface{} 的映射。
问题是深度未知,可能还有地图以外的其他值,所以使用map[string]map[string]interface{}不好。
一种可行的方法是让yaml 解组为interface{} 类型的值,并递归地处理结果,并将遇到的每个map[interface{}]interface{} 转换为map[string]interface{} 值。地图和切片都必须处理。
下面是这个转换器函数的一个例子:
func convert(i interface{}) interface{} {
switch x := i.(type) {
case map[interface{}]interface{}:
m2 := map[string]interface{}{}
for k, v := range x {
m2[k.(string)] = convert(v)
}
return m2
case []interface{}:
for i, v := range x {
x[i] = convert(v)
}
}
return i
}
并使用它:
func main() {
fmt.Printf("Input: %s\n", s)
var body interface{}
if err := yaml.Unmarshal([]byte(s), &body); err != nil {
panic(err)
}
body = convert(body)
if b, err := json.Marshal(body); err != nil {
panic(err)
} else {
fmt.Printf("Output: %s\n", b)
}
}
const s = `Services:
- Orders:
- ID: $save ID1
SupplierOrderCode: $SupplierOrderCode
- ID: $save ID2
SupplierOrderCode: 111111
`
输出:
Input: Services:
- Orders:
- ID: $save ID1
SupplierOrderCode: $SupplierOrderCode
- ID: $save ID2
SupplierOrderCode: 111111
Output: {"Services":[{"Orders":[
{"ID":"$save ID1","SupplierOrderCode":"$SupplierOrderCode"},
{"ID":"$save ID2","SupplierOrderCode":111111}]}]}
需要注意的一点:通过 Go 映射从 yaml 切换到 JSON,您将失去项目的顺序,因为 Go 映射中的元素(键值对)没有排序。这可能是也可能不是问题。