Created
January 5, 2021 23:12
-
-
Save packrat386/bd3f9fcbcc89199667542d2518c4e89b to your computer and use it in GitHub Desktop.
YAML to JSON is harder than you might think
This file contains 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
[acoyle01] wat > go run yamltojson.go | |
lets turn YAML into JSON | |
here's the naive data structure | |
(map[string]interface {}) (len=1) { | |
(string) (len=3) "top": (map[interface {}]interface {}) (len=4) { | |
(string) (len=5) "super": (map[interface {}]interface {}) (len=1) { | |
(string) (len=5) "duper": (map[interface {}]interface {}) (len=1) { | |
(string) (len=4) "deep": (string) (len=3) "map" | |
} | |
}, | |
(string) (len=4) "list": ([]interface {}) (len=2 cap=2) { | |
(map[interface {}]interface {}) (len=1) { | |
(string) (len=5) "where": (map[interface {}]interface {}) (len=1) { | |
(string) (len=3) "the": (string) (len=6) "values" | |
} | |
}, | |
(map[interface {}]interface {}) (len=1) { | |
(string) (len=3) "are": (map[interface {}]interface {}) (len=1) { | |
(string) (len=4) "yaml": (string) (len=4) "maps" | |
} | |
} | |
}, | |
(string) (len=6) "isnull": (interface {}) <nil>, | |
(string) (len=7) "numkeys": (map[interface {}]interface {}) (len=2) { | |
(int) 1: (string) (len=3) "one", | |
(int) 2: (string) (len=3) "two" | |
} | |
} | |
} | |
this fails: json: unsupported type: map[interface {}]interface {} | |
here's the custom data structure | |
(map[string]*main.JSONValue) (len=1) { | |
(string) (len=3) "top": (*main.JSONValue)(0xc000010b00)({ | |
contains: (map[string]*main.JSONValue) (len=4) { | |
(string) (len=6) "isnull": (*main.JSONValue)(<nil>), | |
(string) (len=7) "numkeys": (*main.JSONValue)(0xc000010b50)({ | |
contains: (map[string]*main.JSONValue) (len=2) { | |
(string) (len=1) "1": (*main.JSONValue)(0xc000010b80)({ | |
contains: (string) (len=3) "one" | |
}), | |
(string) (len=1) "2": (*main.JSONValue)(0xc000010c40)({ | |
contains: (string) (len=3) "two" | |
}) | |
} | |
}), | |
(string) (len=5) "super": (*main.JSONValue)(0xc000010d00)({ | |
contains: (map[string]*main.JSONValue) (len=1) { | |
(string) (len=5) "duper": (*main.JSONValue)(0xc000010d30)({ | |
contains: (map[string]*main.JSONValue) (len=1) { | |
(string) (len=4) "deep": (*main.JSONValue)(0xc000010d60)({ | |
contains: (string) (len=3) "map" | |
}) | |
} | |
}) | |
} | |
}), | |
(string) (len=4) "list": (*main.JSONValue)(0xc000010e20)({ | |
contains: ([]*main.JSONValue) (len=2 cap=2) { | |
(*main.JSONValue)(0xc000010e50)({ | |
contains: (map[string]*main.JSONValue) (len=1) { | |
(string) (len=5) "where": (*main.JSONValue)(0xc000010e80)({ | |
contains: (map[string]*main.JSONValue) (len=1) { | |
(string) (len=3) "the": (*main.JSONValue)(0xc000010eb0)({ | |
contains: (string) (len=6) "values" | |
}) | |
} | |
}) | |
} | |
}), | |
(*main.JSONValue)(0xc000010f50)({ | |
contains: (map[string]*main.JSONValue) (len=1) { | |
(string) (len=3) "are": (*main.JSONValue)(0xc000010f80)({ | |
contains: (map[string]*main.JSONValue) (len=1) { | |
(string) (len=4) "yaml": (*main.JSONValue)(0xc000010fb0)({ | |
contains: (string) (len=4) "maps" | |
}) | |
} | |
}) | |
} | |
}) | |
} | |
}) | |
} | |
}) | |
} | |
this succeeds | |
{"top":{"isnull":null,"list":[{"where":{"the":"values"}},{"are":{"yaml":"maps"}}],"numkeys":{"1":"one","2":"two"},"super":{"duper":{"deep":"map"}}}} |
This file contains 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
package main | |
import ( | |
"encoding/json" | |
"fmt" | |
"github.com/davecgh/go-spew/spew" | |
"gopkg.in/yaml.v2" | |
) | |
const document = ` | |
top: | |
isnull: null | |
numkeys: | |
1: one | |
2: two | |
super: | |
duper: | |
deep: map | |
list: | |
- where: | |
the: values | |
- are: | |
yaml: maps | |
` | |
func main() { | |
fmt.Println("lets turn YAML into JSON") | |
var naive map[string]interface{} | |
err := yaml.Unmarshal([]byte(document), &naive) | |
if err != nil { | |
panic(err) | |
} | |
fmt.Println("here's the naive data structure") | |
spew.Dump(naive) | |
buf, err := json.Marshal(naive) | |
if err != nil { | |
fmt.Println("this fails: ", err) | |
} | |
var fixed map[string]*JSONValue | |
err = yaml.Unmarshal([]byte(document), &fixed) | |
if err != nil { | |
panic(err) | |
} | |
fmt.Println("here's the custom data structure") | |
spew.Dump(fixed) | |
buf, err = json.Marshal(fixed) | |
if err != nil { | |
panic(err) | |
} | |
fmt.Println("this succeeds") | |
fmt.Println(string(buf)) | |
} | |
type JSONValue struct { | |
contains interface{} | |
} | |
func (j *JSONValue) UnmarshalYAML(unmarshal func(interface{}) error) error { | |
var object map[string]*JSONValue | |
err := unmarshal(&object) | |
if err == nil { | |
j.contains = object | |
return nil | |
} | |
var array []*JSONValue | |
err = unmarshal(&array) | |
if err == nil { | |
j.contains = array | |
return nil | |
} | |
var str string | |
err = unmarshal(&str) | |
if err == nil { | |
j.contains = str | |
return nil | |
} | |
var number float64 | |
err = unmarshal(&number) | |
if err == nil { | |
j.contains = number | |
return nil | |
} | |
var boolean bool | |
err = unmarshal(&boolean) | |
if err == nil { | |
j.contains = boolean | |
return nil | |
} | |
var null interface{} | |
err = unmarshal(&null) | |
if err == nil && null == nil { | |
j.contains = nil | |
return nil | |
} | |
return fmt.Errorf("No JSON suitable type found") | |
} | |
func (j *JSONValue) MarshalJSON() ([]byte, error) { | |
return json.Marshal(j.contains) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment