第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機(jī)立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用自定義解組器處理嵌套的 JSON 結(jié)構(gòu)

使用自定義解組器處理嵌套的 JSON 結(jié)構(gòu)

Go
喵喵時光機(jī) 2021-09-27 17:26:39
我正在處理一個遺留系統(tǒng),該系統(tǒng)返回帶有嵌套結(jié)構(gòu)和一些可選字段(以隨機(jī)順序)的 JSON。像這樣的東西:type A struct {    /* simple struct, can be unmarshalled normally */    AF1 string `json:"AF1"`}type B struct {    /* simple struct, can be unmarshalled normally */    BF1 string `json:"BF1"`}type X struct {    Things []A `json:"things"` /* mandatory */    Thangs []B `json:"thangs"` /* mandatory */    /* some individual string values may or may not appear, eg:    Item1 string    Item2 string    */         }如果 Item[12] 確實出現(xiàn),我想把它們藏在地圖或類似的地方。有沒有優(yōu)雅的方法來解組 X?有什么方法可以為 X 編寫自定義 UnmarshalJSON func(以處理選項字符串字段),然后將 A 和 B 交給默認(rèn)的 JSON 解組器?
查看完整描述

2 回答

?
慕標(biāo)5832272

TA貢獻(xiàn)1966條經(jīng)驗 獲得超4個贊

如果我從您的附加評論中正確理解了問題,那么輸入可能包含任何具有未知名稱(和類型?)的任意額外字段,并且您想要/需要訪問這些字段。如果只是為了以后重新編組,那么該json.RawMessage類型會很有趣。


理想情況下encoding/json會有一個特殊的標(biāo)簽(如",any" encoding/xml標(biāo)簽),它會自動將任何額外/未引用的 JSON 項目收集到 a map[string]interface{}或map[string]json.RawMessage字段中。但是我找不到任何這樣的功能,也找不到一種明顯的方法來用匿名結(jié)構(gòu)來模擬它(但我并沒有很努力地嘗試)。


編輯:Go 項目中有一個針對此功能的未解決問題。顯然,圍繞 Go 1.2 提交了一個更改并進(jìn)行了部分審查,但最終沒有被接受。


如果做不到這一點,有幾種方法可以完全按照您的建議執(zhí)行,為 X 制作自定義 (un) marshaller 并回調(diào)到 json 包以處理[]A和[]B.


這是一個快速組合在一起的示例,可能有更好/更清晰/更安全的方法來做到這一點。(在整個示例中,A 和 B 可以是任意復(fù)雜的,可能包含本身具有自定義(取消)編組方法的類型。)


package main


import (

    "encoding/json"

    "fmt"

)


type A struct {

    AF1 string

}


type B struct {

    BF1 string

}


type X struct {

    Things []A

    Thangs []B


    // Or perhaps json.RawMessage if you just

    // want to pass them through.

    // Or map of string/int/etc if the value type is fixed.

    Extra map[string]interface{}

}


// Marshal Way 1: call unmarshal twice on whole input


type xsub struct {

    Things []A `json:"things"`

    Thangs []B `json:"thangs"`

}


func (x *X) _UnmarshalJSON(b []byte) error {

    // First unmarshall the known keys part:

    var tmp xsub

    if err := json.Unmarshal(b, &tmp); err != nil {

        return err

    }


    // Then unmarshall the whole thing again:

    var vals map[string]interface{}

    if err := json.Unmarshal(b, &vals); err != nil {

        return err

    }


    // Everything worked, chuck the map entries for

    // "known" fields and store results.

    delete(vals, "things")

    delete(vals, "thangs")

    x.Things = tmp.Things

    x.Thangs = tmp.Thangs

    x.Extra = vals

    return nil

}


// Way 2:


