我是一个新来的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?
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
}
正如@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]]]}}]}