解析嵌套的json文件

I'm parsing a JSON file with an unusual structure which looks like this:

{
    "394885": 
    {
        "record": 
        {
            "student_name": "Daryl Jones",
            "student_number": 123884,
            "student_dob": "12/10/1982",
            "student_email": "djones@school.ac.uk",
        }    
    },
}

I've been working through some code demos, but I would like to put it all in to a struct, which I then plan to search through by the number string that's the object name I would guess?

I'm not strong on JSON or Go, and this is the code I've written so far:

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "os"
)

type id struct {
    recordid string
    record   []record
}

type record struct {
    name   string
    number uint32
    dob    string
    email  string
}

func main() {
    jsonFile, err := os.Open("/home/emyrw/development/go/src/json_processor/demo.json")
    if err != nil {
        fmt.Println(err)
    } else {
        var records id

        byteValue, _ := ioutil.ReadAll(jsonFile)
        json.Unmarshal(byteValue, &records)
        fmt.Println(records)

        fmt.Println("opened demo.json")
        defer jsonFile.Close()
    }
}

I'm not sure I've got it right, but would value any tips or advice anyone has to offer. I've been googling, but none of the samples I find quite fit my scenario.

You can use this struct for your id type

type id struct {
    record map[string]record
}

Edit

here is the working solution with some explanation:

since you have a multi level json, you can parse it into nested structs.

{
        "student_name": "Daryl Jones",
        "student_number": 123884,
        "student_dob": "12/10/1982",
        "student_email": "djones@school.ac.uk"
} 

to parse this part of the json you need this struct

type record struct {
    Name   string `json:"student_name"`
    Number uint32 `json:"student_number"`
    Dob    string `json:"student_dob"`
    Email  string `json:"student_email"`
}

the fields have to be exported(start with capital letter) and have a json tag that matches json properties.

{
    "record": 
    {
        "student_name": "Daryl Jones",
        "student_number": 123884,
        "student_dob": "12/10/1982",
        "student_email": "djones@school.ac.uk"
    }    
}

for this part to work, you need a nested struct like this

type id struct {
     Record record
}

the filed name is exported again but since it matches your json property, you don't need the tag.

{
"394885": 
  {
    "record": 
    {
        "student_name": "Daryl Jones",
        "student_number": 123884,
        "student_dob": "12/10/1982",
        "student_email": "djones@school.ac.uk"
    }    
  }
}

since the top level property name is the student id, you can use a map instead of a struct

 var records map[string]id 

and make sure you don't have trailing commas as that is not allowed in json specs

First, your JSON is invalid. Unlike GoLang structs, you don't need to put , after your final object.

{ "394885": { "record": { "student_name": "Daryl Jones", "student_number": 123884, "student_dob": "12/10/1982", "student_email": "djones@school.ac.uk" }
} }

Second, var records supposed to model your JSON exactly, either by naming the fields in your struct exactly as they are named in the JSON object, or by using attributes.

The exterior of your JSON is not of type id, it is of type map[string]id

id doesn't have a recordid field, it does however, has a record field, but, the field of your structs must be exported (start with capital case) if you want to serialise JSON into them.

This is where attributes come in handy,

type id struct {
    Record []record `json:"record"`
}

Same with the record struct,

type record struct {
    Name string `json:"student_name"`
    Email string `json:"student_email"`
    // You get the idea...
}

Third, You put the defer statement right after you open the file, putting it at the end of the block defeats the purpose.

Declare Go types that match the structure of the data. The JSON data has three levels of objects. Use a map to represent the top-level object in the JSON because the top-level object has arbitrary keys. Use structs for the lower-level objects in the JSON.

Use JSON field tags to map the snake case names used in the JSON to more idiomatic Go names. Export the fields so they can be accessed by the JSON package.

See the Marshal function documentation for info on how the json/encoding package uses field tags and the requirement to export the fields.

type Record struct {
    Name   string `json:"student_name"`
    Number uint32 `json:"student_number"`
    DOB    string `json:"student_dob"`
    Email  string `json:"student_email"`
}

type ID struct {
    Record Record
}

...

var records map[string]ID
err := json.Unmarshal(jsonFile, &records)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("%#v
", records)

Run it on the playground.

jsonquery package can easy extract data from JSON document, and it does't dependent on defined struct object.

func main() {
    s := `{
        "394885": 
        {
            "record": 
            {
                "student_name": "Daryl Jones",
                "student_number": 123884,
                "student_dob": "12/10/1982",
                "student_email": "djones@school.ac.uk"
            }    
        }
    }`
    doc, err := jsonquery.Parse(strings.NewReader(s))
    if err != nil {
        panic(err)
    }
    nodes := jsonquery.Find(doc, "*")
    for _, n := range nodes {
        fmt.Printf("id: %s 
", n.Data)
        name := jsonquery.FindOne(n, "//student_name") // Find student name node
        fmt.Printf("student name: %s
", name.InnerText())
        number := jsonquery.FindOne(n, "//student_number") // Find node for student number
        fmt.Printf("student number: %s
", number.InnerText())
    }
}