使用 \u0000 \x00 转到 json.Unmarshal 键
Go json.Unmarshal key with \u0000 \x00
这是 Go playground link.
基本上我的JSON字符串键中有一些特殊字符('\u0000'
):
var j = []byte(`{"Page":1,"Fruits":["5","6"],"\u0000*\u0000_errorMessages":{"x":"123"},"*_successMessages":{"ok":"hi"}}`)
我想将其解组为一个结构:
type Response1 struct {
Page int
Fruits []string
Msg interface{} `json:"*_errorMessages"`
Msg1 interface{} `json:"\u0000*\u0000_errorMessages"`
Msg2 interface{} `json:"\u0000*\u0000_errorMessages"`
Msg3 interface{} `json:"[=12=]*[=12=]_errorMessages"`
Msg4 interface{} `json:"\0*\0_errorMessages"`
Msg5 interface{} `json:"\x00*\x00_errorMessages"`
Msg6 interface{} `json:"\x00*\x00_errorMessages"`
SMsg interface{} `json:"*_successMessages"`
}
我尝试了很多,但没有用。
这 link 可能会帮助 golang.org/src/encoding/json/encode_test.go。
您不能这样做,因为:http://golang.org/ref/spec#Struct_types
但是您可以解组为 map[string]interface{}
,然后通过 regexp.
检查该对象的字段名称
我认为结构标签不可能做到这一点。您可以做的最好的事情是将其解组为 map[string]interface{}
,然后手动获取值:
var b = []byte(`{"\u0000abc":42}`)
var m map[string]interface{}
err := json.Unmarshal(b, &m)
if err != nil {
panic(err)
}
fmt.Println(m, m["\x00abc"])
简答:与当前json
implementation it is not possible using only struct tags.
注意:这是一个实现限制,而不是规范限制。 (这是json
包实现的限制,不是struct tags specification的限制。)
一些背景:您使用 raw string literal:
指定了标签
The value of a raw string literal is the string composed of the uninterpreted (implicitly UTF-8-encoded) characters between the quotes...
因此编译器.
不会在原始字符串文字的内容中发生转义或取消引用
引用自reflect.StructTag
的结构标签值约定:
By convention, tag strings are a concatenation of optionally space-separated key:"value" pairs. Each key is a non-empty string consisting of non-control characters other than space (U+0020 ' '), quote (U+0022 '"'), and colon (U+003A ':'). Each value is quoted using U+0022 '"' characters and Go string literal syntax.
这意味着按照惯例,标签值是由空格分隔的 (key:"value") 对列表。键有很多限制,但值可以是任何东西,值(应该)使用 "Go string literal syntax",这意味着这些 值将在运行时从代码 中取消引用(通过调用 strconv.Unquote()
, called from StructTag.Get()
, in source file reflect/type.go
,当前行 #809)。
所以不需要双引号。查看您的简化示例:
type Response1 struct {
Page int
Fruits []string
Msg interface{} `json:"\u0000_abc"`
}
现在代码如下:
t := reflect.TypeOf(Response1{})
fmt.Printf("%#v\n", t.Field(2).Tag)
fmt.Printf("%#v\n", t.Field(2).Tag.Get("json"))
打印:
"json:\"\u0000_abc\""
"\x00_abc"
如您所见,json
键的值部分是 "\x00_abc"
,因此它正确包含零字符。
但是 json
包将如何使用它?
json
包使用 StructTag.Get()
(from the reflect
package), exactly what we did. You can see it in the json/encode.go
源文件 typeFields()
函数返回的值,当前行 #1032。到目前为止一切顺利。
然后它调用未导出的 json.parseTag()
函数,在 json/tags.go
源文件中,当前行 #17。这将截断逗号后的部分(变成 "tag options")。
最后 json.isValidTag()
函数在源文件 json/encode.go
, currently line #731. This function checks the runes of the passed string
, and (besides a set of pre-defined allowed characters "!#$%&()*+-./:<=>?@[]^_{|}~ "
) rejects everything that is not a unicode letter or digit (as defined by unicode.IsLetter()
and unicode.IsDigit()
):
中用之前的值调用
if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
return false
}
'\u0000'
不是预定义的允许字符的一部分,您现在可以猜到,它既不是字母也不是数字:
// Following code prints "INVALID":
c := '\u0000'
if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
fmt.Println("INVALID")
}
并且由于 isValidTag()
returns false
,name
(这是 json
键的值,没有 "tag options"部分) 将被丢弃 (name = ""
) 而不会被使用。因此,将找不到包含 unicode 零的结构字段的匹配项。
对于替代解决方案,请使用 map
或自定义 json.Unmarshaler
or use json.RawMessage
。
但我强烈反对使用如此难看的 json 键。我知道你可能只是想解析这样的 json 响应,它可能超出你的范围,但你应该反对使用这些密钥,因为它们只会在以后引起更多问题(例如,如果存储在数据库中,通过检查记录很难发现其中有 '\u0000'
个字符,因为它们可能显示为空)。
这是 Go playground link.
基本上我的JSON字符串键中有一些特殊字符('\u0000'
):
var j = []byte(`{"Page":1,"Fruits":["5","6"],"\u0000*\u0000_errorMessages":{"x":"123"},"*_successMessages":{"ok":"hi"}}`)
我想将其解组为一个结构:
type Response1 struct {
Page int
Fruits []string
Msg interface{} `json:"*_errorMessages"`
Msg1 interface{} `json:"\u0000*\u0000_errorMessages"`
Msg2 interface{} `json:"\u0000*\u0000_errorMessages"`
Msg3 interface{} `json:"[=12=]*[=12=]_errorMessages"`
Msg4 interface{} `json:"\0*\0_errorMessages"`
Msg5 interface{} `json:"\x00*\x00_errorMessages"`
Msg6 interface{} `json:"\x00*\x00_errorMessages"`
SMsg interface{} `json:"*_successMessages"`
}
我尝试了很多,但没有用。 这 link 可能会帮助 golang.org/src/encoding/json/encode_test.go。
您不能这样做,因为:http://golang.org/ref/spec#Struct_types
但是您可以解组为 map[string]interface{}
,然后通过 regexp.
我认为结构标签不可能做到这一点。您可以做的最好的事情是将其解组为 map[string]interface{}
,然后手动获取值:
var b = []byte(`{"\u0000abc":42}`)
var m map[string]interface{}
err := json.Unmarshal(b, &m)
if err != nil {
panic(err)
}
fmt.Println(m, m["\x00abc"])
简答:与当前json
implementation it is not possible using only struct tags.
注意:这是一个实现限制,而不是规范限制。 (这是json
包实现的限制,不是struct tags specification的限制。)
一些背景:您使用 raw string literal:
指定了标签The value of a raw string literal is the string composed of the uninterpreted (implicitly UTF-8-encoded) characters between the quotes...
因此编译器.
不会在原始字符串文字的内容中发生转义或取消引用引用自reflect.StructTag
的结构标签值约定:
By convention, tag strings are a concatenation of optionally space-separated key:"value" pairs. Each key is a non-empty string consisting of non-control characters other than space (U+0020 ' '), quote (U+0022 '"'), and colon (U+003A ':'). Each value is quoted using U+0022 '"' characters and Go string literal syntax.
这意味着按照惯例,标签值是由空格分隔的 (key:"value") 对列表。键有很多限制,但值可以是任何东西,值(应该)使用 "Go string literal syntax",这意味着这些 值将在运行时从代码 中取消引用(通过调用 strconv.Unquote()
, called from StructTag.Get()
, in source file reflect/type.go
,当前行 #809)。
所以不需要双引号。查看您的简化示例:
type Response1 struct {
Page int
Fruits []string
Msg interface{} `json:"\u0000_abc"`
}
现在代码如下:
t := reflect.TypeOf(Response1{})
fmt.Printf("%#v\n", t.Field(2).Tag)
fmt.Printf("%#v\n", t.Field(2).Tag.Get("json"))
打印:
"json:\"\u0000_abc\""
"\x00_abc"
如您所见,json
键的值部分是 "\x00_abc"
,因此它正确包含零字符。
但是 json
包将如何使用它?
json
包使用 StructTag.Get()
(from the reflect
package), exactly what we did. You can see it in the json/encode.go
源文件 typeFields()
函数返回的值,当前行 #1032。到目前为止一切顺利。
然后它调用未导出的 json.parseTag()
函数,在 json/tags.go
源文件中,当前行 #17。这将截断逗号后的部分(变成 "tag options")。
最后 json.isValidTag()
函数在源文件 json/encode.go
, currently line #731. This function checks the runes of the passed string
, and (besides a set of pre-defined allowed characters "!#$%&()*+-./:<=>?@[]^_{|}~ "
) rejects everything that is not a unicode letter or digit (as defined by unicode.IsLetter()
and unicode.IsDigit()
):
if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
return false
}
'\u0000'
不是预定义的允许字符的一部分,您现在可以猜到,它既不是字母也不是数字:
// Following code prints "INVALID":
c := '\u0000'
if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
fmt.Println("INVALID")
}
并且由于 isValidTag()
returns false
,name
(这是 json
键的值,没有 "tag options"部分) 将被丢弃 (name = ""
) 而不会被使用。因此,将找不到包含 unicode 零的结构字段的匹配项。
对于替代解决方案,请使用 map
或自定义 json.Unmarshaler
or use json.RawMessage
。
但我强烈反对使用如此难看的 json 键。我知道你可能只是想解析这样的 json 响应,它可能超出你的范围,但你应该反对使用这些密钥,因为它们只会在以后引起更多问题(例如,如果存储在数据库中,通过检查记录很难发现其中有 '\u0000'
个字符,因为它们可能显示为空)。