Extract all JSON keys and values as map

i want to get all keys and values of json fields as type map[string][]string. The objects with same keys, should be in same map field.

I can convert JSON to map[string]interface{} now with this function, but it doesn't meet my needs.

func jsonToMap(data []byte) map[string]interface{} {
    x := map[string]interface{}
    json.Unmarshal(data, &x)

    return x
}

Sample json:

  {
  "data": {
    "name": "John",
    "age": 30
  },
  "items": [
    1,
    2,
    3
  ],
  "data2": {
    "name": "Johns",
    "age": {
      "test": [
        1,
        2,
        3,
        {
          "test2": "123"
        }
      ]
    }
  }
}

Expected result:

map[string][]string
map["data"][]string{""}
map["name"][]string{"John", "Johns"}
map["age"][]string{"30",""}
map["items"][]string{"1","2","3"}
map["test"][]string{"1","2","3"}
map["test2"][]string{"123"}

Upvotes: 3

Views: 3292

Answers (1)

Amirreza Noori
Amirreza Noori

Reputation: 1525

The solution is using recursive function.

https://en.wikipedia.org/wiki/Recursion_(computer_science)

Here is a simple example: https://gobyexample.com/recursion

The following code can do what you want:

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    JSONStr := `{
        "data": {"name": "John", "age": 30},
        "items": [1, 2, 3],
        "data2": {
            "name": "Johns",
            "age": {"test": [1, 2, 3, {"test2": "123"}]}
        }
    }`

    var JSON map[string]interface{}
    json.Unmarshal([]byte(JSONStr), &JSON)

    neededOutput := jsonToMap(JSON)
    fmt.Println(neededOutput)
}

func jsonToMap(data map[string]interface{}) map[string][]string {
    // final output
    out := make(map[string][]string)

    // check all keys in data
    for key, value := range data {
        // check if key not exist in out variable, add it
        if _, ok := out[key]; !ok {
            out[key] = []string{}
        }

        if valueA, ok := value.(map[string]interface{}); ok { // if value is map
            out[key] = append(out[key], "")
            for keyB, valueB := range jsonToMap(valueA) {
                if _, ok := out[keyB]; !ok {
                    out[keyB] = []string{}
                }
                out[keyB] = append(out[keyB], valueB...)
            }
        } else if valueA, ok := value.([]interface{}); ok { // if value is array
            for _, valueB := range valueA {
                if valueC, ok := valueB.(map[string]interface{}); ok {
                    for keyD, valueD := range jsonToMap(valueC) {
                        if _, ok := out[keyD]; !ok {
                            out[keyD] = []string{}
                        }
                        out[keyD] = append(out[keyD], valueD...)
                    }
                } else {
                    out[key] = append(out[key], fmt.Sprintf("%v", valueB))
                }
            }
        } else { // if string and numbers and other ...
            out[key] = append(out[key], fmt.Sprintf("%v", value))
        }
    }
    return out
}

Output:

map[age:[30 ] data:[] data2:[] items:[1 2 3] name:[John Johns] test:[1 2 3] test2:[123]]

Upvotes: 4

Related Questions