Maison >développement back-end >Golang >Golang Unmarshal avec différents ensembles de balises structurelles

Golang Unmarshal avec différents ensembles de balises structurelles

WBOY
WBOYavant
2024-02-09 23:10:09562parcourir

具有不同结构标签集的 Golang Unmarshal

L'éditeur php Baicao vous présente aujourd'hui une puissante fonctionnalité Golang - Unmarshal avec différents ensembles de balises structurelles. Dans la programmation Golang, Unmarshal est un processus de conversion de données en structure. Cependant, lorsque notre source de données contient différents ensembles de balises structurelles, la méthode traditionnelle Unmarshal peut ne pas répondre aux besoins. Par conséquent, nous devons utiliser Golang Unmarshal avec un ensemble différent de balises structurelles pour obtenir cette fonctionnalité. Cet article présentera en détail l'utilisation et les précautions de cette fonctionnalité. Explorons ensemble !

Contenu de la question

J'utilise l'API d'un outil tiers qui a des noms de clés personnalisés dans son json. Je dois également utiliser l'API sur deux environnements différents (production et staging). Malheureusement, les champs personnalisés de l'API ont des noms de clé différents dans les deux environnements pour représenter les mêmes données. Dans l'exemple ci-dessous, la clé json custom-1 与暂存环境中的 json 密钥 custom-7 完全相同。我想将其中任何一个解组到相同的数据结构中,但我不知道如何进行。我希望有一种方法可以以某种方式覆盖 json.unmarshal() 函数用于在 prod 上使用 json 的标签,但在暂存时使用 jsonstaging 。对我来说,这是最有意义且最简单的解决方案。我猜我必须为我的 jsonobj 类型编写一个自定义 unmarshaljson(data []byte) error fonctionne en production, mais encore une fois, je ne sais pas comment obtenir le comportement souhaité dans une fonction personnalisée. Quelqu'un peut-il m'orienter dans la bonne direction, de la documentation ou des exemples que je peux utiliser ?

package main

import (
    "encoding/json"
    "fmt"
)

type jsonobj struct {
    id   string `json:"custom-1" jsonstaging:"custom-7"`
    desc string `json:"custom-2" jsonstaging:"custom-8"`
}

func (i jsonobj) string() string {
    return fmt.sprintf(`{ id: "%s", desc: "%s" }`, i.id, i.desc)
}

func main() {
    var jsonprod = `{
        "custom-1": "object-a",
        "custom-2": "test"
    }
    `
    var jsonstaging = `{
        "custom-7": "object-a",
        "custom-8": "test"
    }
    `

    var jsonobjprod jsonobj
    var jsonobjstaging jsonobj

    json.unmarshal([]byte(jsonprod), &jsonobjprod)
    json.unmarshal([]byte(jsonstaging), &jsonobjstaging)

    fmt.println("production: ", jsonobjprod)
    fmt.println("staging: ", jsonobjstaging)
}

Quand je l'exécute avec go run, j'obtiens

production:  { id: "object-a", desc: "test" }
staging:  { id: "", desc: "" }

C'est ce qu'attend mon code actuel, mais j'aimerais l'obtenir

Production:  { Id: "object-a", Desc: "test" }
Staging:  { Id: "object-a", Desc: "test" }

Je ne peux pas modifier l'API de l'environnement de préparation ou de production.

J'ai essayé de créer différentes structures et interfaces, mais à mesure que le nombre de champs (et de clés JSON personnalisées) augmente (et ils grandissent), cela semble être un cauchemar de maintenance. S'il vous plaît, aidez-moi si c'est le seul moyen, je ne l'ai pas non plus fait fonctionner avant de décider que ce n'était peut-être pas le bon chemin.

Solution de contournement

Pour référence future, si quelqu'un veut faire cela, je pense avoir trouvé un moyen en utilisant le package reflect intégré.

Tout d'abord, vous devez utiliser la fonction json.unmarshal(), mais remplissez map[string] 接口{} à la place de l'objet que vous souhaitez construire.

Ensuite, j'ai écrit une fonction qui récupère l'environnement et la carte. Il parcourt tous les champs de la nouvelle instance de l'objet réel (pas la carte) et obtient l'étiquette de l'environnement que vous utilisez. Il définit ensuite les champs du nouvel objet sur objmap[tag].(f215d538f93896d2fa3ea4137b420524). Après avoir défini tous les champs avec des étiquettes, le nouvel objet sera renvoyé.

Voici mon code de travail :

package main

import (
    "encoding/json"
    "fmt"
    "reflect"
)

const (
    StagingStructTag    = "jsonStaging"
    ProductionStructTag = "json"
)

type jsonObj struct {
    Id   string `json:"custom-1" jsonStaging:"custom-7"`
    Desc string `json:"custom-2" jsonStaging:"custom-8"`
}

func (i jsonObj) String() string {
    return fmt.Sprintf(`{ Id: "%s", Desc: "%s" }`, i.Id, i.Desc)
}

func main() {
    var jsonProd = `{
        "custom-1": "object-a",
        "custom-2": "test"
    }
    `
    var jsonStaging = `{
        "custom-7": "object-a",
        "custom-8": "test"
    }
    `

    var env string = "staging"
    var jsonObjProd jsonObj
    var jsonObjStaging jsonObj
    var jsonObjProdMap map[string]interface{}
    var jsonObjStagingMap map[string]interface{}

    json.Unmarshal([]byte(jsonStaging), &jsonObjStagingMap)
    json.Unmarshal([]byte(jsonProd), &jsonObjProdMap)

    jsonObjStaging = BuildJsonObj(env, jsonObjStagingMap)
    env = "production"
    jsonObjProd = BuildJsonObj(env, jsonObjProdMap)

    fmt.Println("Production: ", jsonObjProd)
    fmt.Println("Staging:    ", jsonObjStaging)
}

func BuildJsonObj(env string, objMap map[string]interface{}) jsonObj {
    var obj jsonObj
    var t reflect.Type = reflect.TypeOf(obj)
    var structTagName string

    if env == "staging" {
        structTagName = StagingStructTag

    } else if env == "production" {
        structTagName = ProductionStructTag
    }

    for i := 0; i < t.NumField(); i++ {
        var field reflect.StructField = t.Field(i)
        var tag string
        var ok bool

        if tag, ok = field.Tag.Lookup(structTagName); ok {
            switch field.Name {
            case "Id":
                obj.Id = objMap[tag].(string)
            case "Desc":
                obj.Desc = objMap[tag].(string)
            }
        }

    }
    return obj
}

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