print handling golang deserialize json go

handling - print json golang



Eliminando campos de struct u ocultándolos en JSON Response (8)

Creé una API en Go que, al ser llamada, realiza una consulta, crea una instancia de una estructura y luego codifica esa estructura como JSON antes de enviar de vuelta a la persona que llama. Ahora me gustaría permitir que la persona que llama pueda seleccionar los campos específicos que desea que devuelvan al pasar en un parámetro GET de "campos".

Esto significa que dependiendo de los valores de los campos, mi estructura cambiaría. ¿Hay alguna forma de eliminar campos de una estructura? ¿O al menos ocultarlos en la respuesta JSON de forma dinámica? (Nota: A veces tengo valores vacíos, así que la etiqueta JSON omitEmpty no funcionará aquí). Si ninguno de estos es posible, ¿hay alguna sugerencia sobre una mejor manera de manejar esto? Gracias por adelantado.

Una versión más pequeña de las estructuras que estoy usando están debajo:

type SearchResult struct { Date string `json:"date"` IdCompany int `json:"idCompany"` Company string `json:"company"` IdIndustry interface{} `json:"idIndustry"` Industry string `json:"industry"` IdContinent interface{} `json:"idContinent"` Continent string `json:"continent"` IdCountry interface{} `json:"idCountry"` Country string `json:"country"` IdState interface{} `json:"idState"` State string `json:"state"` IdCity interface{} `json:"idCity"` City string `json:"city"` } //SearchResult type SearchResults struct { NumberResults int `json:"numberResults"` Results []SearchResult `json:"results"` } //type SearchResults

Luego codifico y genero la respuesta de esta manera:

err := json.NewEncoder(c.ResponseWriter).Encode(&msg)


Acabo de publicar el sheriff , que transforma las estructuras en un mapa basado en etiquetas anotadas en los campos de la estructura. A continuación, puede ordenar (JSON u otros) el mapa generado. Probablemente no le permita serializar solo el conjunto de campos solicitados por la persona que llama, pero imagino que usar un grupo de grupos le permitirá cubrir la mayoría de los casos. Usar grupos en lugar de los campos directamente probablemente también aumentaría la capacidad de caché.

Ejemplo:

package main import ( "encoding/json" "fmt" "log" "github.com/hashicorp/go-version" "github.com/liip/sheriff" ) type User struct { Username string `json:"username" groups:"api"` Email string `json:"email" groups:"personal"` Name string `json:"name" groups:"api"` Roles []string `json:"roles" groups:"api" since:"2"` } func main() { user := User{ Username: "alice", Email: "[email protected]", Name: "Alice", Roles: []string{"user", "admin"}, } v2, err := version.NewVersion("2.0.0") if err != nil { log.Panic(err) } o := &sheriff.Options{ Groups: []string{"api"}, ApiVersion: v2, } data, err := sheriff.Marshal(o, user) if err != nil { log.Panic(err) } output, err := json.MarshalIndent(data, "", " ") if err != nil { log.Panic(err) } fmt.Printf("%s", output) }


EDIT: noté algunos votos negativos y volví a mirar este Q & A. La mayoría de la gente parece perderse que el OP pidió que los campos se seleccionen dinámicamente en función de la lista de campos proporcionada por el que llama. No puede hacer esto con la etiqueta struct json estáticamente definida.

Si lo que quieres es omitir siempre un campo para json-encode, entonces por supuesto usa json:"-" para ignorar el campo (también ten en cuenta que esto no es necesario si tu campo no está exportado - esos campos siempre son ignorados por el json codificador). Pero esa no es la pregunta del OP.

Para citar el comentario sobre el json:"-" respuesta:

Esta [la respuesta json:"-" ] es la respuesta que la mayoría de las personas que terminan aquí buscando querría, pero no es la respuesta a la pregunta.

Yo usaría un mapa [string] interface {} en lugar de una struct en este caso. Puede eliminar campos fácilmente llamando a la función delete incorporada en el mapa para eliminar los campos.

Es decir, si no puede consultar solo los campos solicitados en primer lugar.


La pregunta ahora es un poco vieja, pero me encontré con el mismo problema hace un rato, y como no encontré una manera fácil de hacerlo, construí una biblioteca que cumpliera con este propósito. Permite generar fácilmente un map[string]interface{} partir de una estructura estática.

