亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

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

我如何在切片內對切片進行 json 解組

我如何在切片內對切片進行 json 解組

Go
動漫人物 2023-03-21 17:25:49
我正在嘗試解組一些非常丑陋的 json,但不知道如何解組。我有:package mainimport "fmt"import "encoding/json"type PublicKey struct {    ID     int    `json:"id"`    Key    string `json:"key"`    MyData []struct {        ID    string `json:"id"`        Value int    `json:"value"`    }}func main() {    b := `[  {    "id": 1,    "key": "my_key"  },  [    {      "id": "some_id",      "value": 12    },    {      "id": "anorther_id",      "value": 13    }  ]]`    var pk []PublicKey    err := json.Unmarshal([]byte(b), &pk)    if err != nil {        fmt.Println(err)    }    fmt.Println(pk)}對于我得到的結果:[{1 my_key []} {0  []}]第二個切片本不應該是空的。編輯:我得到的錯誤是:json: cannot unmarshal array into Go struct field PublicKey.key of type main.PublicKeyhttps://play.golang.org/p/cztXOchiiS5
查看完整描述

2 回答

?
梵蒂岡之花

TA貢獻1900條經驗 獲得超5個贊

那是一些真正可怕的 JSON!我有兩種方法來處理混合數組元素,我更喜歡第二種。interface這是使用類型開關的第一種方法:


package main


import (

    "encoding/json"

    "errors"

    "fmt"

)


type PublicKey struct {

    ID  int    `json:"id"`

    Key string `json:"key"`

}


type MyData struct {

    ID    string `json:"id"`

    Value int    `json:"value"`

}


type MixedData struct {

    Key    []PublicKey

    MyData [][]MyData

}


func (md *MixedData) UnmarshalJSON(b []byte) error {

    md.Key = []PublicKey{}

    md.MyData = [][]MyData{}

    var obj []interface{}

    err := json.Unmarshal([]byte(b), &obj)

    if err != nil {

        return err

    }

    for _, o := range obj {

        switch o.(type) {

        case map[string]interface{}:

            m := o.(map[string]interface{})

            id, ok := m["id"].(float64)

            if !ok {

                return errors.New("public key id must be an int")

            }

            pk := PublicKey{}

            pk.ID = int(id)

            pk.Key, ok = m["key"].(string)

            if !ok {

                return errors.New("public key key must be a string")

            }

            md.Key = append(md.Key, pk)

        case []interface{}:

            a := o.([]interface{})

            myData := make([]MyData, len(a))

            for i, x := range a {

                m, ok := x.(map[string]interface{})

                if !ok {

                    return errors.New("data array contains unexpected object")

                }

                val, ok := m["value"].(float64)

                if !ok {

                    return errors.New("data value must be an int")

                }

                myData[i].Value = int(val)

                myData[i].ID, ok = m["id"].(string)

                if !ok {

                    return errors.New("data id must be a string")

                }

                md.MyData = append(md.MyData, myData)

            }

        default:

            // got something unexpected, handle somehow

        }

    }

    return nil

}


func main() {

    b := `[

  {

    "id": 1,

    "key": "my_key"

  },

  [

    {

      "id": "some_id",

      "value": 12

    },

    {

      "id": "another_id",

      "value": 13

    }

  ]

]`


    m := MixedData{}

    err := json.Unmarshal([]byte(b), &m)

    if err != nil {

        fmt.Println(err)

    }

    fmt.Println(m)


}

https://play.golang.org/p/g8d_AsH-pYY


希望沒有任何意外的其他元素,但它們可以類似地處理。


這是第二個更多地依賴于 Go 的內部 JSON 解析的幫助json.RawMessage。它對數組的內容做出相同的假設。它假定任何對象都將解組為PublicKey實例,并且任何數組僅由實例組成MyData。我還添加了如何編組回目標 JSON 以實現對稱:


package main


import (

    "encoding/json"

    "fmt"

    "os"

)


type PublicKey struct {

    ID  int    `json:"id"`

    Key string `json:"key"`

}


type MyData struct {

    ID    string `json:"id"`

    Value int    `json:"value"`

}


type MixedData struct {

    Keys   []PublicKey

    MyData [][]MyData

}


