Golang 解除Marshaling数组给出运行时错误:索引超出范围

问题描述 投票:0回答:1

我是一个新来的golang,还在学习一些东西,但我在这个问题上遇到了麻烦。顶端. json的相关部分是这样的。

{
   "features": [
     {
       "properties": {
         "display_name": "name", 
         "address": {"county": "County", "country":"country", "country_code":"cc"}
       },
       "bbox": [13.9171885,44.2603464,15.2326512,45.6729436],
       "geometry": {
          "coordinates": [
               [
                 [
                   [14.4899021,41.4867039],
                   [14.5899021,41.5867039]
                 ]
               ],
               [
                 [
                   [15.4899021,41.4867039],
                   [15.5899021,41.5867039]
                 ]
               ],
            ]
        }
     }
   ]
}

我试图用这种结构来解开它的marshal。

// Feature struct
type Feature struct {
    Properties struct {
        Name    string `json:"display_name"`
        Address struct {
            Country string `json:"country"`
            Code    string `json:"country_code"`
        } `json:"address"`
    } `json:"properties"`
    Bbox []float64 `json:"bbox"`
    Geo  struct {
        Coordinates [][][][]float64 `json:"coordinates"`
    } `json:"geometry"`
}

// GeoJSONEntry struct
type GeoJSONEntry struct {
    Features []Feature `json:"features"`
}

我用这个函数调用api:

func (server *Server) ImportRegionsMultiPolygon(w http.ResponseWriter, r *http.Request) {
    var locations []LocationMulti
    var errors []error

    for _, county := range multiPolygons {
        res, err := http.Get(baseURL + "?osm_ids=" + county.Type + county.OsmID + "&format=json&polygon_geojson=1")
        if err != nil {
            errors = append(errors, err)
        }

        bytes, err := ioutil.ReadAll(res.Body)

        if err != nil {
            errors = append(errors, err)
        }

        location, err := ParseGeoJSON(bytes)

        if err != nil {
            errors = append(errors, err)
        } else {
            locations = append(locations, location)
        }
    }

    if errors != nil {
        http.Error(w, errors[0].Error(), http.StatusBadRequest)
        return
    } else {
        file, _ := json.MarshalIndent(locations, "", " ")
        if err := ioutil.WriteFile("./static/regions/geodata-multi.json", file, 0644); err != nil {
            http.Error(w, "Error writing file", http.StatusBadRequest)
            return
        } else {
            responses.JSON(w, http.StatusCreated, locations)
        }
    }
}

我用这个函数调用api: LocationMulti 看起来像这样。

// LocationMulti struct
type LocationMulti struct {
    Name        string
    Lat         string
    Lng         string
    Country     string
    CountryCode string
    Coordinates [][][][]float64
}

功能 ParseGeoJSON 看起来像这样。

func ParseGeoJSON(bytes []byte) (LocationMulti, error) {
    var entry GeoJSONEntry
    var err error

    if err := json.Unmarshal(bytes, &entry); err != nil {
        fmt.Println("Error parsing json", err)
    }

    fmt.Printf("%v\n", &entry)

    location := LocationMulti{
        Name:        entry.Features[0].Properties.Name,
        Lat:         fmt.Sprintf("%f", (entry.Features[0].Bbox[1]+entry.Features[0].Bbox[3])/2),
        Lng:         fmt.Sprintf("%f", (entry.Features[0].Bbox[0]+entry.Features[0].Bbox[2])/2),
        Country:     entry.Features[0].Properties.Address.Country,
        CountryCode: entry.Features[0].Properties.Address.Code,
        Coordinates: entry.Features[0].Geo.Coordinates,
    }

    return location, err
}

我得到一个错误。

Error parsing json json: cannot unmarshal array into Go value of type controllers.Entry
2020/04/28 17:36:39 http: panic serving [::1]:61457: runtime error: index out of range

我到底做错了什么,我应该如何解开这种json的marshal?

json go unmarshalling
1个回答
3
投票

Unmarshal方法本身的调用是正确的,问题是你要求的是 JSON 格式,是一个数组,而不是预期的 GeoJSON. 解决以下错误的方法 json.Unmarshal 正在取代

    res, err := http.Get(baseURL + "?osm_ids=" + county.Type + county.OsmID + "&format=json&polygon_geojson=1")

    res, err := http.Get(baseURL + "?osm_ids=" + county.Type + county.OsmID + "&format=geojson&polygon_geojson=1")

EDIT: 虽然另外我还会重写一下。ParseGeoJSON 以避免恐慌。

func ParseGeoJSON(bytes []byte) (LocationMulti, error) {
    var entry Entry
    var err error

    if err := json.Unmarshal(bytes, &entry); err != nil {
        fmt.Println("Error parsing json", err)
        return LocationMulti{}, err
    }

    fmt.Printf("%v\n", &entry)

    if len(entry.Features) == 0 {
        return LocationMulti{}, fmt.Errorf("parsed entry has no features")
    }

    feature := entry.Features[0]
    if len(feature.Bbox) < 4 {
        return LocationMulti{}, fmt.Errorf("bbox of parsed entry has too few points")
    }

    location := LocationMulti{
        Name:        feature.Properties.Name,
        Lat:         fmt.Sprintf("%f", (feature.Bbox[1]+feature.Bbox[3])/2),
        Lng:         fmt.Sprintf("%f", (feature.Bbox[0]+feature.Bbox[2])/2),
        Country:     feature.Properties.Address.Country,
        CountryCode: feature.Properties.Address.Code,
        Coordinates: feature.Geo.Coordinates,
    }

    return location, err
}

-1
投票

正如@mkopriva所指出的,问题很可能出在了检索上 bytes. 下面产生预期的输出。

package main

import (
    "encoding/json"
    "fmt"
)

type Feature struct {
    Properties struct {
        Name    string `json:"display_name"`
        Address struct {
            Country string `json:"country"`
            Code    string `json:"country_code"`
        } `json:"address"`
    } `json:"properties"`
    Bbox []float64 `json:"bbox"`
    Geo  struct {
        Coordinates [][][]float64 `json:"coordinates"`
    } `json:"geometry"`
}

type Entry struct {
    Features []Feature `json:"features"`
}

var data = `{
   "features": [
     {
       "properties": {
         "display_name": "name",
         "address": {"county": "County", "country":"country", "country_code":"cc"}
       },
       "bbox": [13.9171885,44.2603464,15.2326512,45.6729436],
       "geometry": {
          "coordinates": [
             [
               [14.4899021,41.4867039],
               [14.5899021,41.5867039]
             ]
          ]
        }
     }
   ]
}`

func main() {
    var entry Entry

    bytes := []byte(data)
    if err := json.Unmarshal(bytes, &entry); err != nil {
        fmt.Println("Error parsing json", err)
    }

    fmt.Printf("%v\n", entry)
}

而结果是:

{[{{name {country cc}} [13.9171885 44.2603464 15.2326512 45.6729436] {[[[14.4899021 41.4867039] [14.5899021 41.5867039]]]}}]}

© www.soinside.com 2019 - 2024. All rights reserved.