如何在 Go 中解组可以是数组或字符串的字段?
How to unmarshal a field that can be an array or a string in Go?
我正在尝试解组此文件:
{
"@babel/code-frame@7.0.0": {
"licenses": "MIT",
"repository": "https://github.com/babel/babel/tree/master/packages/babel-code-frame",
"publisher": "Sebastian McKenzie",
"email": "sebmck@gmail.com",
"path": "/Users/lislab/workspace/falcon-enrolment/frontend-customer/node_modules/@babel/code-frame",
"licenseFile": "/Users/lislab/workspace/falcon-enrolment/frontend-customer/node_modules/@babel/code-frame/LICENSE"
},
"json-schema@0.2.3": {
"licenses": [
"AFLv2.1",
"BSD"
],
"repository": "https://github.com/kriszyp/json-schema",
"publisher": "Kris Zyp",
"path": "/Users/lislab/workspace/falcon-enrolment/frontend-customer/node_modules/json-schema",
"licenseFile": "/Users/lislab/workspace/falcon-enrolment/frontend-customer/node_modules/json-schema/README.md"
}
}
进入这个结构:
type Dependency struct {
Name string
URL string
Version string
License string
}
使用这些说明:
dependencies := map[string]*json.RawMessage{}
err = json.Unmarshal(file, &dependencies)
// boilerplate
for key, value := range dependencies {
depVal := map[string]string{}
err = json.Unmarshal(*value, &depVal)
// boilerplate
result = append(result, depVal)
}
这个问题是在 "json-schema@0.2.3" 中我们有一个许可证数组而不是一个字符串,因此我显然得到
json: cannot unmarshal array into Go value of type string
有没有办法自动处理license
可以是数组也可以是字符串的字段?
谢谢
不幸的是,json
包没有为此提供真正的自动解决方案。
但是您可以将依赖项解组为 map[string]*json.RawMessage
而不是 map[string]string
。 json.RawMessage
只是一个[]byte
,所以你可以根据第一个字节来决定消息的类型。
示例:
for _, value := range dependencies {
depVal := map[string]*json.RawMessage{}
_ = json.Unmarshal(*value, &depVal)
// check if the first character of the RawMessage is a bracket
if rune([]byte(*depVal["licenses"])[0]) == '[' {
var licenses []string
json.Unmarshal(*depVal["licenses"], &licenses)
fmt.Println(licenses)
// do something with the array
}
result = append(result, Dependency{
URL: string(*depVal["repository"]),
License: string(*depVal["licenses"]),
})
}
另一种解决方案是使用 2 个结构。一个包含字符串形式的依赖项,另一个包含数组形式的依赖项。然后,您可以尝试对它们都调用 json.Unmarshal
。
示例:
type Dependency struct {
Licenses string
// other fields
}
type DependencyWithArr struct {
Licenses []string
// other fields
}
// in your function
for _, value := range dependencies {
type1 := Dependency{}
type2 := DependencyWithArr{}
err = json.Unmarshal(*value, &type1)
if err != nil {
err = json.Unmarshal(*value, &type2)
// use the array type
} else {
// use the single string type
}
}
我正在尝试解组此文件:
{
"@babel/code-frame@7.0.0": {
"licenses": "MIT",
"repository": "https://github.com/babel/babel/tree/master/packages/babel-code-frame",
"publisher": "Sebastian McKenzie",
"email": "sebmck@gmail.com",
"path": "/Users/lislab/workspace/falcon-enrolment/frontend-customer/node_modules/@babel/code-frame",
"licenseFile": "/Users/lislab/workspace/falcon-enrolment/frontend-customer/node_modules/@babel/code-frame/LICENSE"
},
"json-schema@0.2.3": {
"licenses": [
"AFLv2.1",
"BSD"
],
"repository": "https://github.com/kriszyp/json-schema",
"publisher": "Kris Zyp",
"path": "/Users/lislab/workspace/falcon-enrolment/frontend-customer/node_modules/json-schema",
"licenseFile": "/Users/lislab/workspace/falcon-enrolment/frontend-customer/node_modules/json-schema/README.md"
}
}
进入这个结构:
type Dependency struct {
Name string
URL string
Version string
License string
}
使用这些说明:
dependencies := map[string]*json.RawMessage{}
err = json.Unmarshal(file, &dependencies)
// boilerplate
for key, value := range dependencies {
depVal := map[string]string{}
err = json.Unmarshal(*value, &depVal)
// boilerplate
result = append(result, depVal)
}
这个问题是在 "json-schema@0.2.3" 中我们有一个许可证数组而不是一个字符串,因此我显然得到
json: cannot unmarshal array into Go value of type string
有没有办法自动处理license
可以是数组也可以是字符串的字段?
谢谢
不幸的是,json
包没有为此提供真正的自动解决方案。
但是您可以将依赖项解组为 map[string]*json.RawMessage
而不是 map[string]string
。 json.RawMessage
只是一个[]byte
,所以你可以根据第一个字节来决定消息的类型。
示例:
for _, value := range dependencies {
depVal := map[string]*json.RawMessage{}
_ = json.Unmarshal(*value, &depVal)
// check if the first character of the RawMessage is a bracket
if rune([]byte(*depVal["licenses"])[0]) == '[' {
var licenses []string
json.Unmarshal(*depVal["licenses"], &licenses)
fmt.Println(licenses)
// do something with the array
}
result = append(result, Dependency{
URL: string(*depVal["repository"]),
License: string(*depVal["licenses"]),
})
}
另一种解决方案是使用 2 个结构。一个包含字符串形式的依赖项,另一个包含数组形式的依赖项。然后,您可以尝试对它们都调用 json.Unmarshal
。
示例:
type Dependency struct {
Licenses string
// other fields
}
type DependencyWithArr struct {
Licenses []string
// other fields
}
// in your function
for _, value := range dependencies {
type1 := Dependency{}
type2 := DependencyWithArr{}
err = json.Unmarshal(*value, &type1)
if err != nil {
err = json.Unmarshal(*value, &type2)
// use the array type
} else {
// use the single string type
}
}