Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从API的json响应中检索数据_Json_Api_Go_Interface_Maps - Fatal编程技术网

从API的json响应中检索数据

从API的json响应中检索数据,json,api,go,interface,maps,Json,Api,Go,Interface,Maps,我试图通过将json响应中的数据存储在一些结构(Airport+坐标)中来获取数据,但我不知道如何处理这些数据,因为我对映射和接口不够精通。代码未显示任何错误,但MapofAirports完全为空。代码如下: package main import ( //"api/client" //"api/client/clienterrors" //"api/client/openstreetmap" "encoding/json" "fmt" "io/

我试图通过将json响应中的数据存储在一些结构(Airport+坐标)中来获取数据,但我不知道如何处理这些数据,因为我对映射和接口不够精通。代码未显示任何错误,但MapofAirports完全为空。代码如下:

package main

import (
    //"api/client"
    //"api/client/clienterrors"
    //"api/client/openstreetmap"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "math"
    "net/http"
    "os"
    "strconv"
    "strings"
)

type Coordinates struct {
    Longitude string `json:"lon"`
    Latitude  string `json:"lat"`
}

type Airport struct {
    Co       Coordinates `json:"location"`
    IATACode string      `json:"id"`
    Distance float64     `json:"distance"` // distance to coordinates in kilometer
}

func GetCoordinatesFromURL(url string) (float64, float64) {

    parts := strings.Split(url, "=")

    lat0 := strings.Split(parts[2], "&")
    lon0 := strings.Split(parts[3], "&")

    lat1, _ := strconv.ParseFloat(lat0[0], 64)
    lon1, _ := strconv.ParseFloat(lon0[0], 64)

    return lat1, lon1
}

func CalcDistance(lat1 float64, long1 float64, lat2 float64, long2 float64) float64 {

    var latitude1 = lat1 * math.Pi / 180
    var latitude2 = lat2 * math.Pi / 180
    var longitude1 = long1 * math.Pi / 180
    var longitude2 = long2 * math.Pi / 180

    var R = 6371.0
    var d = R * math.Acos(math.Cos(latitude1)*math.Cos(latitude2)*math.Cos(longitude2-longitude1)+math.Sin(latitude1)*math.Sin(latitude2))

    return d
}

func main() {
    var Locations []Airport
    Locations = make([]Airport, 0)

    var url = fmt.Sprintf("https://api.skypicker.com/locations?type=radius&lat=40.730610&lon=-73.935242&radius=250&location_types=airport&limit=3&sort=id&active_only=true")

    UrlLat, UrlLon := GetCoordinatesFromURL(url)

    resp, err := http.Get(url)
    if err != nil {
        panic(err.Error())
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)

    var airportsJsonResponse interface{}

    err = json.Unmarshal(body, &airportsJsonResponse)

    MapofAirports, ok := airportsJsonResponse.([]interface{})

    if ok {
        lenAiroMap := len(MapofAirports)

        locationsMaps := make(map[int]map[string]interface{})

        for i := 0; i < lenAiroMap; i++ {
            locationsMaps[i] = MapofAirports[i].(map[string]interface{})
        }
        var coords Coordinates
        for i := 0; i < lenAiroMap; i++ {
            if longitude, ok0 := locationsMaps[i]["lon"].(string); ok0 {
                if latitude, ok1 := locationsMaps[i]["lat"].(string); ok1 {
                    coords = Coordinates{longitude, latitude}
                }
            }
            code := locationsMaps[i]["id"].(string)

            latFromCoordinates, _ := strconv.ParseFloat(Locations[i].Co.Latitude, 64)
            lonFromCoordinates, _ := strconv.ParseFloat(Locations[i].Co.Longitude, 64)

            dist := CalcDistance(latFromCoordinates, lonFromCoordinates, UrlLat, UrlLon)
            Locations = append(Locations, Airport{
                Co:       coords,
                IATACode: code,
                Distance: dist,
            })
        }
    }
    LocationsJson, err := json.Marshal(Locations)
    if err != nil {
        log.Fatal("Cannot encode to JSON ", err)
    }
    fmt.Fprintf(os.Stdout, "%s", LocationsJson)
}

将此行
mapofairport,ok:=airportsJsonResponse。([]接口{})
更改为此

MapofAirports, ok := airportsJsonResponse.(map[string]interface{})
如果在这一行放置断点,您将看到
airportsJsonResponse
的类型是
map[string]接口{}
。 您必须将这些行更改为键值迭代

for i := 0; i < lenAiroMap; i++ {
            locationsMaps[i] = MapofAirports[i].(map[string]interface{})
        }

这是我最后一次更新,在运行程序时,它在解组步骤中陷入恐慌

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "math"
    "net/http"
    "strconv"
    "strings"
)

type Coordinates struct {
    Longitude string `json:"lon"`
    Latitude  string `json:"lat"`
}

type Airport struct {
    Co       Coordinates `json:"location"`
    IATACode string      `json:"id"`
    Distance float64     `json:"distance"` // distance to coordinates in kilometer
}

type Response struct {
    Locations []Airport `json:"locations"`
    // add all the other fields you care about
}

func GetCoordinatesFromURL(url string) (float64, float64) {

    parts := strings.Split(url, "=")

    lat0 := strings.Split(parts[2], "&")
    lon0 := strings.Split(parts[3], "&")

    lat1, _ := strconv.ParseFloat(lat0[0], 64)
    lon1, _ := strconv.ParseFloat(lon0[0], 64)

    return lat1, lon1
}

