0

I'm just starting to learn go.

This is the file I need to parse:

{ 
    "people": {
        "asd": {
            "name": "Alex",
            "id": 0,
            "s": "m"
        },
        "fda": {
            "name": "Mike",
            "id": 1,
            "s": "m"
        },
        "fg2": {
            "name": "Rosa",
            "id": 3,
            "s": "f",
            "Childs" :
            [
                {
                    "name": "Bob",
                    "age": 1,
                    "s": "m"
                },
                {
                    "name": "Maria",
                    "age": 2,
                    "s": "f"
                }
            ]
        }
    }
}

asd, fda, fg2 are some kind of identifiers consisting of a random set of characters.

First of all, I couldn't describe the structure for this file, I was confused by these random identifiers.

And I did this:

type people {
    People *map[string]interface{} `json:"people"`
}

So I'm trying to read and parse this file and just got stuck. This is my code:

package main

import "encoding/json"
import "io/ioutil"
import "log"
import "fmt"

type people struct {
    People map[string]interface{} `json:"people"`
}

func main() {

    file, err := ioutil.ReadFile("./people.json")
    if err != nil {
        log.Println("error:", err)
    }

    var data people

    err = json.Unmarshal([]byte(file), &data)
    if err != nil {
        log.Println("error:", err)
    }

    //fmt.Println(data.people)//

    fmt.Println(data)
    //  for i := 0; i < len(data); i++ {//here the compiler throws error...
    //    fmt.Println("name: ", data[i].name)//#@!o_0
    //  }
  }

The error is: invalid operation: data[i] (type people does not support indexing).

Please help me sort out and print the names of these people, as well as the names of their children.

Alex
Mike
Rosa
    Bob
    Maria
Evgeny
  • 45
  • 6
  • The errors that he compiler throws are more descriptive than `#@!o_0`, and will tell you exactly what is wrong there. `data` probably looks strange because you don't need a pointer to a map, the struct itself is addressable. – JimB May 04 '20 at 21:24
  • @JimB thank you, I removed the " * " character from the structure description. And the error is: invalid operation: data[i] (type people does not support indexing). Please tell me how do i work with this structure... – Evgeny May 04 '20 at 21:36
  • You can't iterate over `data` or index it, because it's a struct with a single field called `People`. – JimB May 04 '20 at 21:39
  • @JimB, can you tell me how to describe the structure for such a file? – Evgeny May 04 '20 at 21:43
  • I'm not sure what you mean, the javascript presented here is an object with a single field named `"people"`, so this structure will work. – JimB May 04 '20 at 21:48
  • @JimB, how do I enumerate elements with these random IDs? – Evgeny May 04 '20 at 22:10
  • @Evgeny Does [Iterating over all the keys of a map](https://stackoverflow.com/questions/1841443/iterating-over-all-the-keys-of-a-map) answer your question? – Charlie Tumahai May 04 '20 at 23:39
  • @CeriseLimón for k := range data.People { fmt.Printf("%s\n", data.People[k]["name"])//invalid operation: data.People[k]["name"] (type interface {} does not support indexing) } Isn't there an easy way to do what I need to do? :( – Evgeny May 05 '20 at 00:05
  • https://play.golang.org/p/45EVMf5RPgb to give you some idea. – gipsy May 05 '20 at 03:01
  • @gipsy, thank you! Thank you all! I have solved this task. – Evgeny May 06 '20 at 00:04

2 Answers2

3

It's probably simplest to use a json.Decoder. Also you need to remember that when decoding a JSON map with varying keys (such as "asd", "fda", "fg2" in your example) you should use a map but for fixed keys ("name", "id", "age") you shoudl use a struct.

Here is some code to illustrate Go Playground:

package main

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

type people struct {
    People map[string]Person `json:"people"`
}

type Person struct {
    Name     string   `json:"name"`
    ID       int      `json:"id,omitempty"`
    Sex      string   `json:"s,omitempty"`
    Age      int      `json:"age,omitempty"`
    Children []Person `json:"Childs,omitempty"`
}

func main() {
    file, err := ioutil.ReadFile("./people.json")
    if err != nil {
        log.Fatalln("error:", err)
    }

    var data people
    if err := json.NewDecoder(strings.NewReader(string(file))).Decode(&data); err == nil {
        fmt.Println(data)
    }
}

Andrew W. Phillips
  • 3,254
  • 1
  • 21
  • 24
-1

You could do that this way. Update: sort the name.

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "sort"
)

type people struct {
    People map[string]interface{} `json:"people"`
}

type Node struct {
    Name     string
    Space    int
    Children *[]Node
}

func sortAndPrint(ans []Node) {
    if len(ans) == 0 {
        return
    }
    sort.Slice(ans, func(i, j int) bool {
        return ans[i].Name < ans[j].Name
    })
    for _, node := range ans {
        for i := 0; i < node.Space; i++ {
            fmt.Printf(" ")
        }
        fmt.Println(node.Name)
        sortAndPrint(*node.Children)
    }
}

func findAllNode(ans *[]Node, people map[string]interface{}, space int) {
    ansChild := make([]Node, 0)

    *ans = append(*ans, Node{people["name"].(string), space, &ansChild})
    children, hasChildren := (people["Childs"]).([]interface{})
    if !hasChildren {
        return
    }
    for _, child := range children {
        childMap, ok := child.(map[string]interface{})
        if !ok {
            return
        }
        findAllNode(&ansChild, childMap, space+4)
    }
}

func main() {
    file, err := ioutil.ReadFile("./people.json")
    if err != nil {
        log.Println("error:", err)
    }

    var data people

    err = json.Unmarshal([]byte(file), &data)
    if err != nil {
        log.Println("error:", err)
    }

    ans := make([]Node, 0)

    for _, value := range data.People {
        value2, ok := value.(map[string]interface{})
        if !ok {
            continue
        }
        findAllNode(&ans, value2, 0)
    }

    sortAndPrint(ans)
}
hyz
  • 472
  • 3
  • 10