Created
December 14, 2015 23:17
-
-
Save mjohnsullivan/24647cae50928a34b5cc to your computer and use it in GitHub Desktop.
Parse JSON objects with arbitrary key names in Go using interfaces and type assertions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Parsing arbitrary JSON using interfaces in Go | |
// Demonstrates how to parse JSON with abritrary key names | |
// See https://blog.golang.org/json-and-go for more info on generic JSON parsing | |
package main | |
import ( | |
"encoding/json" | |
"fmt" | |
) | |
var jsonBytes = []byte(` | |
{ | |
"key1":{ | |
"Item1": "Value1", | |
"Item2": 1}, | |
"key2":{ | |
"Item1": "Value2", | |
"Item2": 2}, | |
"key3":{ | |
"Item1": "Value3", | |
"Item2": 3} | |
}`) | |
// Item struct; we want to create these from the JSON above | |
type Item struct { | |
Item1 string | |
Item2 int | |
} | |
// Implement the String interface for pretty printing Items | |
func (i Item) String() string { | |
return fmt.Sprintf("Item: %s, %d", i.Item1, i.Item2) | |
} | |
func main() { | |
// Unmarshal using a generic interface | |
var f interface{} | |
err := json.Unmarshal(jsonBytes, &f) | |
if err != nil { | |
fmt.Println("Error parsing JSON: ", err) | |
} | |
// JSON object parses into a map with string keys | |
itemsMap := f.(map[string]interface{}) | |
// Loop through the Items; we're not interested in the key, just the values | |
for _, v := range itemsMap { | |
// Use type assertions to ensure that the value's a JSON object | |
switch jsonObj := v.(type) { | |
// The value is an Item, represented as a generic interface | |
case interface{}: | |
var item Item | |
// Access the values in the JSON object and place them in an Item | |
for itemKey, itemValue := range jsonObj.(map[string]interface{}) { | |
switch itemKey { | |
case "Item1": | |
// Make sure that Item1 is a string | |
switch itemValue := itemValue.(type) { | |
case string: | |
item.Item1 = itemValue | |
default: | |
fmt.Println("Incorrect type for", itemKey) | |
} | |
case "Item2": | |
// Make sure that Item2 is a number; all numbers are transformed to float64 | |
switch itemValue := itemValue.(type) { | |
case float64: | |
item.Item2 = int(itemValue) | |
default: | |
fmt.Println("Incorrect type for", itemKey) | |
} | |
default: | |
fmt.Println("Unknown key for Item found in JSON") | |
} | |
} | |
fmt.Println(item) | |
// Not a JSON object; handle the error | |
default: | |
fmt.Println("Expecting a JSON object; got something else") | |
} | |
} | |
} |
Thank you, helped me in solving one of my problem.
Beautiful!
although its 6 years ago, I found its still useful, oolala
Beautiful! Thanks for sharing.
shouldn't line 53 be case map[string]interface{}:
, then line 56 can just be for itemKey, itemValue := range jsonObj {
? 🤔
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I found this an incredibly effective solution in parsing JSON objects with a variable number of top level keys in Golang.