bind json golang
Deshacerse de los objetos JSON anidados en Golang (8)
¿Hay alguna manera de desasignar la propiedad de barra anidada y asignarla directamente a una propiedad de estructura sin crear una estructura anidada?
No, encoding / json no puede hacer el truco con "> some> deep> childnode" como encoding / xml puede hacer. Estructuras anidadas es el camino a seguir.
Hay few questions sobre el topic pero ninguna parece cubrir mi caso, así que estoy creando una nueva.
Tengo JSON como el siguiente:
{"foo":{ "bar": "1", "baz": "2" }, "more": "text"}
¿Hay alguna manera de desasignar la propiedad de barra anidada y asignarla directamente a una propiedad de estructura sin crear una estructura anidada?
La solución que estoy adoptando ahora es la siguiente:
type Foo struct {
More String `json:"more"`
Foo struct {
Bar string `json:"bar"`
Baz string `json:"baz"`
} `json:"foo"`
// FooBar string `json:"foo.bar"`
}
Esta es una versión simplificada, por favor ignore la verbosidad. Como puede ver, me gustaría poder analizar y asignar el valor a
// FooBar string `json:"foo.bar"`
He visto personas usando un mapa, pero ese no es mi caso. Básicamente no me importa el contenido de foo
(que es un objeto grande), excepto por algunos elementos específicos.
¿Cuál es el enfoque correcto en este caso? No estoy buscando hacks extraños, así que si este es el camino a seguir, estoy de acuerdo con eso.
¿Qué hay de los campos anónimos? No estoy seguro de si eso constituirá una "estructura anidada", pero es más claro que tener una declaración de estructura anidada. ¿Qué sucede si quiere reutilizar el elemento anidado en otro lugar?
type NestedElement struct{
someNumber int `json:"number"`
someString string `json:"string"`
}
type BaseElement struct {
NestedElement `json:"bar"`
}
Al igual que lo que Volker mencionó, las estructuras anidadas es el camino a seguir. Pero si realmente no desea estructuras anidadas, puede anular el func UnmarshalJSON.
http://play.golang.org/p/T0aZEDL0Nu
type A struct {
FooBar string // takes foo.bar
FooBaz string // takes foo.baz
More string `json:"more"`
}
func (a *A) UnmarshalJSON(b []byte) error {
var f interface{}
json.Unmarshal(b, &f)
m := f.(map[string]interface{})
foomap := m["foo"]
v := foomap.(map[string]interface{})
a.FooBar = v["bar"].(string)
a.FooBaz = v["baz"].(string)
return nil
}
Por favor, ignore el hecho de que no estoy devolviendo un error apropiado. Lo dejé por simplicidad.
Estaba trabajando en algo como esto. Pero está trabajando solo con estructuras generadas desde proto. https://github.com/flowup-labs/grpc-utils
en tu proto
message Msg {
Firstname string = 1 [(gogoproto.jsontag) = "name.firstname"];
PseudoFirstname string = 2 [(gogoproto.jsontag) = "lastname"];
EmbedMsg = 3 [(gogoproto.nullable) = false, (gogoproto.embed) = true];
Lastname string = 4 [(gogoproto.jsontag) = "name.lastname"];
Inside string = 5 [(gogoproto.jsontag) = "name.inside.a.b.c"];
}
message EmbedMsg{
Opt1 string = 1 [(gogoproto.jsontag) = "opt1"];
}
Entonces su salida será
{
"lastname": "Three",
"name": {
"firstname": "One",
"inside": {
"a": {
"b": {
"c": "goo"
}
}
},
"lastname": "Two"
},
"opt1": "var"
}
Este es un ejemplo de cómo deshacer las respuestas JSON del servidor proxy sbserver de Safebrowsing v4 API: https://play.golang.org/p/4rGB5da0Lt
// this example shows how to unmarshall JSON requests from the Safebrowsing v4 sbserver
package main
import (
"fmt"
"log"
"encoding/json"
)
// response from sbserver POST request
type Results struct {
Matches []Match
}
// nested within sbserver response
type Match struct {
ThreatType string
PlatformType string
ThreatEntryType string
Threat struct {
URL string
}
}
func main() {
fmt.Println("Hello, playground")
// sample POST request
// curl -X POST -H ''Content-Type: application/json''
// -d ''{"threatInfo": {"threatEntries": [{"url": "http://testsafebrowsing.appspot.com/apiv4/ANY_PLATFORM/MALWARE/URL/"}]}}''
// http://127.0.0.1:8080/v4/threatMatches:find
// sample JSON response
jsonResponse := `{"matches":[{"threatType":"MALWARE","platformType":"ANY_PLATFORM","threatEntryType":"URL","threat":{"url":"http://testsafebrowsing.appspot.com/apiv4/ANY_PLATFORM/MALWARE/URL/"}}]}`
res := &Results{}
err := json.Unmarshal([]byte(jsonResponse), res)
if(err!=nil) {
log.Fatal(err)
}
fmt.Printf("%v/n",res)
fmt.Printf("/tThreat Type: %s/n",res.Matches[0].ThreatType)
fmt.Printf("/tPlatform Type: %s/n",res.Matches[0].PlatformType)
fmt.Printf("/tThreat Entry Type: %s/n",res.Matches[0].ThreatEntryType)
fmt.Printf("/tURL: %s/n",res.Matches[0].Threat.URL)
}
La combinación de map y struct permite desasignar objetos JSON anidados donde la clave es dinámica. => mapa [cadena]
Por ejemplo: stock.json
{
"MU": {
"symbol": "MU",
"title": "micro semiconductor",
"share": 400,
"purchase_price": 60.5,
"target_price": 70
},
"LSCC":{
"symbol": "LSCC",
"title": "lattice semiconductor",
"share": 200,
"purchase_price": 20,
"target_price": 30
}
}
Ir a la aplicación
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
)
type Stock struct {
Symbol string `json:"symbol"`
Title string `json:"title"`
Share int `json:"share"`
PurchasePrice float64 `json:"purchase_price"`
TargetPrice float64 `json:"target_price"`
}
type Account map[string]Stock
func main() {
raw, err := ioutil.ReadFile("stock.json")
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
var account Account
log.Println(account)
}
La clave dinámica en el hash es manejar una cadena, y el objeto anidado está representado por una estructura.
Sí. Con gjson todo lo que tienes que hacer ahora es:
bar := gjson.Get(json, "foo.bar")
bar
podría ser una propiedad de estructura si lo desea. Además, no hay mapas.
sí puede asignar los valores de json anidado a struct hasta que conozca el tipo subyacente de claves json, por ejemplo.
package main
import (
"encoding/json"
"fmt"
)
// Object
type Object struct {
Foo map[string]map[string]string `json:"foo"`
More string `json:"more"`
}
func main(){
someJSONString := []byte(`{"foo":{ "bar": "1", "baz": "2" }, "more": "text"}`)
var obj Object
err := json.Unmarshal(someJSONString, &obj)
if err != nil{
fmt.Println(err)
}
fmt.Println("jsonObj", obj)
}