Как демонтировать поле, которое может быть массивом или строкой в ​​Go? - PullRequest
0 голосов
/ 30 мая 2019

Я пытаюсь распаковать этот файл:

{
  "@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 Ответ

2 голосов
/ 30 мая 2019

К сожалению, для этого не существует реального автоматического решения, предоставляемого пакетом 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
    }
}
...