Il y a apequestions sur le sujet mais aucun ne semble couvrir mon cas, donc je suis créer un nouveau.
J'ai JSON comme ce qui suit:
{"foo":{ "bar": "1", "baz": "2" }, "more": "text"}
Existe-t-il un moyen de disséminer la propriété de barre imbriquée et de l'affecter directement à une propriété de structure sans créer de structure imbriquée?
La solution que j'adopte actuellement est la suivante:
type Foo struct {
More String `json:"more"`
Foo struct {
Bar string `json:"bar"`
Baz string `json:"baz"`
} `json:"foo"`
// FooBar string `json:"foo.bar"`
}
Ceci est une version simplifiée, veuillez ignorer la verbosité. Comme vous pouvez le constater, j'aimerais pouvoir analyser et attribuer la valeur à
// FooBar string `json:"foo.bar"`
J'ai vu des gens utiliser une carte, mais ce n'est pas mon cas. Fondamentalement, je ne me soucie pas du contenu de foo
(qui est un objet volumineux), à l'exception de quelques éléments spécifiques.
Quelle est la bonne approche dans ce cas? Je ne cherche pas de hacks étranges, donc si c'est la voie à suivre, ça me convient.
Existe-t-il un moyen de disséminer la propriété de barre imbriquée et de l'affecter directement à une propriété de structure sans créer de structure imbriquée?
Non, encoding/json ne peut pas faire l'affaire avec "> some> deep> childnode" contrairement à encoding/xml. Les structures imbriquées sont la voie à suivre.
Comme ce que Volker a mentionné, les structures imbriquées sont la voie à suivre. Mais si vous réellement ne voulez pas de structures imbriquées, vous pouvez remplacer la fonction UnmarshalJSON.
https://play.golang.org/p/dqn5UdqFfJt
type A struct {
FooBar string // takes foo.bar
FooBaz string // takes foo.baz
More string
}
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)
a.More = m["more"].(string)
return nil
}
Veuillez ignorer le fait que je ne renvoie pas une erreur appropriée. J'ai laissé cela pour plus de simplicité.
UPDATE: Récupération correcte de la valeur "more".
Voici un exemple de suppression des réponses JSON du serveur 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)
}
Oui. Avec gjson , tout ce que vous avez à faire maintenant est:
bar := gjson.Get(json, "foo.bar")
bar
pourrait être une propriété de struct si vous voulez. En outre, pas de cartes.
Qu'en est-il des champs anonymes? Je ne sais pas si cela constituera une "structure imbriquée", mais cela est plus propre qu'une déclaration de structure imbriquée. Que faire si vous souhaitez réutiliser l'élément imbriqué ailleurs?
type NestedElement struct{
someNumber int `json:"number"`
someString string `json:"string"`
}
type BaseElement struct {
NestedElement `json:"bar"`
}
Attribuez les valeurs de json
imbriqué à struct jusqu'à ce que vous connaissiez le type de clés JSON sous-jacent: -
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)
}
Je travaillais sur quelque chose comme ça. Mais travaille uniquement avec des structures générées à partir de proto. https://github.com/flowup-labs/grpc-utils
dans ton 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"];
}
Ensuite, votre sortie sera
{
"lastname": "Three",
"name": {
"firstname": "One",
"inside": {
"a": {
"b": {
"c": "goo"
}
}
},
"lastname": "Two"
},
"opt1": "var"
}