如何在Go中解组可以是数组或字符串的字段?

时间:2019-05-30 11:35:42

标签: json go unmarshalling

我正试图解组该文件:

{
  "@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的方法,该字段可以是数组或字符串?

谢谢

1 个答案:

答案 0 :(得分:2)

不幸的是,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
    }
}