Maison  >  Article  >  développement back-end  >  Annuler le marshal des clés JSON contenant des guillemets simples

Annuler le marshal des clés JSON contenant des guillemets simples

WBOY
WBOYavant
2024-02-14 15:12:09555parcourir

从包含单引号的 JSON 键解组

L'éditeur php Shinichi a introduit une technique intéressante, qui consiste à supprimer le marshal des clés JSON contenant des guillemets simples. Cette astuce peut aider les développeurs à être plus flexibles lors du traitement des données JSON et à éviter les erreurs d'analyse causées par l'inclusion de guillemets simples. En utilisant quelques astuces et fonctions simples, les développeurs peuvent facilement gérer cette situation et garantir une analyse et un traitement corrects des données JSON. Cette technique est très utile pour les développeurs qui traitent souvent des données JSON et peut améliorer l'efficacité du développement et la qualité du code.

Contenu de la question

Je suis très confus à ce sujet. J'ai besoin de charger des données sérialisées en json (à partir d'une base de données française) où certaines clés ont des guillemets simples.

Ceci est une version simplifiée :

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>)

Unmarshalling ne provoque pas d'erreur, mais le "prix d'achat" (p.cost) n'est pas analysé correctement.

Quand je désélectionne map[string]any la touche "prix d'achat" s'analyse comme je l'attends :

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>)

J'ai vérifié la json.marshal documentation sur le balisage des structures mais je n'ai trouvé aucun problème avec les données que j'essaie de traiter.

Est-ce que j'ai raté quelque chose d'évident ici ? Comment analyser les clés json contenant des guillemets simples à l'aide de balises struct ?

Merci beaucoup pour vos idées !

Solution de contournement

Je n'ai rien trouvé dans la documentation, mais l'encodeur json traite les guillemets simples comme des caractères réservés dans les noms de balises.

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
}

Je pense qu'il est raisonnable de poser la question ici. En attendant, vous devrez implémenter json.unmarshaler et/ou json.marshaler. C'est un début :

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
}

Essayez-le sur l'aire de jeux : https://www.php.cn/link/9b47b8678d84ea8a0f9fe6c4ec599918一个>

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer