İç içe yerleştirilmiş JSON nesnelerinin eşlemesini kaldırma


122

Orada bir kaç soru üzerine konunun ancak bunların hiçbiri böylece bir yenisini oluşturmak ediyorum, davamı kapsayacak şekilde görünüyor.

Aşağıdaki gibi JSON'a sahibim:

{"foo":{ "bar": "1", "baz": "2" }, "more": "text"}

Yuvalanmış bar özelliğini unmarshal haline getirmenin ve iç içe bir yapı oluşturmadan bunu doğrudan bir struct özelliğine atamanın bir yolu var mı?

Şu anda benimsediğim çözüm şudur:

type Foo struct {
    More String `json:"more"`
    Foo  struct {
        Bar string `json:"bar"`
        Baz string `json:"baz"`
    } `json:"foo"`
    //  FooBar  string `json:"foo.bar"`
}

Bu basitleştirilmiş bir versiyon, lütfen ayrıntıları dikkate almayın. Gördüğünüz gibi, değeri ayrıştırıp atayabilmek istiyorum

//  FooBar  string `json:"foo.bar"`

Harita kullanan insanlar gördüm, ama bu benim durumum değil. Temelde foobirkaç belirli öğe dışında (büyük bir nesne olan) içeriğini umursamıyorum .

Bu durumda doğru yaklaşım nedir? Garip hackler aramıyorum, bu yüzden gidilecek yol buysa, bunda sorun yok.

Yanıtlar:


67

Yuvalanmış bar özelliğini unmarshal haline getirmenin ve iç içe bir yapı oluşturmadan bunu doğrudan bir struct özelliğine atamanın bir yolu var mı?

Hayır, encoding / json, encoding / xml'nin yapabileceği gibi "> some> deep> childnode" ile hile yapamaz. İç içe yapılar, gitmenin yoludur.


1
Bu kodlama / xml'den neden farklı?
Caleb Hearth

1
@CalebThompson XML ve JSON için yapı, basit durumlar birbirine benzese bile tamamen farklıdır. XML etiketinin içeriği bir çeşittir: (Alt etiketlerin sıralı bir haritası VEYA Metin) VE niteliklerin sırasız bir haritası. JSON, bir Go yapısı gibidir. Dolayısıyla, JSON'u yapılarla eşleştirmek çok daha basittir: Yapıyı JSON'nuzdan sonra modellemeniz yeterlidir.
Volker

benim durumumda JSON yapısının gerçekte kararlaştırılmamış olması nedeniyle bir yapı oluşturabilirim ve bunu [string] arabiriminin {} haritasını kullanarak ayrıştırdığımda, iç içe geçmiş öğelerle ilgili sorunlar yaşıyorum. Ne yapılabilir.?
viveksinghggits

Ama neden struct içinde yapı oluşturmayı geri alamıyoruz?
Vitaly Zdanevich

29

Volker'ın bahsettiği gibi, iç içe yapılar gitmenin yoludur. Eğer Ama eğer gerçekten iç içe yapılar istemiyoruz, sen UnmarshalJSON fonk geçersiz kılabilir.

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
}

Lütfen düzgün bir hata vermediğim gerçeğini dikkate almayın. Basit olması için bunu dışarıda bıraktım.

GÜNCELLEME: "Daha fazla" değeri doğru bir şekilde alıyor.


3
& {FooBar: 1 FooBaz: 2 Daha:} alıyorum. "Metin" eksik
Guy Segev

@GuySegev Ben devam ettim ve bu sorunu çözmek için cevabımı güncelledim. Bunu belirttiğiniz için teşekkürler.
rexposadas

22

Bu, Safebrowsing v4 API sbserver proxy sunucusundan JSON yanıtlarının nasıl unmarshall yapılacağına dair bir örnektir: 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)
}

2
Json.Unmarshal olduğunu gösterdiğin için teşekkür ederiz olabilir karmaşık iç içe json verilerini unmarshal. Benim sorunum, bir dosyadan JSON okuyordum ve sıfır dolgusu ile sonuçlandı. Bunu paylaşmanıza sevindim!
Rohanthewiz

12

Evet. Gjson ile şimdi yapmanız gereken tek şey:

bar := gjson.Get(json, "foo.bar")

baristerseniz bir struct özelliği olabilir. Ayrıca harita yok.


1
fastjson da aynı numaraya izin veriyor: fastjson.GetString(json, "foo", "bar")
valyala

9

Anonim alanlar ne olacak? Bunun bir "iç içe yapı" oluşturup oluşturmayacağından emin değilim, ancak iç içe geçmiş bir yapı bildirimine sahip olmaktan daha temiz. Ya yuvalanmış öğeyi başka bir yerde yeniden kullanmak isterseniz?

type NestedElement struct{
    someNumber int `json:"number"`
    someString string `json:"string"`
}

type BaseElement struct {
    NestedElement `json:"bar"`
}

1

jsonTemel json anahtarlarının türünü öğrenene kadar iç içe geçmiş değerlerini struct'a atayın : -

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)
}

0

Bunun gibi bir şey üzerinde çalışıyordum. Ancak yalnızca protokolden oluşturulan yapılarla çalışıyor. https://github.com/flowup-labs/grpc-utils

senin protokolünde

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"];
}

O zaman çıktınız olacak

{
"lastname": "Three",
"name": {
    "firstname": "One",
    "inside": {
        "a": {
            "b": {
                "c": "goo"
            }
        }
    },
    "lastname": "Two"
},
"opt1": "var"
}

2
Bunun soruyu nasıl yanıtladığını açıklamak için birkaç satır ekleyin. Repo silinmişse cevapta değer kalmaz.
Ubercool

Geri döneceğini sanmıyorum arkadaşlar.
DevX

-1

Harita ve yapının birleştirilmesi, anahtarın dinamik olduğu iç içe yerleştirilmiş JSON nesnelerinin eşlemesini kaldırmaya izin verir. => harita [dize]

Örneğin: 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
  }
}

Uygulamaya git

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)
}

Karmadaki dinamik anahtar bir dizgedir ve yuvalanmış nesne bir yapı ile temsil edilir.


3
bu eksik görünüyor. ham kullanılmamış
buildmaestro
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.