I'm trying to unmarshal some json data I get from a web service. I have simplified the problem which is shown in the code below. My question is can I make version (c) in the code work..
I know it works for single number values as shown for "timestamp" by adding the option ",string" to the json annotation. But I can't figure out how or if this works for arrays of string encoded numbers too. (See "conversions" in the example json listed in the code)
package main
import (
"encoding/json"
"fmt"
)
//version (a)
type JsonData1 struct {
TimeStamp uint64 `json:"timestamp,string"`
Conversions [][2]string `json:"conversions"`
}
//version (b)
type JsonData2 struct {
TimeStamp uint64 `json:"timestamp,string"`
Conversions [][2]json.Number `json:"conversions"`
}
//version (c)
type JsonData3 struct {
TimeStamp uint64 `json:"timestamp,string"`
Conversions [][2]float32 `json:"conversions"`
}
const incomingJson string = `{"timestamp": "1407178369", "conversions": [["1.021", "2.124"], ["2.432", "3.923"], ["3.234", "5.001"]]}`
func main() {
var data1 JsonData1
if err1 := json.Unmarshal([]byte(incomingJson), &data1); err1 != nil {
fmt.Println("Error unmarshaling with struct JsonData1")
fmt.Println("--> ", err1.Error())
} else {
fmt.Println("Success unmarshaling with struct JsonData1")
fmt.Println("--> ", data1)
}
var data2 JsonData2
if err2 := json.Unmarshal([]byte(incomingJson), &data2); err2 != nil {
fmt.Println("Error unmarshaling with struct JsonData2")
fmt.Println("--> ", err2.Error())
} else {
fmt.Println("Success unmarshaling with struct JsonData2")
fmt.Println("--> ", data2)
}
var data3 JsonData3
if err3 := json.Unmarshal([]byte(incomingJson), &data3); err3 != nil {
fmt.Println("Error unmarshaling with struct JsonData3")
fmt.Println("--> ", err3.Error())
} else {
fmt.Println("Success unmarshaling with struct JsonData3")
fmt.Println("--> ", data3)
}
}
If i compile and run the code I get this output:
Success unmarshaling with struct JsonData1
--> {1407178369 [[1.021 2.124] [2.432 3.923] [3.234 5.001]]}
Success unmarshaling with struct JsonData2
--> {1407178369 [[1.021 2.124] [2.432 3.923] [3.234 5.001]]}
Error unmarshaling with struct JsonData3
--> json: cannot unmarshal string into Go value of type float32
You can run the code here: http://play.golang.org/p/4TC0IgCI8H
Is there a way to achieve unmarshaling into struct version (c)? Thanks for your help!
The easiest way I know to do this is to define a new type and then define UnmarshalJSON
for it:
type Conversions [][2]float64
func (c *Conversions) UnmarshalJSON(b []byte) error {
tmp := [][2]json.Number{}
if err := json.Unmarshal(b, &tmp); err != nil {
return err
}
*c = make(Conversions, len(tmp))
for i, a := range tmp {
var (
pair [2]float64
err error
)
pair[0], err = a[0].Float64()
if err != nil {
return err
}
pair[1], err = a[1].Float64()
if err != nil {
return err
}
(*c)[i] = pair
}
return nil
}
Playground , see version (d). This is not the most perfect way to do that and the algorithm can be improved to use less resources, but you get the idea.
If you put " around the numbers they are considered like string. In fact, in the first two structure you haven't any problem.
If you want to convert them into numeric type, use the correct method to do that: parse float
Here you can see how you can use ParseFloat: http://play.golang.org/p/XDuiF0FCQq
You can't do that since you pass them as strings, your best bet really is using json.Number
and write a function like:
func fval(n json.Number) float32 {
if f, err := n.Float64(); err == nil {
return float32(f)
}
return 0
}
.....
f := fval(data2.Conversions[0][0])
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.