问题
I'm trying to unmarshal this file:
{
"@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"
}
}
into this struct:
type Dependency struct {
Name string
URL string
Version string
License string
}
using these instructions:
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)
}
The problem with this is that in "json-schema@0.2.3" we have an array of licenses instead of a string, and due to that I obviously get
json: cannot unmarshal array into Go value of type string
Is there a way to automatically deal with the field license
which can be an array or a string?
Thanks
回答1:
Unfortunately, there is no real automatic solution for this provided by the json
package.
But you can unmarshal the dependencies to a map[string]*json.RawMessage
instead of map[string]string
. json.RawMessage
is just a []byte
, so you can decide on the type of the message based on the first byte.
Example:
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"]),
})
}
Another solution would be to use 2 structs. One contains the dependencies as string, the other as array. You can then try to call json.Unmarshal
on both of them.
Example:
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
}
}
来源:https://stackoverflow.com/questions/56377551/how-to-unmarshal-a-field-that-can-be-an-array-or-a-string-in-go