func (x *X) UnmarshalJSON(b []byte) error {

    // Only partially decode:

    var tmp map[string]json.RawMessage

    if err := json.Unmarshal(b, &tmp); err != nil {

        return err

    }


    // Now handle the known fields:

    var things []A

    if err := json.Unmarshal(tmp["things"], &things); err != nil {

        return err

    }

    var thangs []B

    if err := json.Unmarshal(tmp["thangs"], &thangs); err != nil {

        return err

    }


    // And the unknown fields.

    var extra map[string]interface{}


    // Either:

    if true {

        // this has more calls to Unmarshal, but may be more desirable

        // as it completely skips over the already handled things/thangs.

        delete(tmp, "things")

        delete(tmp, "thangs")

        // If you only needed to store the json.RawMessage for use

        // in MarshalJSON then you'd just store "tmp" and stop here.


        extra = make(map[string]interface{}, len(tmp))

        for k, raw := range tmp {

            var v interface{}

            if err := json.Unmarshal(raw, &v); err != nil {

                return err

            }

            extra[k] = v

        }

    } else { // Or:

        // just one more call to Unmarshal, but it will waste

        // time with things/thangs again.

        if err := json.Unmarshal(b, &extra); err != nil {

            return err

        }

        delete(extra, "things")

        delete(extra, "thangs")

    }


    // no error, we can store the results

    x.Things = things

    x.Thangs = thangs

    x.Extra = extra

    return nil

}


func (x X) MarshalJSON() ([]byte, error) {

    // abusing/reusing x.Extra, could copy map instead

    x.Extra["things"] = x.Things

    x.Extra["thangs"] = x.Thangs

    result, err := json.Marshal(x.Extra)

    delete(x.Extra, "things")

    delete(x.Extra, "thangs")

    return result, err

}


func main() {

    inputs := []string{

        `{"things": [], "thangs": []}`,


        `

{

    "things": [

    {

        "AF1": "foo"

    },

    {

        "AF1": "bar"

    }

    ],

    "thangs": [

        {

            "BF1": "string value"

        }

    ],

    "xRandomKey":       "not known ahead of time",

    "xAreValueTypesKnown": 172

}`,

    }


    for _, in := range inputs {

        fmt.Printf("\nUnmarshal(%q):\n", in)

        var x X

        err := json.Unmarshal([]byte(in), &x)

        if err != nil {

            fmt.Println("unmarshal:", err)

        } else {

            fmt.Printf("\tas X: %+v\n", x)

            fmt.Printf("\twith map: %v\n", x.Extra)

            out, err := json.Marshal(x)

            if err != nil {

                fmt.Println("marshal:", err)

                continue

            }

            fmt.Printf("\tRemarshals to: %s\n", out)

        }

    }

}

Run on Playground


查看完整回答
反對 回復(fù) 2021-09-27
?
holdtom

TA貢獻(xiàn)1805條經(jīng)驗 獲得超10個贊

作為 Dace C 答案的附加答案。我想實現(xiàn)與您相同的目標(biāo),但是我想重用該函數(shù)而不是對值進(jìn)行硬編碼。


這是我做的:


type DynamicFieldsUnmarshaller interface {

    WithExtraFields(map[string]interface{})

    Unmarshal([]byte) error

}


type TestObject struct {

    Name string `json:"name"`

    CustomFields map[string]interface{} `json:"-"`

}


func (o *TestObject) Unmarshal(data []byte) error {

    return UnmarshalCustomJSON(data,o)

}


func (o *TestObject) WithExtraFields(f map[string]interface{}) {

    o.CustomFields = f

}


func UnmarshalCustomJSON(b []byte, o DynamicFieldsUnmarshaller) error {

    if err := json.Unmarshal(b, &o); err != nil {

        return err

    }


    // unmarshal everything to a map

    var vals map[string]interface{}

    if err := json.Unmarshal(b, &vals); err != nil {

        return err

    }


    if len(vals)== 0 {

        return nil

    }


    fields := reflect.TypeOf(o).Elem()

    num := fields.NumField()

    for i := 0; i < num; i++ {

        field := fields.Field(i)

        jsonTag := field.Tag.Get("json")

        if jsonTag != "" && jsonTag != "-" {

            delete(vals, jsonTag)

        }

    }


    o.WithExtraFields(vals)


    return nil

}

這應(yīng)該只將不在結(jié)構(gòu)中的值添加到map[string]interface{}字段中。


例如:


   body := []byte(`

        {

            "name":"kilise",

            "age": 40

        }

    `)


    var dto TestObject

    err := dto.Unmarshal(body)

    if err != nil {

        panic(err)

    }

只會將“年齡”添加到 dto.CustomFields 地圖。


請注意,此解決方案可能并不總是最好的,因為它沒有實現(xiàn) json.Unmarshaler


查看完整回答
反對 回復(fù) 2021-09-27
  • 2 回答
  • 0 關(guān)注
  • 182 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號