https://github.com/tuvistavie/structomap


Otra forma de hacerlo es tener una estructura de punteros con la etiqueta ,omitempty . Si los punteros son nulos , los campos no serán Marshalled.

Este método no requerirá una reflexión adicional o un uso ineficiente de los mapas.

El mismo ejemplo que jorelli usando este método: http://play.golang.org/p/JJNa0m2_nw


Puede usar el atributo de etiquetado "omitifempty" o hacer punteros de campos opcionales y dejar los que desee omitidos sin inicializar.


Puede usar el paquete de reflect para seleccionar los campos que desee al reflejar en las etiquetas de campo y seleccionar los valores de la etiqueta json . Defina un método en su tipo SearchResults que seleccione los campos que desee y los devuelva como un map[string]interface{} , y luego marque eso en lugar de la estructura SearchResults. Aquí hay un ejemplo de cómo puede definir ese método:

func fieldSet(fields ...string) map[string]bool { set := make(map[string]bool, len(fields)) for _, s := range fields { set[s] = true } return set } func (s *SearchResult) SelectFields(fields ...string) map[string]interface{} { fs := fieldSet(fields...) rt, rv := reflect.TypeOf(*s), reflect.ValueOf(*s) out := make(map[string]interface{}, rt.NumField()) for i := 0; i < rt.NumField(); i++ { field := rt.Field(i) jsonKey := field.Tag.Get("json") if fs[jsonKey] { out[jsonKey] = rv.Field(i).Interface() } } return out }

y aquí hay una solución ejecutable que muestra cómo llamarías a este método y organizarías tu selección: http://play.golang.org/p/1K9xjQRnO8


Toma tres ingredientes:

  1. El paquete reflect para recorrer todos los campos de una estructura.

  2. Una instrucción if para recoger los campos que desea Marshal , y

  3. El paquete de encoding/json para Marshal los campos que te gustan.

Preparación:

  1. Mézclalos en una buena proporción. Utilice reflect.TypeOf(your_struct).Field(i).Name() para obtener un nombre del i ésimo campo de your_struct .

  2. Utilice reflect.ValueOf(your_struct).Field(i) para obtener una representación de tipo de Value de un i ésimo campo de your_struct .

  3. Use fieldValue.Interface{} para recuperar el valor real (upcasted to type interface {}) del fieldValue of type Value

Si por suerte logra no quemar ningún transistor o interruptor automático en el proceso, debería obtener algo como esto:

func MarshalOnlyFields(structa interface{}, includeFields map[string]bool) (jsona []byte, status error) { value := reflect.ValueOf(structa) typa := reflect.TypeOf(structa) size := value.NumField() jsona = append(jsona, ''{'') for i := 0; i < size; i++ { structValue := value.Field(i) var fieldName string = typa.Field(i).Name if marshalledField, marshalStatus := json.Marshal((structValue).Interface()); marshalStatus != nil { return []byte{}, marshalStatus } else { if includeFields[fieldName] { jsona = append(jsona, ''"'') jsona = append(jsona, []byte(fieldName)...) jsona = append(jsona, ''"'') jsona = append(jsona, '':'') jsona = append(jsona, (marshalledField)...) if i+1 != len(includeFields) { jsona = append(jsona, '','') } } } } jsona = append(jsona, ''}'') return }

Servicio:

servir con una estructura arbitraria y un map[string]bool de campos que desea incluir, por ejemplo

type magic struct { Magic1 int Magic2 string Magic3 [2]int } func main() { var magic = magic{0, "tusia", [2]int{0, 1}} if json, status := MarshalOnlyFields(magic, map[string]bool{"Magic1": true}); status != nil { println("error") } else { fmt.Println(string(json)) } }

¡Buen provecho!


usa `json:" - "`

// Field is ignored by this package. Field int `json:"-"` // Field appears in JSON as key "myName". Field int `json:"myName"` // Field appears in JSON as key "myName" and // the field is omitted from the object if its value is empty, // as defined above. Field int `json:"myName,omitempty"` // Field appears in JSON as key "Field" (the default), but // the field is skipped if empty. // Note the leading comma. Field int `json:",omitempty"`

doc: http://golang.org/pkg/encoding/json/#Marshal