前言:我优化和改进了下面的解决方案,并将其作为库发布在这里: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配置的深度超过一层,则尝试失败,因为这个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 maps 从 yaml 切换到 JSON 格式,你将失去项目的顺序,因为 Go map 中的元素(键值对)没有序列。这可能会或可能不会是一个问题。
body
的变量,可以使用以下代码:body := make(map[string]interface{})
。 - Yandry Pozo