目前我正在映射一个服务的输出,比方说,它可以自由地为它的布尔类型交换0和false(以及1和true)。有没有办法为内置编码/ json unmarshal函数使用更宽松的解析器?我试过添加,字符串到json标签无济于事。
我想要的一个例子:
type MyType struct {
AsBoolean bool `json:"field1"`
AlsoBoolean bool `json:"field2"`
}
然后,给定输入json:
{
"field1" : true,
"field2" : 1
}
生成的结构将是:
obj := MyType{}
json_err := json.Unmarshal([]byte(input_json), &obj)
fmt.Printf("%v\n", obj.AsBoolean) //"true"
fmt.Printf("%v\n", obj.AlsoBoolean) //"true"
答案 0 :(得分:9)
结束使用特殊的"布尔"类型,以及我使用普通布尔的地方,交换了这个:
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
}
答案 1 :(得分:6)
谢谢Will Charzuck的回答,但是,除非我使用指针方法接收器,并且在函数体中设置指针的值,否则它对我不起作用。
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
}
答案 2 :(得分:0)
这是我的看法。万一您需要处理一些额外的情况。根据需要添加更多。
// so you know what's 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
}
在playground中查看。
我也被这样的人所认识:
// 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
}
如果您想变小:
// 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
}
在playground中查看此人。
答案 3 :(得分:0)
对于@Twitch Captian's的第三个示例,我发现string(b)
的结果导致txt
等于""1""
而不是我期望的"1"
。为了解决这个问题,我将字节数组解编为txt
,然后评估了"1" || "true"
// Bool allows 0/1 to also become boolean.
type Bool bool
func (bit *Bool) UnmarshalJSON(b []byte) error {
var txt string
err := json.Unmarshal(b, &txt)
if err != nil {
return err
}
*bit = Bool(txt == "1" || txt == "true")
return nil
}