Home > Blockchain >  strconv.Unquote does not remove escaped json characters, unmarshall fails in Go
strconv.Unquote does not remove escaped json characters, unmarshall fails in Go

Time:07-01

I am parsing rather simple json where the slash in the date format string is escaped when it arrives in response.

however, when you try to unmarshall the string, it fails on "invalid syntax" error. So I googled and we should use strconv.Unquote to replace the escaped characters first. Did that, and now the unquote function fails on the "unknown escape" error. However JSON RFC 8259 shows it is a valid case. So why valid JSON is causing failures in Go unmarshaller?

This is the simple JSON

{
   "created_at": "6\/30\/2022 21:51:49"
}
    var dst string
    err := json.Unmarshal([]byte("6\/30\/2022 21:51:49"), dst) // this fails on ivnalid quote
    fmt.Println(dst, err)

    s, err := strconv.Unquote(`"6\/30\/2022 21:51:49"`) // this fails on ivnalid syntax
    fmt.Println(s, err)

How does one proceed with such cases when the JSON is valid, but none of the built-in functions of Go actually parse it? What is the right way, apart from writing simple find and replace pattern in json []byte manually?

EDIT: ok I think I should have asked a better question or provided a specific example from the scenario rather than just a portion of it. Garbage in garbage out, my fault. Here is the thing. Let's say we have the specific, non standard time format like in the above json example.

{
   "created_at": "6\/30\/2022 21:51:49"
}

I need to parse it into the struct with go time type. Because the standard parser for time would fail for that format I create a custom type.

type Request struct {
    CreatedAt Time `json:"created_at"`
}

type Time time.Time

unc (d *Time) UnmarshalJSON(b []byte) error {
    s := strings.Trim(string(b), "\"")
    parse, err := time.Parse("1/2/2006 15:04:05", s) // this fails because of the escaped backslashes
    if err != nil {
        return err
    }
    *d = Time(parse)
    return nil
}

Here is an example in Playground: https://go.dev/play/p/bE3AWQeV-ug

panic: parsing time "6\\/30\\/2022 21:51:49" as "1/2/2006 15:04:05": cannot parse "\\/30\\/2022 21:51:49" as "/"

This is the reason I am trying to put the Unquote into the custom unmarshal function, but that is not the right approach as it was already pointed out. How does the default string json unmarshaller for example removes those escaped slashes? Oh and I have no control about the side that writes the json, it comes in with single escaped slashes like that in []byte from *http.Response

CodePudding user response:

Unquote is designed for cases when you have a double quoted string like "\"My name\"", you don't really need that in this case.

The problem with that code is that you're trying to unmarshal a byte slice that isn't JSON. You're also unmarshaling into an string which isn't going to work. You need to unmarshal into a struct that has json tags or unmarshal into a map.

var dest map[string]string

someJsonString := `{
"created_at": "6\/30\/2022 21:51:49"
}`


err := json.Unmarshal([]byte(someJsonString), &dest)

if err != nil {     
    panic(err)
}

fmt.Println(dest)

if you wanted to do Unmarshal into a struct, you can do it like so

type SomeStruct struct {
    CreatedAt string `json:"created_at"`
}

someJsonString := `{
   "created_at": "6\/30\/2022 21:51:49"
}`

var data SomeStruct

err := json.Unmarshal([]byte(someJsonString), &data)

if err != nil {
    panic(err)
}

fmt.Println(data)

CodePudding user response:

Go has a great built-in function to convert a JSON string to a Go string: json.Unmarshal. Here is how you can integrate it with a custom UnmarshalJSON method:

func (d *Time) UnmarshalJSON(b []byte) error {
    var s string
    if err := json.Unmarshal(b, &s); err != nil {
        return err
    }
    // Remove this line: s := strings.Trim(string(b), "\"")
    // The rest of the code is unchanged
  • Related