func (md *MixedData) UnmarshalJSON(b []byte) error {

    md.Keys = []PublicKey{}

    md.MyData = [][]MyData{}

    obj := []json.RawMessage{}

    err := json.Unmarshal([]byte(b), &obj)

    if err != nil {

        return err

    }

    for _, o := range obj {

        switch o[0] {

        case '{':

            pk := PublicKey{}

            err := json.Unmarshal(o, &pk)

            if err != nil {

                return err

            }

            md.Keys = append(md.Keys, pk)

        case '[':

            myData := []MyData{}

            err := json.Unmarshal(o, &myData)

            if err != nil {

                return err

            }

            md.MyData = append(md.MyData, myData)

        default:

            // got something unexpected, handle somehow

        }

    }

    return nil

}


func (md *MixedData) MarshalJSON() ([]byte, error) {

    out := make([]interface{}, len(md.Keys)+len(md.MyData))

    i := 0

    for _, x := range md.Keys {

        out[i] = x

        i++

    }

    for _, x := range md.MyData {

        out[i] = x

        i++

    }

    return json.Marshal(out)

}


func main() {

    b := `[

  {

    "id": 1,

    "key": "my_key"

  },

  [

    {

      "id": "some_id",

      "value": 12

    },

    {

      "id": "another_id",

      "value": 13

    }

  ]

]`


    m := MixedData{}

    err := json.Unmarshal([]byte(b), &m)

    if err != nil {

        fmt.Println(err)

        os.Exit(1)

    }

    fmt.Println(m)


    enc := json.NewEncoder(os.Stdout)

    enc.SetIndent("", "    ")

    if err := enc.Encode(m); err != nil {

        fmt.Println(err)

        os.Exit(1)

    }

}

https://play.golang.org/p/ryZzaWKNcN0


查看完整回答
反對 回復 2023-03-21
?
大話西游666

TA貢獻1817條經驗 獲得超14個贊

這是一種方法,它結合了在通過創建一個新的臨時類型json.RawMessage來實現的類型中使用默認解組器的技巧json.Unmarshaler,該臨時類型為目標類型設置別名。

我們的想法是,我們將傳入的數組解組為原始消息,并確保數組長度符合我們的預期。然后我們使用它們的 JSON 標記注釋將各個數組元素解組為自定義結構類型。最終結果是我們可以用PublicKey通常的方式解組類型,UnmarshalJSON一旦你理解了這些技巧,代碼就不會很難理解了。

例如(去游樂場):

type PublicKey struct {

  ID   int    `json:"id"`

  Key  string `json:"key"`

  Data []MyData

}


type MyData struct {

  ID    string `json:"id"`

  Value int    `json:"value"`

}


func (pk *PublicKey) UnmarshalJSON(bs []byte) error {

  // Unmarshal into a RawMessage so we can inspect the array length.

  var rawMessage []json.RawMessage

  err := json.Unmarshal(bs, &rawMessage)

  if err != nil {

    return err

  }

  if len(rawMessage) != 2 {

    return fmt.Errorf("expected array of length 2, got %d", len(rawMessage))

  }


  // Parse the first object as PublicKey using the default unmarshaler

  // using a temporary type that is an alias for the target type.

  type PublicKey2 PublicKey

  var pk2 PublicKey2

  err = json.Unmarshal(rawMessage[0], &pk2)

  if err != nil {

    return err

  }


  // Parse the second object as []MyData in the usual way.

  err = json.Unmarshal(rawMessage[1], &pk2.Data)

  if err != nil {

    return err

  }


  // Finally, assign the aliased object to the target object.

  *pk = PublicKey(pk2)

  return nil

}


func main() {

  var pk PublicKey

  err := json.Unmarshal([]byte(jsonstr), &pk)

  if err != nil {

    panic(err)

  }

  fmt.Printf("%#v\n", pk)

  // main.PublicKey{ID:1, Key:"my_key", Data:[]main.MyData{main.MyData{ID:"some_id", Value:12}, main.MyData{ID:"anorther_id", Value:13}}}


}


查看完整回答
反對 回復 2023-03-21
  • 2 回答
  • 0 關注
  • 128 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號