Parsing arbitary JSON

Published: Sunday, Dec 15, 2013 Last modified: Monday, Apr 8, 2024

For example.json:

{"menu": {
  "id": "file",
  "value": "File",
  "popup": {
	"menuitem": [
	  {"value": "New", "onclick": "CreateNewDoc()"},
	  {"value": "Open", "onclick": "OpenDoc()"},
	  {"value": "Close", "onclick": "CloseDoc()"}
	]
  }
}}

Desired output:

this.menu.popup.menuitem[0].value = "New"
this.menu.popup.menuitem[0].onclick = "CreateNewDoc()"
this.menu.popup.menuitem[1].value = "Open"
this.menu.popup.menuitem[1].onclick = "OpenDoc()"
this.menu.popup.menuitem[2].value = "Close"
this.menu.popup.menuitem[2].onclick = "CloseDoc()"
this.menu.value = "File"
this.menu.id = "file"

Python implementation

With thanks from Hyperair on Freenode’s #hackerspace.sg

#!/usr/bin/python3

import json
import sys

fmt = '{key} = {value}'

def dump_obj(prefix, obj):
	if isinstance(obj, dict):
		for k, v in obj.items():
			if prefix:
				k = prefix + '.' + k

			dump_obj(k, v)

	elif isinstance(obj, list):
		for i, v in enumerate(obj):
			if prefix:
				k = "{prefix}[{idx}]".format(prefix=prefix, idx=i)
			dump_obj(k, v)

	else:
		print(fmt.format(key=prefix, value=json.dumps(obj)))

obj = json.loads(sys.stdin.read())
dump_obj('this', obj)

Golang implementation

Since Golang is statically typed, the important element in the code is t := x.(type) where they type of x gets asserted, which is a required step, so you can then iterate over the resulting structure.

package main

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

func dumpobj(prefix string, x interface{}) {

	switch t := x.(type) {

	case map[string]interface{}:
		for k, v := range t {
			dumpobj(prefix+"."+k, v)
		}
	case []interface{}:
		for i, v := range t {
			dumpobj(prefix+"["+strconv.Itoa(i)+"]", v)
		}
	case string:
		fmt.Printf("%s = %q\n", prefix, t)
	default:
		fmt.Printf("Unhandled: %T\n", t)
	}
}

func main() {
	j, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		panic(err)
	}
	var pj interface{}
	err = json.Unmarshal(j, &pj)
	if err != nil {
		panic(err)
	}

	dumpobj("this", pj)

}

Alternative example with depth: http://play.golang.org/p/QOwxJQ4z4Z

Source is with thanks again from dsal from #go-nuts http://play.golang.org/p/pt4MLJ6HcV

However ideally you know the JSON structure beforehand, and you create a structure for it to map to, e.g. http://play.golang.org/p/bdjC6DLTqo. Only then you can access values easily like:

fmt.Println(myOb.Menu.Popup.Menuitem[0].Value)