Как разобрать массивы переменной глубины в структуру из JSON - PullRequest
0 голосов
/ 15 мая 2019

Я анализирую JSON из API в структуру. Мой код, представляющий структуру, не работает, и я заметил, что это потому, что API возвращает массивы переменной глубины (например, иногда [] float64, иногда [] [] float64). Я не знаю, как спроектировать структуру, чтобы справиться с этим.

Я попытался возиться с моим определением структуры, поменяв местами сбойный тип между [] float64, [] [] float64 и [] interface {}.

Мой код для моего определения структуры:

...
Geometries []struct {
    Type        string    `json:"type"`
    Coordinates []float64 `json:"coordinates"`
} `json:"geometries"`
...

Ниже приведен пример вывода из API:

...
"geometries": [{"type": "Point", "coordinates": [-81.7046006, 41.4955689]}, {"type": "Polygon", "coordinates": [[[-81.7176885, 41.507513], [-81.7205424, 41.4857622], [-81.6915158, 41.4836231], [-81.6886557, 41.5053737], [-81.7176885, 41.507513]]]}]
...

Я ожидаю, что JSON проанализирует структуру. Вместо этого я вижу следующую ошибку с кодом: json: cannot unmarshal array into Go struct field .coordinates of type float64

1 Ответ

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

Используйте json.RawMessage для захвата значения, которое варьируется в зависимости от типа геометрии:

Geometries []struct {
    Type        string          `json:"type"`
    Coordinates json.RawMessage `json:"coordinates"`
} `json:"geometries"`

Разберите координаты до значения, соответствующего каждому типу:

for _, geo := range x.Geometries {
    switch geo.Type {
    case "Point":
        var coords []float64
        if err := json.Unmarshal(geo.Coordinates, &coords); err != nil {
            log.Fatal(err)
        }
        fmt.Println(coords)
    case "Polygon":
        var coords [][][]float64
        if err := json.Unmarshal(geo.Coordinates, &coords); err != nil {
            log.Fatal(err)
        }
        fmt.Println(coords)
    }
}

Запустите его на игровой площадке .

Другой вариант - разархивировать до interface{} и использовать утверждения типа для поиска значения:

Geometries []struct {
    Type        string      `json:"type"`
    Coordinates interface{} `json:"coordinates"`
} `json:"geometries"`

...

for _, geo := range x.Geometries {
    fmt.Println(geo.Type)
    dump(geo.Coordinates, "")
}

...

func dump(v interface{}, indent string) {
    switch v := v.(type) {
    case []interface{}:
        fmt.Println(indent, "[")
        for _, v := range v {
            dump(v, indent+"  ")
        }
        fmt.Println(indent, "]")
    default:
        fmt.Println(indent, v)
    }
}

Запустите его на детской площадке .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...