1

I have a http server and I would like to handle JSON responses to overwrite a JSON file, and I want to be able to parse any amount of data and structure.

So my JSON data could look like this:

{
  "property1": "value",
  "properties": {
    "property1": 1,
    "property2": "value"
  }
}

Or it can look like this:

{"property": "value"}

I would like to iterate through each property, and if it already exists in the JSON file, overwrite it's value, otherwise append it to the JSON file.

I have tried using map but it doesn't seem to support indexing. I can search for specific properties by using map["property"] but the idea is that I don't know any of the JSON data yet.

How can I (without knowing the struct) iterate through each property and print both its property name and value?

dcn
  • 21
  • 3
  • 3
    What have you tried? What problems did you encounter? – Jonathan Hall Feb 14 '18 at 23:04
  • 1
    Indexing isn't necessary for what you're trying, so your problem with `map` doesn't make sense. Include your code. Also, this question comes up about 2x per week. There are countless other answers on SO. What did your research reveal? – Jonathan Hall Feb 14 '18 at 23:11
  • See https://blog.golang.org/json-and-go. Possible duplicate of https://stackoverflow.com/questions/29366038/looping-iterate-over-the-second-level-nested-json-in-go-lang#answer-29382205 where there is no pre-defined structure. – Charlie Tumahai Feb 14 '18 at 23:15
  • @CeriseLimón So I can iterate using a range and then parse its data. That's what I wanted to know. Thanks! – dcn Feb 14 '18 at 23:24

1 Answers1

3

How can I (without knowing the struct) iterate through each property and print both its property name and value?

Here is a basic function that recurses through the parsed json data structure and prints the keys/values. It's not optimized and probably doesn't address all edge cases (like arrays in arrays), but you get the idea. Playground.

Given an object like {"someNumerical":42.42,"stringsInAnArray":["a","b"]} the output is something like the following:

object {
key: someNumerical value: 42.42
key: stringsInAnArray value: array [
value: a
value: b
]
value: [a b]
}

Code:

func RecurseJsonMap(dat map[string]interface{}) {
    fmt.Println("object {")   
    for key, value := range dat {
        fmt.Print("key: " + key + " ")        
    // print array properties
    arr, ok := value.([]interface{})
    if ok {
        fmt.Println("value: array [") 
        for _, arrVal := range arr {
            // recurse subobjects in the array
            subobj, ok := arrVal.(map[string]interface{})
            if ok {
                RecurseJsonMap(subobj)
            } else {            
                // print other values
                fmt.Printf("value: %+v\n", arrVal)        
            }   
        }
        fmt.Println("]")    
    }

    // recurse subobjects
    subobj, ok := value.(map[string]interface{})
    if ok {
        RecurseJsonMap(subobj)
    } else {            
            // print other values
            fmt.Printf("value: %+v\n" ,value)        
        } 
    }
    fmt.Println("}")   
}

func main() {
    // some random json object in a string
    byt := []byte(`{"someNumerical":42.42,"stringsInAnArray":["a","b"]}`)

    // we are parsing it in a generic fashion
    var dat map[string]interface{}
    if err := json.Unmarshal(byt, &dat); err != nil {
        panic(err)
    }
    RecurseJsonMap(dat)
}
Oswin Noetzelmann
  • 9,166
  • 1
  • 33
  • 46
  • Thanks! A nice recursive JSON parser in a single function :) – dcn Feb 16 '18 at 09:01
  • It's not parsing technically, just iterating through the generic data structures that the golang json parser creates for us. (Which is what you asked for I think) – Oswin Noetzelmann Feb 16 '18 at 09:07
  • 1
    Yeah, whether it just prints it or writes to a file is not really too important, my question was how to do it without a predefined struct and you showed me exactly that. My account is still too newb for upvotes so you'll have to wait a little, sorry! – dcn Feb 16 '18 at 10:44