web-dev-qa-db-fra.com

Comment obtenir les noms de champs json d'une structure dans golang?

Quel est le moyen d'obtenir les noms de champs JSON de cette structure?

type example struct {
    Id          int `json:"id"`
    CreatedAt   string `json:"created_at"`
    Tag         string `json:"tag"`
    Text        string `json:"text"`
    AuthorId    int `json:"author_id"`
}

J'essaie d'imprimer les champs avec cette fonction:

func (b example) PrintFields() {
    val := reflect.ValueOf(b)
    for i := 0; i < val.Type().NumField(); i++ {
        fmt.Println(val.Type().Field(i).Name)
    }
}

Bien sûr je reçois:

Id
CreatedAt
Tag
Text
AuthorId

Mais je voudrais quelque chose comme:

id
created_at
tag
text
author_id
12
lambher

Vous utilisez le type StructTag pour obtenir les balises. La documentation que j'ai liée contient des exemples, recherchez-les, mais votre code pourrait ressembler à quelque chose comme:

func (b example) PrintFields() {
    val := reflect.ValueOf(b)
    for i := 0; i < val.Type().NumField(); i++ {
        fmt.Println(val.Type().Field(i).Tag.Get("json"))
    }
}

NOTE Le format de balise json ne prend pas uniquement en charge les noms de champs, tels que omitempty ou string. Par conséquent, si vous avez besoin d'une approche prenant en compte cela également, vous devez apporter des améliorations supplémentaires à la fonction PrintFields:

  1. nous devons vérifier si la balise json est - (i.e. json:"-")
  2. nous devons vérifier si le nom existe et l'isoler

Quelque chose comme ça:

func (b example) PrintFields() {
    val := reflect.ValueOf(b)
    for i := 0; i < val.Type().NumField(); i++ {
        t := val.Type().Field(i)
        fieldName := t.Name

        if jsonTag := t.Tag.Get("json"); jsonTag != "" && jsonTag != "-" {
            if commaIdx := strings.Index(jsonTag, ","); commaIdx > 0 {
                fieldName = jsonTag[:commaIdx]
            }
        }


        fmt.Println(fieldName)
    }
}
14
ain

Au lieu d'utiliser StructField 's Name, vous pouvez utiliser Tag pour obtenir un objet StructTag . Voir: https://golang.org/pkg/reflect/#StructTag _

Ensuite, vous pouvez utiliser les méthodes StructTag's Get ou Lookup pour obtenir la balise json:

Utiliser Get:

func (b example) PrintFields() {
    val := reflect.ValueOf(b)
    for i := 0; i < val.Type().NumField(); i++ {
        // prints empty line if there is no json tag for the field
        fmt.Println(val.Type().Field(i).Tag.Get("json"))
    }
}

Utiliser Lookup:

func (b example) PrintFields() {
    val := reflect.ValueOf(b)
    for i := 0; i < val.Type().NumField(); i++ {
        // skips fields without json tag
        if tag, ok := val.Type().Field(i).Tag.Lookup("json"); ok {
            fmt.Println(tag)
        }
    }
}
4
jussius

Utilisation:

func (b example) PrintFields() {
    val := reflect.ValueOf(b)
    t := val.Type()
    for i := 0; i < t.NumField(); i++ {
        fmt.Println(t.Field(i).Tag.Get("json"))
    }
}

Voir dans terrain de jeux.

2
sadlil

Pas la Name que vous recherchez. Qu'est-ce que vous cherchez est la Tag

func (b example) PrintFields() {
    val := reflect.ValueOf(b)
    for i := 0; i < val.Type().NumField(); i++ {
        fmt.Println(val.Type().Field(i).Tag.Get("json"))
    }
}
1
Wendy Adi

une version mise à jour avec une interface générique en paramètre:

func PrintFields(b interface{}) {
    val := reflect.ValueOf(b)
    for i := 0; i < val.Type().NumField(); i++ {
        t := val.Type().Field(i)
        fieldName := t.Name

        if jsonTag := t.Tag.Get("json"); jsonTag != "" && jsonTag != "-" {
            // check for possible comma as in "...,omitempty"
            var commaIdx int
            if commaIdx = strings.Index(jsonTag, ","); commaIdx < 0 {
                commaIdx = len(jsonTag)
            }
            fieldName = jsonTag[:commaIdx]
        }
        fmt.Println(fieldName)
    }
}
0
ChuckM