Home  >  Article  >  Backend Development  >  Unmarshal from JSON keys containing single quotes

Unmarshal from JSON keys containing single quotes

WBOY
WBOYforward
2024-02-14 15:12:09497browse

从包含单引号的 JSON 键解组

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.

Question content

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!

Workaround

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!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete