Bỏ phân chia các đối tượng JSON lồng nhau


122

một số câu hỏi về chủ đề này nhưng không có câu hỏi nào trong số đó có vẻ phù hợp với trường hợp của tôi, vì vậy tôi đang tạo một câu hỏi mới.

Tôi có JSON như sau:

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

Có cách nào để bỏ quản lý thuộc tính thanh lồng nhau và gán nó trực tiếp cho thuộc tính struct mà không cần tạo cấu trúc lồng nhau không?

Giải pháp tôi đang áp dụng ngay bây giờ là:

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

Đây là một phiên bản đơn giản hóa, vui lòng bỏ qua sự dài dòng. Như bạn có thể thấy, tôi muốn có thể phân tích cú pháp và gán giá trị cho

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

Tôi đã thấy mọi người sử dụng bản đồ, nhưng đó không phải là trường hợp của tôi. Về cơ bản tôi không quan tâm đến nội dung của foo(là một đối tượng lớn), ngoại trừ một vài yếu tố cụ thể.

Cách tiếp cận chính xác trong trường hợp này là gì? Tôi không tìm kiếm những cách hack kỳ lạ, vì vậy nếu đây là cách để đi, tôi ổn với điều đó.

Câu trả lời:


67

Có cách nào để bỏ quản lý thuộc tính thanh lồng nhau và gán nó trực tiếp cho thuộc tính struct mà không cần tạo cấu trúc lồng nhau không?

Không, mã hóa / json không thể thực hiện thủ thuật với "> some> deep> childnode" như encoding / xml có thể làm được. Cấu trúc lồng nhau là cách để đi.


1
Tại sao điều này lại khác với mã hóa / xml?
Caleb Hearth

1
@CalebThompson Cấu trúc cho XML và JSON hoàn toàn khác nhau, ngay cả khi các trường hợp đơn giản trông giống nhau. Nội dung của thẻ XML là: (Bản đồ có thứ tự của các thẻ con HOẶC Văn bản) VÀ một bản đồ không có thứ tự của các thuộc tính. JSON giống một cấu trúc Go hơn. Vì vậy, ánh xạ JSON với cấu trúc đơn giản hơn nhiều: Chỉ cần lập mô hình cấu trúc sau JSON của bạn.
Volker

trong trường hợp của tôi, cấu trúc của JSON không thực sự được quyết định nên tôi có thể tạo một cấu trúc và khi tôi phân tích cú pháp nó bằng cách sử dụng bản đồ của giao diện [string] {}, tôi đang gặp sự cố đối với các phần tử lồng nhau. Những gì có thể được thực hiện.?
viveksinghggits

Nhưng tại sao chúng ta không thể quản lý cấu trúc bên trong struct?
Vitaly Zdanevich

29

Giống như những gì Volker đã đề cập, cấu trúc lồng nhau là cách để đi. Nhưng nếu bạn thực sự không muốn các cấu trúc lồng nhau, bạn có thể ghi đè chức năng 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
}

Vui lòng bỏ qua thực tế là tôi không trả lại lỗi thích hợp. Tôi bỏ điều đó ra vì đơn giản.

CẬP NHẬT: Đang truy xuất chính xác giá trị "thêm".


3
Tôi đang nhận & {FooBar: 1 FooBaz: 2 Khác:}. "Văn bản" bị thiếu
Guy Segev

@GuySegev Tôi đã tiếp tục và cập nhật câu trả lời của mình để khắc phục sự cố đó. Cảm ơn vì đã chỉ ra điều đó.
rexposadas

22

Đây là ví dụ về cách bỏ quản lý các phản hồi JSON từ máy chủ proxy sbserver API Safebrowsing v4: 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
Cảm ơn bạn đã cho thấy rằng json.Unmarshal có thể giải phóng dữ liệu json phức tạp lồng nhau sâu. Vấn đề của tôi là tôi đang đọc JSON từ một tệp và kết thúc bằng một số không đệm. Rất vui vì bạn đã chia sẻ điều này!
Rohanthewiz

12

Đúng. Với gjson, tất cả những gì bạn phải làm bây giờ là:

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

barcó thể là thuộc tính struct nếu bạn thích. Ngoài ra, không có bản đồ.


1
fastjson cũng cho phép thủ thuật tương tự: fastjson.GetString(json, "foo", "bar")
valyala

9

Còn các trường ẩn danh thì sao? Tôi không chắc liệu điều đó có tạo thành "cấu trúc lồng nhau" hay không nhưng nó rõ ràng hơn việc khai báo cấu trúc lồng nhau. Điều gì sẽ xảy ra nếu bạn muốn sử dụng lại phần tử lồng nhau ở nơi khác?

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

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

1

Gán các giá trị lồng nhau jsoncho struct cho đến khi bạn biết loại khóa json cơ bả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

Tôi đã làm việc trên một cái gì đó như thế này. Nhưng chỉ hoạt động với các cấu trúc được tạo ra từ proto. https://github.com/flowup-labs/grpc-utils

trong proto của bạn

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

Sau đó, đầu ra của bạn sẽ là

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

2
Thêm vài dòng để giải thích cách này trả lời câu hỏi. Nếu repo bị xóa, không còn giá trị nào trong câu trả lời.
Ubercool

Tôi không nghĩ anh ấy sẽ trở lại, các bạn.
DevX

-1

Việc kết hợp bản đồ và cấu trúc cho phép giải nén các đối tượng JSON lồng nhau trong đó khóa là động. => bản đồ [chuỗi]

Ví dụ: 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
  }
}

Đi ứng dụng

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

Khóa động trong hàm băm là xử lý một chuỗi và đối tượng lồng nhau được biểu diễn bằng một cấu trúc.


3
điều này có vẻ không đầy đủ. thô chưa được sử dụng
buildmaestro
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.