2019-05-30 11:35 阅读 59


I'm trying to unmarshal this file:

  "@babel/code-frame@7.0.0": {
    "licenses": "MIT",
    "repository": "",
    "publisher": "Sebastian McKenzie",
    "email": "",
    "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": [
    "repository": "",
    "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/"

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?


  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

1条回答 默认 最新

  • 已采纳
    duanhuai7532 duanhuai7532 2019-05-30 11:54

    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.


    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)
            // 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
    点赞 评论 复制链接分享