如何解析结构未知的嵌套json文件Golang

I am trying to parse and get selected data from a deep nested json data in Go Lang. I'm having issues navigating through the structure and accessing the data. The data is too deep and complex to be parsed with a-priori known structures in Go. Here is the URL of the file: -https://www.data.gouv.fr/api/1/datasets/?format=csv&page=0&page_size=20

I did some parsing with map interfaces and using a json string:

resultdata := map[string]interface {}

json.Unmarshal([]byte(inputbytestring), &resultdata) //Inputstring is the string containing the JSON data of the above URL

The problem:

  • How can turn resultdata into a map (of strings), so I can use methods available for maps?
  • The JSON data is nested and has several levels. How is it possible to access the lower level JSON fields? is it possible to unmarshal the data recursively?

Once you have data as a map[string]interface{}, you can use type assertions to get to the lower levels of data.

There's a good explanation here of how to do this at https://blog.golang.org/json-and-go

Here's an example to get you most of the way:

https://play.golang.org/p/P8cGP1mTDmD

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

func main() {
    jsonData := `{
    "string": "string_value",
    "number": 123.45,
    "js_array": ["a", "b", "c"],
    "integer": 678,
    "subtype": {
        "number_array": [1, 2, 3]
      }
    }`

    m := map[string]interface{}{}
    err := json.Unmarshal([]byte(jsonData), &m)
    if err != nil {
        log.Fatal(err)
    }

    for key, value := range m {
        switch v := value.(type) {
        case int:
            fmt.Printf("Key: %s, Integer: %d
", key, v)
        case float64:
            fmt.Printf("Key: %s, Float: %v
", key, v)
        case string:
            fmt.Printf("Key: %s, String: %s
", key, v)
        case map[string]interface{}:
            fmt.Printf("Key: %s, Subtype: %+v
", key, v)
        case []interface{}:
            //TODO: Read through each item in the interface and work out what type it is.
            fmt.Printf("Key: %s, []interface: %v
", key, v)
        default:
            fmt.Printf("Key: %s, unhandled type: %+v
", key, v)
        }
    }
}

Alternatively https://mholt.github.io/json-to-go/ does a decent job of turning examples of JSON data into Go structs that can be used for marshalling.

Putting the example in, I get something that isn't too bad.

type AutoGenerated struct {
    Data []struct {
        Acronym     interface{}   `json:"acronym"`
        Badges      []interface{} `json:"badges"`
        CreatedAt   string        `json:"created_at"`
        Deleted     interface{}   `json:"deleted"`
        Description string        `json:"description"`
        Extras      struct {
        } `json:"extras"`
        Frequency     string      `json:"frequency"`
        FrequencyDate interface{} `json:"frequency_date"`
        ID            string      `json:"id"`
        LastModified  string      `json:"last_modified"`
        LastUpdate    string      `json:"last_update"`
        License       string      `json:"license"`
        Metrics       struct {
            Discussions    int `json:"discussions"`
            Followers      int `json:"followers"`
            Issues         int `json:"issues"`
            NbHits         int `json:"nb_hits"`
            NbUniqVisitors int `json:"nb_uniq_visitors"`
            NbVisits       int `json:"nb_visits"`
            Reuses         int `json:"reuses"`
            Views          int `json:"views"`
        } `json:"metrics"`
        Organization struct {
            Acronym       string `json:"acronym"`
            Class         string `json:"class"`
            ID            string `json:"id"`
            Logo          string `json:"logo"`
            LogoThumbnail string `json:"logo_thumbnail"`
            Name          string `json:"name"`
            Page          string `json:"page"`
            Slug          string `json:"slug"`
            URI           string `json:"uri"`
        } `json:"organization"`
        Owner     interface{} `json:"owner"`
        Page      string      `json:"page"`
        Private   bool        `json:"private"`
        Resources []struct {
            Checksum struct {
                Type  string `json:"type"`
                Value string `json:"value"`
            } `json:"checksum"`
            CreatedAt   string      `json:"created_at"`
            Description interface{} `json:"description"`
            Extras      struct {
            } `json:"extras"`
            Filesize     int    `json:"filesize"`
            Filetype     string `json:"filetype"`
            Format       string `json:"format"`
            ID           string `json:"id"`
            LastModified string `json:"last_modified"`
            Latest       string `json:"latest"`
            Metrics      struct {
                NbHits         int `json:"nb_hits"`
                NbUniqVisitors int `json:"nb_uniq_visitors"`
                NbVisits       int `json:"nb_visits"`
                Views          int `json:"views"`
            } `json:"metrics"`
            Mime       string `json:"mime"`
            PreviewURL string `json:"preview_url"`
            Published  string `json:"published"`
            Title      string `json:"title"`
            Type       string `json:"type"`
            URL        string `json:"url"`
        } `json:"resources"`
        Slug             string        `json:"slug"`
        Spatial          interface{}   `json:"spatial"`
        Tags             []interface{} `json:"tags"`
        TemporalCoverage interface{}   `json:"temporal_coverage"`
        Title            string        `json:"title"`
        URI              string        `json:"uri"`
    } `json:"data"`
    Facets struct {
        Format [][]interface{} `json:"format"`
    } `json:"facets"`
    NextPage     string      `json:"next_page"`
    Page         int         `json:"page"`
    PageSize     int         `json:"page_size"`
    PreviousPage interface{} `json:"previous_page"`
    Total        int         `json:"total"`
}