How to decouple both 0 and false as bool from JSON

We are currently matching the output of a service that, say, liberally changes the values ​​0 and false (and 1 and true) for its boolean types. Is there a way to use a more permissible parser for the built-in encoding function / json unmarshal? I tried to add a string to json tags to no avail.

An example of what I want:

type MyType struct { AsBoolean bool `json:"field1"` AlsoBoolean bool `json:"field2"` } 

then, given json input:

 { "field1" : true, "field2" : 1 } 

the resulting structure will be:

 obj := MyType{} json_err := json.Unmarshal([]byte(input_json), &obj) fmt.Printf("%v\n", obj.AsBoolean) //"true" fmt.Printf("%v\n", obj.AlsoBoolean) //"true" 
+7
source share
3 answers

Ended up using a special β€œboolean” type, and where I used the usual bool, replaced for this:

 type ConvertibleBoolean bool func (bit ConvertibleBoolean) UnmarshalJSON(data []byte) error { asString := string(data) if asString == "1" || asString == "true" { bit = true } else if asString == "0" || asString == "false" { bit = false } else { return errors.New(fmt.Sprintf("Boolean unmarshal error: invalid input %s", asString)) } return nil } 
+9
source

Thanks to Will Charzuck for the answer, however, this did not work for me if I did not use the pointer method receiver and did not set the pointer value in the function body.

 type ConvertibleBoolean bool func (bit *ConvertibleBoolean) UnmarshalJSON(data []byte) error { asString := string(data) if asString == "1" || asString == "true" { *bit = true } else if asString == "0" || asString == "false" { *bit = false } else { return errors.New(fmt.Sprintf("Boolean unmarshal error: invalid input %s", asString)) } return nil } 
+6
source

This is my opinion. In case you need to deal with a few additional cases. Add more as needed.

 // so you know what needed. import ( "encoding/json" "strconv" "strings" ) // NumBool provides a container and unmarshalling for fields that may be // boolean or numbrs in the WebUI API. type NumBool struct { Val bool Num float64 } // UnmarshalJSON parses fields that may be numbers or booleans. func (f *NumBool) UnmarshalJSON(b []byte) (err error) { switch str := strings.ToLower(strings.Trim(string(b), '"')); str { case "true": f.Val = true case "false": f.Val = false default: f.Num, err = strconv.ParseFloat(str, 64) if f.Num > 0 { f.Val = true } } return err } 

I see it on the playground .

I was also known for something like this:

 // FlexBool provides a container and unmarshalling for fields that may be // boolean or strings in the Unifi API. type FlexBool struct { Val bool Txt string } // UnmarshalJSON method converts armed/disarmed, yes/no, active/inactive or 0/1 to true/false. // Really it converts ready, ok, up, t, armed, yes, active, enabled, 1, true to true. Anything else is false. func (f *FlexBool) UnmarshalJSON(b []byte) error { if f.Txt = strings.Trim(string(b), '"'); f.Txt == "" { f.Txt = "false" } f.Val = f.Txt == "1" || strings.EqualFold(f.Txt, "true") || strings.EqualFold(f.Txt, "yes") || strings.EqualFold(f.Txt, "t") || strings.EqualFold(f.Txt, "armed") || strings.EqualFold(f.Txt, "active") || strings.EqualFold(f.Txt, "enabled") || strings.EqualFold(f.Txt, "ready") || strings.EqualFold(f.Txt, "up") || strings.EqualFold(f.Txt, "ok") return nil } 

And if you want to go very small:

 // Bool allows 0/1 to also become boolean. type Bool bool func (bit *Bool) UnmarshalJSON(b []byte) error { txt := string(b) *bit = Bool(txt == "1" || txt == "true") return nil } 

Watch it on the playground .

0
source

Source: https://habr.com/ru/post/989166/


All Articles