kon*_*tin 7 json go unmarshalling
我正在解组到一个具有time.Time
名为 Foo 的字段的结构:
type AStructWithTime struct {
Foo time.Time `json:"foo"`
}
Run Code Online (Sandbox Code Playgroud)
我的期望是,解组后我会得到这样的结果:
var expectedStruct = AStructWithTime{
Foo: time.Date(2022, 9, 26, 21, 0, 0, 0, time.UTC),
}
Run Code Online (Sandbox Code Playgroud)
当使用纯 json 字符串时,这工作得很好:
func Test_Unmarshalling_DateTime_From_String(t *testing.T) {
jsonStrings := []string{
"{\"foo\": \"2022-09-26T21:00:00Z\"}", // trailing Z = UTC offset
"{\"foo\": \"2022-09-26T21:00:00+00:00\"}", // explicit zero offset
"{\"foo\": \"2022-09-26T21:00:00\u002b00:00\"}", // \u002b is an escaped '+'
}
for _, jsonString := range jsonStrings {
var deserializedStruct AStructWithTime
err := json.Unmarshal([]byte(jsonString), &deserializedStruct)
if err != nil {
t.Fatalf("Could not unmarshal '%s': %v", jsonString, err) // doesn't happen
}
if deserializedStruct.Foo.Unix() != expectedStruct.Foo.Unix() {
t.Fatal("Unmarshalling is erroneous") // doesn't happen
}
// works; no errors
}
}
Run Code Online (Sandbox Code Playgroud)
如果我将 json 数组中的相同对象解组到切片中,它也可以工作:
func Test_Unmarshalling_DateTime_From_Array(t *testing.T) {
// these are just the same objects as above, just all in one array instead of as single objects/dicts
jsonArrayString := "[{\"foo\": \"2022-09-26T21:00:00Z\"},{\"foo\": \"2022-09-26T21:00:00+00:00\"},{\"foo\": \"2022-09-26T21:00:00\u002b00:00\"}]"
var slice []AStructWithTime // and now I need to unmarshal into a slice
unmarshalErr := json.Unmarshal([]byte(jsonArrayString), &slice)
if unmarshalErr != nil {
t.Fatalf("Could not unmarshal array: %v", unmarshalErr)
}
for index, instance := range slice {
if instance.Foo.Unix() != expectedStruct.Foo.Unix() {
t.Fatalf("Unmarshalling failed for index %v: Expected %v but got %v", index, expectedStruct.Foo, instance.Foo)
}
}
// works; no errors
}
Run Code Online (Sandbox Code Playgroud)
现在,我使用从文件“test.json”读取的 JSON 进行相同的解组。它的内容是上面工作示例中的数组:
[
{
"foo": "2022-09-26T21:00:00Z"
},
{
"foo": "2022-09-26T21:00:00+00:00"
},
{
"foo": "2022-09-26T21:00:00\u002b00:00"
}
]
Run Code Online (Sandbox Code Playgroud)
代码是:
func Test_Unmarshalling_DateTime_From_File(t *testing.T) {
fileName := "test.json"
fileContent, readErr := os.ReadFile(filepath.FromSlash(fileName))
if readErr != nil {
t.Fatalf("Could not read file %s: %v", fileName, readErr)
}
if fileContent == nil {
t.Fatalf("File %s must not be empty", fileName)
}
var slice []AStructWithTime
unmarshalErr := json.Unmarshal(fileContent, &slice)
if unmarshalErr != nil {
// ERROR HAPPENS HERE
// Could not unmarshal file content test.json: parsing time "\"2022-09-26T21:00:00\\u002b00:00\"" as "\"2006-01-02T15:04:05Z07:00\"": cannot parse "\\u002b00:00\"" as "Z07:00"
t.Fatalf("Could not unmarshal file content %s: %v", fileName, unmarshalErr)
}
for index, instance := range slice {
if instance.Foo.Unix() != expectedStruct.Foo.Unix() {
t.Fatalf("Unmarshalling failed for index %v in file %s. Expected %v but got %v", index, fileName, expectedStruct.Foo, instance.Foo)
}
}
}
Run Code Online (Sandbox Code Playgroud)
由于转义了“+”,它失败了。
将时间“2022-09-26T21:00:00\u002b00:00”解析为“2006-01-02T15:04:05Z07:00”:无法将“\u002b00:00”解析为“Z07:00” ”
问题:为什么从文件读取 time.Time 字段时解组会失败,但从相同字符串读取相同 json 时解组却可以?
我相信这是一个错误encoding/json
。
https://www.json.org上的 JSON 语法和RFC 8259 第 7 节:字符串中的 IETF JSON 定义都规定 JSON 字符串可以包含 Unicode 转义序列:
\n\n\n7. 弦乐
\n字符串的表示形式类似于 C\n 系列编程语言中使用的约定。字符串以引号\n开头和结尾。所有 Unicode 字符都可以放在引号内,\n除了必须转义的字符:引号、反向\n斜线和控制字符(U+0000 到 U+001F)。
\n任何字符都可以被转义。如果字符位于基本\n多语言平面(U+0000 到 U+FFFF)中,则它可以表示为\n六个字符序列:反斜线,后跟小写字母\nu,后跟四个十六进制数字对字符的代码点进行编码。十六进制字母 A 到 F 可以是大写或小写。\n因此,例如,仅包含单个反斜线\n字符的字符串可以表示为“\\u005C”。
\n。。。
\n为了转义不在基本多语言平面中的扩展字符,该字符被表示为 12 个字符的序列,并对 UTF-16 代理项对进行编码。因此,例如,仅包含 G 谱号字符 (U+1D11E) 的字符串可以表示为“\\uD834\\uDD1E”。
\nRun Code Online (Sandbox Code Playgroud)\n\nstring = quotation-mark *char quotation-mark\n\nchar = unescaped /\n escape (\n %x22 / ; " quotation mark U+0022\n %x5C / ; \\ reverse solidus U+005C\n %x2F / ; / solidus U+002F\n %x62 / ; b backspace U+0008\n %x66 / ; f form feed U+000C\n %x6E / ; n line feed U+000A\n %x72 / ; r carriage return U+000D\n %x74 / ; t tab U+0009\n %x75 4HEXDIG ) ; uXXXX U+XXXX\n\nescape = %x5C ; \\\n\nquotation-mark = %x22 ; "\n\nunescaped = %x20-21 / %x23-5B / %x5D-10FFFF\n\n
原始帖子中的 JSON 文档
\n{\n "foo": "2022-09-26T21:00:00\\u002b00:00"\n} \n
Run Code Online (Sandbox Code Playgroud)\n使用 Node.js 在 Node.js 中完美解析和反序列化JSON.parse()
。
这是演示该错误的示例:
\npackage main\n\nimport (\n "encoding/json"\n "fmt"\n "time"\n)\n\nvar document []byte = []byte(`\n{\n "value": "2022-09-26T21:00:00\\u002b00:00"\n}\n`)\n\nfunc main() {\n\n deserializeJsonAsTime()\n\n deserializeJsonAsString()\n\n}\n\nfunc deserializeJsonAsTime() {\n fmt.Println("")\n fmt.Println("Deserializing JSON as time.Time ...")\n\n type Widget struct {\n Value time.Time `json: "value"`\n }\n\n expected := Widget{\n Value: time.Date(2022, 9, 26, 21, 0, 0, 0, time.UTC),\n }\n actual := Widget{}\n err := json.Unmarshal(document, &actual)\n\n switch {\n case err != nil:\n fmt.Println("Error deserializing JSON as time.Time")\n fmt.Println(err)\n case actual.Value != expected.Value:\n fmt.Printf("Unmarshalling failed: expected %v but got %v\\n", expected.Value, actual.Value)\n default:\n fmt.Println("Sucess")\n }\n\n}\n\nfunc deserializeJsonAsString() {\n fmt.Println("")\n fmt.Println("Deserializing JSON as string ...")\n\n type Widget struct {\n Value string `json: "value"`\n }\n\n expected := Widget{\n Value: "2022-09-26T21:00:00+00:00",\n }\n actual := Widget{}\n err := json.Unmarshal(document, &actual)\n\n switch {\n case err != nil:\n fmt.Println("Error deserializing JSON as string")\n fmt.Println(err)\n case actual.Value != expected.Value:\n fmt.Printf("Unmarshalling failed: expected %v but got %v\\n", expected.Value, actual.Value)\n default:\n fmt.Println("Sucess")\n }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n当运行 \xe2\x80\x94 时,请参阅https://goplay.tools/snippet/fHQQVJ8GfPp \xe2\x80\x94 我们得到:
\npackage main\n\nimport (\n "encoding/json"\n "fmt"\n "time"\n)\n\nvar document []byte = []byte(`\n{\n "value": "2022-09-26T21:00:00\\u002b00:00"\n}\n`)\n\nfunc main() {\n\n deserializeJsonAsTime()\n\n deserializeJsonAsString()\n\n}\n\nfunc deserializeJsonAsTime() {\n fmt.Println("")\n fmt.Println("Deserializing JSON as time.Time ...")\n\n type Widget struct {\n Value time.Time `json: "value"`\n }\n\n expected := Widget{\n Value: time.Date(2022, 9, 26, 21, 0, 0, 0, time.UTC),\n }\n actual := Widget{}\n err := json.Unmarshal(document, &actual)\n\n switch {\n case err != nil:\n fmt.Println("Error deserializing JSON as time.Time")\n fmt.Println(err)\n case actual.Value != expected.Value:\n fmt.Printf("Unmarshalling failed: expected %v but got %v\\n", expected.Value, actual.Value)\n default:\n fmt.Println("Sucess")\n }\n\n}\n\nfunc deserializeJsonAsString() {\n fmt.Println("")\n fmt.Println("Deserializing JSON as string ...")\n\n type Widget struct {\n Value string `json: "value"`\n }\n\n expected := Widget{\n Value: "2022-09-26T21:00:00+00:00",\n }\n actual := Widget{}\n err := json.Unmarshal(document, &actual)\n\n switch {\n case err != nil:\n fmt.Println("Error deserializing JSON as string")\n fmt.Println(err)\n case actual.Value != expected.Value:\n fmt.Printf("Unmarshalling failed: expected %v but got %v\\n", expected.Value, actual.Value)\n default:\n fmt.Println("Sucess")\n }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n由于反序列化包含 Unicode 转义序列的 JSON 字符串会产生string
正确/预期的结果 \xe2\x80\x94 转义序列被转换为预期的符文/字节序列 \xe2\x80\x94 问题似乎在于处理代码反序列化为time.Time
(它似乎没有反序列化为字符串,然后将字符串值解析为time.Time
.
归档时间: |
|
查看次数: |
1360 次 |
最近记录: |