如何将 JSON 中的 0 和 false 都解析为布尔值?

huangapple go评论82阅读模式
英文:

How to unmarshall both 0 and false as bool from JSON

问题

目前我正在映射一个服务的输出,假设该服务在布尔类型中自由地交换0和false(以及1和true)。有没有办法为内置的encoding/json unmarshal函数使用更宽松的解析器?我尝试了在json标签中添加",string",但没有成功。

以下是我想要的示例:

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"

请注意,以上代码是用于演示目的,实际使用时需要根据你的需求进行适当的修改。

英文:

Currently am mapping the output of a service that, lets say, liberally interchanges 0 and false (and 1 and true) for its boolean types. Is there a way to use a more permissive parser for the built in encoding/json unmarshal function? I've tried adding ,string to the json tags to no avail.

An example of what I'd want:

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

then, given input json:

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

the resulting struct would 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"

答案1

得分: 13

谢谢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
}
英文:

Thank you Will Charzuck for the answer, however, it did not work for me unless I used a pointer method receiver, and set the value of the pointer 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
}

答案2

得分: 12

最终使用了一个特殊的"boolean"类型,将原本使用的普通bool类型替换为以下代码:

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
}

这段代码定义了一个名为ConvertibleBoolean的类型,它是一个自定义的布尔类型。在UnmarshalJSON方法中,根据输入的JSON数据进行解析,将字符串"1"或"true"转换为true,将字符串"0"或"false"转换为false,其他情况则返回错误。

英文:

Ended up using a special "boolean" type, and where I was using a normal bool, swapped 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
}

答案3

得分: 6

这是我的看法。如果你需要处理一些额外的情况,可以添加更多。

// 为了让你知道需要什么。
import (
	"encoding/json"
	"strconv"
	"strings"
)

// NumBool 提供了一个容器和解析函数,用于处理可能是布尔值或数字的字段。
type NumBool struct {
	Val bool
	Num float64
}

// UnmarshalJSON 解析可能是数字或布尔值的字段。
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 提供了一个容器和解析函数,用于处理可能是布尔值或字符串的字段。
type FlexBool struct {
	Val bool
	Txt string
}

// UnmarshalJSON 方法将armed/disarmed、yes/no、active/inactive或0/1转换为true/false。
// 它将ready、ok、up、t、armed、yes、active、enabled、1、true转换为true。其他任何值都为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 允许0/1和"0"/"1"以及"true"/"false"(字符串)也可以转换为布尔值。
type Bool bool

func (bit *Bool) UnmarshalJSON(b []byte) error {
	// txt := string(b) // 原始版本,没有字符串。
	txt := string(bytes.Trim(b, `"`))
	*bit = Bool(txt == "1" || txt == "true")
	return nil
}

playground: bool/int/string中查看这个示例。旧版本在playground: bool/int中。

英文:

This is my take on it. In case you need something to deal with a few extra cases. Add more as needed.

// 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
}

See it in playground.

I've also been known to 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 real small:

// Bool allows 0/1 and "0"/"1" and "true"/"false" (strings) to also become boolean.
type Bool bool

func (bit *Bool) UnmarshalJSON(b []byte) error {
	// txt := string(b) // original, no strings.
	txt := string(bytes.Trim(b, `"`))
	*bit = Bool(txt == "1" || txt == "true")
	return nil
}

See this one in playground: bool/int/string.
The old version: playground: bool/int.

答案4

得分: 0

对于@Twitch Captian的第三个示例,我发现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
}
英文:

For @Twitch Captian's 3rd example, I found the result of string(b) caused txt to equal ""1"" instead of "1" as I expected. To remedy this I unmarshaled the byte array into txt, then evaluated the contents for "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
}

huangapple
  • 本文由 发表于 2015年6月16日 07:12:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/30856454.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定