php editor Shinichi introduced an interesting technique to unmarshal from JSON keys containing single quotes. This tip can help developers be more flexible when processing JSON data and avoid parsing errors caused by the inclusion of single quotes. By using some simple tricks and functions, developers can easily handle this situation and ensure correct parsing and processing of JSON data. This technique is very useful for developers who often deal with JSON data, and can improve development efficiency and code quality.
I am very confused about this. I need to load some data serialized in json (from a French database) where some keys have single quotes.
This is a simplified version:
package main import ( "encoding/json" "fmt" ) type product struct { name string `json:"nom"` cost int64 `json:"prix d'achat"` } func main() { var p product err := json.unmarshal([]byte(`{"nom":"savon", "prix d'achat": 170}`), &p) fmt.printf("product cost: %d\nerror: %s\n", p.cost, err) } // product cost: 0 // error: %!s(<nil>)
Unmarshaling does not result in an error, but "prix d'achat" (p.cost
) is not parsed correctly.
When I unmarshal to map[string]any
, the "prix d'achat" key parses as I expect:
package main import ( "encoding/json" "fmt" ) func main() { blob := map[string]any{} err := json.Unmarshal([]byte(`{"nom":"savon", "prix d'achat": 170}`), &blob) fmt.Printf("blob: %f\nerror: %s\n", blob["prix d'achat"], err) } // blob: 170.000000 // error: %!s(<nil>)
I checked the json.marshal
documentation on struct tags but can't find any issues with the data I'm trying to process.
Am I missing something obvious here? How to parse json keys containing single quotes using struct tags?
Thank you very much for your insights!
I didn't find anything in the documentation, but the json encoder treats single quotes as reserved characters in tag names.
func isvalidtag(s string) bool { if s == "" { return false } for _, c := range s { switch { case strings.containsrune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", c): // backslash and quote chars are reserved, but // otherwise any punctuation chars are allowed // in a tag name. case !unicode.isletter(c) && !unicode.isdigit(c): return false } } return true }
I think it's reasonable to ask the question here. In the meantime, you will have to implement json.unmarshaler and/or json.marshaler. This is a start:
func (p *Product) UnmarshalJSON(b []byte) error { type product Product // revent recursion var _p product if err := json.Unmarshal(b, &_p); err != nil { return err } *p = Product(_p) return unmarshalFieldsWithSingleQuotes(p, b) } func unmarshalFieldsWithSingleQuotes(dest interface{}, b []byte) error { // Look through the JSON tags. If there is one containing single quotes, // unmarshal b again, into a map this time. Then unmarshal the value // at the map key corresponding to the tag, if any. var m map[string]json.RawMessage t := reflect.TypeOf(dest).Elem() v := reflect.ValueOf(dest).Elem() for i := 0; i < t.NumField(); i++ { tag := t.Field(i).Tag.Get("json") if !strings.Contains(tag, "'") { continue } if m == nil { if err := json.Unmarshal(b, &m); err != nil { return err } } if j, ok := m[tag]; ok { if err := json.Unmarshal(j, v.Field(i).Addr().Interface()); err != nil { return err } } } return nil }
Try it on the playground: https://www.php.cn/link/9b47b8678d84ea8a0f9fe6c4ec599918一个>
The above is the detailed content of Unmarshal from JSON keys containing single quotes. For more information, please follow other related articles on the PHP Chinese website!