Skip to content

Instantly share code, notes, and snippets.

@wolf0403
Created July 19, 2018 09:17
Show Gist options
  • Save wolf0403/e90e6d0555a7353f400980b19f770e9b to your computer and use it in GitHub Desktop.
Save wolf0403/e90e6d0555a7353f400980b19f770e9b to your computer and use it in GitHub Desktop.
Marshalling / unmarshalling JSON in Go, keeping "order of the keys as they were in the source"
package main
import (
"bytes"
"encoding/json"
"fmt"
"log"
"os"
)
type M struct {
keys []string
parsed map[string]json.RawMessage
}
const (
key = iota
value
)
func (m *M) UnmarshalJSON(data []byte) error {
dec := json.NewDecoder(bytes.NewBuffer(data))
parsed := map[string]json.RawMessage{}
var keys []string
// read open bracket
t, err := dec.Token()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%T: %v\n", t, t)
step := key
k := ""
// while the array contains values
for dec.More() {
switch step {
case key:
t, err := dec.Token()
if err != nil {
log.Fatalf("want key, got %v", err)
}
k = t.(string)
keys = append(keys, k)
step = value
case value:
var m json.RawMessage
if err := dec.Decode(&m); err != nil {
return err
}
parsed[k] = m
step = key
}
}
// read closing bracket
t, err = dec.Token()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%T: %v\n", t, t)
fmt.Println("keys: ", keys)
m.keys = keys
m.parsed = parsed
return nil
}
func (m *M) MarshalJSON() ([]byte, error) {
b := bytes.Buffer{}
fmt.Fprintf(&b, "{ ")
for i, k := range m.keys {
fmt.Fprintf(&b, "%q: ", k)
b.Write(m.parsed[k])
if i < len(m.keys)-1 {
b.WriteString(",")
}
}
fmt.Fprintf(&b, " }")
rt := b.String()
fmt.Println("marshal -> %q", rt)
return []byte(rt), nil
}
func s(str string) {
var m M
err := json.Unmarshal([]byte(str), &m)
fmt.Println("unmarshal err: ", err)
b, err := json.MarshalIndent(&m, "", "\t")
if err != nil {
fmt.Println("error:", err)
}
os.Stdout.Write(b)
}
func main() {
s(`{"Message": "Hello", "Array": [1, 2, 3], "Null": null, "Number": 1.234}`)
s(`{"Message": "Hello", "Null": null, "Number": 1.234, "Array": [1, 2, 3]}`)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment