diff --git a/cmd/json2csv/main.go b/cmd/json2csv/main.go index 9a73eb6..836af95 100644 --- a/cmd/json2csv/main.go +++ b/cmd/json2csv/main.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "log" "os" @@ -19,7 +18,7 @@ const ( ApplicationName = "json2csv" // Version is the version number of this application. - Version = "0.1.0" + Version = "0.1.1" ) var headerStyleTable = map[string]json2csv.KeyStyle{ @@ -145,13 +144,11 @@ func readJSONFile(filename string) (interface{}, error) { } func readJSON(r io.Reader) (interface{}, error) { - buf, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } + decoder := json.NewDecoder(r) + decoder.UseNumber() var data interface{} - if err := json.Unmarshal(buf, &data); err != nil { + if err := decoder.Decode(&data); err != nil { return nil, err } diff --git a/flatten.go b/flatten.go index 848c908..285faf1 100644 --- a/flatten.go +++ b/flatten.go @@ -1,6 +1,7 @@ package json2csv import ( + "encoding/json" "fmt" "reflect" "sort" @@ -9,6 +10,8 @@ import ( "github.com/yukithm/json2csv/jsonpointer" ) +var jsonNumberType = reflect.TypeOf(json.Number("")) + type mapKeys []reflect.Value func (k mapKeys) Len() int { return len(k) } @@ -51,6 +54,14 @@ func _flatten(out KeyValue, obj interface{}, key jsonpointer.JSONPointer) error value = value.Elem() } + if value.IsValid() { + vt := value.Type() + if vt.AssignableTo(jsonNumberType) { + out[key.String()] = value.Interface().(json.Number) + return nil + } + } + switch value.Kind() { case reflect.Map: _flattenMap(out, value, key) diff --git a/json2csv_test.go b/json2csv_test.go index cd466cb..8d2a063 100644 --- a/json2csv_test.go +++ b/json2csv_test.go @@ -1,11 +1,24 @@ package json2csv import ( + "bytes" "encoding/json" "reflect" "testing" ) +// Decode JSON with UseNumber option. +func json2obj(jsonstr string) (interface{}, error) { + r := bytes.NewReader([]byte(jsonstr)) + d := json.NewDecoder(r) + d.UseNumber() + var obj interface{} + if err := d.Decode(&obj); err != nil { + return nil, err + } + return obj, nil +} + var testJSON2CSVCases = []struct { json string expected []KeyValue @@ -17,8 +30,8 @@ var testJSON2CSVCases = []struct { {"id": 2, "name": "bar"} ]`, []KeyValue{ - {"/id": 1.0, "/name": "foo"}, - {"/id": 2.0, "/name": "bar"}, + {"/id": json.Number("1"), "/name": "foo"}, + {"/id": json.Number("2"), "/name": "bar"}, }, ``, }, @@ -28,8 +41,8 @@ var testJSON2CSVCases = []struct { {"id": 2, "name~b": "bar"} ]`, []KeyValue{ - {"/id": 1.0, "/name~1a": "foo"}, - {"/id": 2.0, "/name~0b": "bar"}, + {"/id": json.Number("1"), "/name~1a": "foo"}, + {"/id": json.Number("2"), "/name~0b": "bar"}, }, ``, }, @@ -39,8 +52,8 @@ var testJSON2CSVCases = []struct { {"id":2, "values":["x"]} ]`, []KeyValue{ - {"/id": 1.0, "/values/0": "a", "/values/1": "b"}, - {"/id": 2.0, "/values/0": "x"}, + {"/id": json.Number("1"), "/values/0": "a", "/values/1": "b"}, + {"/id": json.Number("2"), "/values/0": "x"}, }, ``, }, @@ -50,8 +63,8 @@ var testJSON2CSVCases = []struct { {"id":2, "values":["x"]} ]`, []KeyValue{ - {"/id": 1.0}, - {"/id": 2.0, "/values/0": "x"}, + {"/id": json.Number("1")}, + {"/id": json.Number("2"), "/values/0": "x"}, }, ``, }, @@ -61,8 +74,8 @@ var testJSON2CSVCases = []struct { {"id":2, "values":["x"]} ]`, []KeyValue{ - {"/id": 1.0}, - {"/id": 2.0, "/values/0": "x"}, + {"/id": json.Number("1")}, + {"/id": json.Number("2"), "/values/0": "x"}, }, ``, }, @@ -75,7 +88,7 @@ var testJSON2CSVCases = []struct { ] }`, []KeyValue{ - {"/id": 123.0, "/values/0/foo": "FOO", "/values/1/bar": "BAR"}, + {"/id": json.Number("123"), "/values/0/foo": "FOO", "/values/1/bar": "BAR"}, }, ``, }, @@ -89,6 +102,16 @@ var testJSON2CSVCases = []struct { []KeyValue{}, ``, }, + { + `{"large_int_value": 146163870300}`, + []KeyValue{{"/large_int_value": json.Number("146163870300")}}, + ``, + }, + { + `{"float_value": 146163870.300}`, + []KeyValue{{"/float_value": json.Number("146163870.300")}}, + ``, + }, {`"foo"`, nil, `Unsupported JSON structure.`}, {`123`, nil, `Unsupported JSON structure.`}, {`true`, nil, `Unsupported JSON structure.`}, @@ -96,8 +119,7 @@ var testJSON2CSVCases = []struct { func TestJSON2CSV(t *testing.T) { for caseIndex, testCase := range testJSON2CSVCases { - var obj interface{} - err := json.Unmarshal([]byte(testCase.json), &obj) + obj, err := json2obj(testCase.json) if err != nil { t.Fatal(err) }