func CalcDistance(lat1 float64, long1 float64, lat2 float64, long2 float64) float64 {

    var latitude1 = lat1 * math.Pi / 180
    var latitude2 = lat2 * math.Pi / 180
    var longitude1 = long1 * math.Pi / 180
    var longitude2 = long2 * math.Pi / 180

    var R = 6371.0
    var d = R * math.Acos(math.Cos(latitude1)*math.Cos(latitude2)*math.Cos(longitude2-longitude1)+math.Sin(latitude1)*math.Sin(latitude2))

    return d
}

func main() {


    var url = fmt.Sprintf("https://api.skypicker.com/locations?type=radius&lat=40.730610&lon=-73.935242&radius=250&location_types=airport&limit=3&sort=id&active_only=true")

    UrlLat, UrlLon := GetCoordinatesFromURL(url)

    resp, err := http.Get(url)
    if err != nil {
        panic(err.Error())
    }
    defer resp.Body.Close()

     data, err := ioutil.ReadAll(resp.Body)
    res := &Response{}
    if err := json.Unmarshal(data, res); err != nil {
        panic(err)
    }
    fmt.Println(res.Locations)

    for i, item := range res.Locations {
        latt,_ := strconv.ParseFloat(item.Co.Latitude, 64)
        lonn,_ :=strconv.ParseFloat(item.Co.Longitude, 64)
        res.Locations[i].Distance = CalcDistance(latt,lonn , UrlLat, UrlLon)
    }
    fmt.Println("after calculate distance")
    fmt.Println(res.Locations)
}

这有什么不对?

如果您预先知道JSON结构,并且愿意使用Go结构,那么就不要使用映射和空接口。如果数据结构已知,我还建议使用structs进行编译。您可以。@mkopriva谢谢您的回答,它真的很有效,但我仍然只有一个问题,如果我想向结构添加#Distance float64
json:“Distance”
#,并想使用CalcDistance()函数和lon、lat参数获取值,我该怎么办?@herotet您可以让
CalcDistance
成为具有坐标访问权限的类型上的方法,无论是
Location
还是
LocationItem
由您决定。如果需要将
距离
作为一个字段,那么在完成解组后,可以通过在已解组json的结构实例上循环来计算距离,这非常简单。如果要在解组的同时计算距离,可以使用要解组的类型,实现
json.Unmarshaler
接口。@herotet下面是一个解组后循环goroutine 1[运行]:main.main()C:/Users/herotet/go/src/CT_ProjectV2/main.go:70+0x536当我调试时,我得到了这样一个结果:json:cannot unmarshal number到go struct field Coordinates.locations.location.lat类型strings将lat Lon字段类型从
string
更改为
float64
。我还有一个问题,由于这是一项小组工作,其他人已经将纬度和经度作为字符串进行了工作,我应该如何做?我希望得到相同的结果,但在这种情况下?是否需要在
坐标
类型中使用
字符串
?或者,您是否需要在发送回发出初始请求的客户端的响应json中使用
string
        lenAiroMap := len(MapofAirports)
        locationsMaps := make([]map[string]interface{},lenAiroMap)
        for i, value := range MapofAirports["locations"].([]interface{}) {
            converted := value.(map[string]interface{})
            locationsMaps[i] = converted
        }
package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "math"
    "net/http"
    "strconv"
    "strings"
)

type Coordinates struct {
    Longitude string `json:"lon"`
    Latitude  string `json:"lat"`
}

type Airport struct {
    Co       Coordinates `json:"location"`
    IATACode string      `json:"id"`
    Distance float64     `json:"distance"` // distance to coordinates in kilometer
}

type Response struct {
    Locations []Airport `json:"locations"`
    // add all the other fields you care about
}

func GetCoordinatesFromURL(url string) (float64, float64) {

    parts := strings.Split(url, "=")

    lat0 := strings.Split(parts[2], "&")
    lon0 := strings.Split(parts[3], "&")

    lat1, _ := strconv.ParseFloat(lat0[0], 64)
    lon1, _ := strconv.ParseFloat(lon0[0], 64)

    return lat1, lon1
}

func CalcDistance(lat1 float64, long1 float64, lat2 float64, long2 float64) float64 {

    var latitude1 = lat1 * math.Pi / 180
    var latitude2 = lat2 * math.Pi / 180
    var longitude1 = long1 * math.Pi / 180
    var longitude2 = long2 * math.Pi / 180

    var R = 6371.0
    var d = R * math.Acos(math.Cos(latitude1)*math.Cos(latitude2)*math.Cos(longitude2-longitude1)+math.Sin(latitude1)*math.Sin(latitude2))

    return d
}

func main() {


    var url = fmt.Sprintf("https://api.skypicker.com/locations?type=radius&lat=40.730610&lon=-73.935242&radius=250&location_types=airport&limit=3&sort=id&active_only=true")

    UrlLat, UrlLon := GetCoordinatesFromURL(url)

    resp, err := http.Get(url)
    if err != nil {
        panic(err.Error())
    }
    defer resp.Body.Close()

     data, err := ioutil.ReadAll(resp.Body)
    res := &Response{}
    if err := json.Unmarshal(data, res); err != nil {
        panic(err)
    }
    fmt.Println(res.Locations)

    for i, item := range res.Locations {
        latt,_ := strconv.ParseFloat(item.Co.Latitude, 64)
        lonn,_ :=strconv.ParseFloat(item.Co.Longitude, 64)
        res.Locations[i].Distance = CalcDistance(latt,lonn , UrlLat, UrlLon)
    }
    fmt.Println("after calculate distance")
    fmt.Println(res.Locations)
}