downloadTemp2014
2018-09-12 18:05
浏览 401

根据Golang中的对象值对JSON的解析进行排序

Trying to parse the json and sorting based on one of the values of struct. I want to sort the json based on the custom_meta's part_num, how we can do that. The code is as follows:

type Maininfo struct {
    Id   string     `json:"id"`
    Meta []Metainfo `json:"meta"`
}


type Metainfo struct {
    Filename     string `json:"filename"`
    Custom_meta  string `json:"custom_meta"`
    Size         int    `json:"size"`
    Content_hash string `json:"content_hash"`
}

type Custom_meta struct {
    Part_num string `json:"part_num"`
    Part     int
}

func getMeta(body []byte) (*Maininfo, error) {
    var s = new(Maininfo)
    err := json.Unmarshal(body, &s)
    if err != nil {
        fmt.Println("whoops:", err)
    }
    return s, err
}


func getMetainfo(body []byte) (*Metainfo, error) {
    var s = new(Metainfo)
    err := json.Unmarshal(body, &s)
    if err != nil {
        fmt.Println("error", err)
    }
    return s, err
}

type AxisSorter []Metainfo

func (a AxisSorter) Len() int           { return len(a) }
func (a AxisSorter) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a AxisSorter) Less(i, j int) bool { return a[i].Custom_meta < a[j].Custom_meta }


type NameSorter []Metainfo

func (a NameSorter) Len() int           { return len(a) }
func (a NameSorter) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a NameSorter) Less(i, j int) bool { return a[i].Custom_meta < a[j].Custom_meta }

func main() {
s, err := getMeta([]byte(body))
    fmt.Println("Main stuff", s)

    var metaInfo []Metainfo
    metaInfo = s.Meta
}
    var customMeta CustomMeta

    sort.Sort(AxisSorter(metaInfo))
    fmt.Println("metaInfo sorted ", metaInfo)

    sort.Sort(NameSorter(metaInfo))
    fmt.Println("metaInfo sorted 2 ", metaInfo)

    sort.Slice(metaInfo, func(i, j int) bool {
        fmt.Println("meta ", metaInfo[i].Custom_meta)
        return metaInfo[i].Custom_meta < metaInfo[j].Custom_meta
      })

}

I am not able to sort the code based on the part_num, how can we do that, since info is not a separate object it is a string. How we can parse string and sort it based on the int value.

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • dongya767979565 2018-09-12 21:24
    已采纳

    It looks like the main issue here is that the "custom_meta" value is a quoted JSON string instead of a nested object, which means it cannot be unmarshaled into an object with the (presumably) desired "part_num" integer.

    Ideally you could fix the source of this data so that it emits a JSON object instead of a quoted JSON string; however, if that is not feasible, then you could do the following.

    1. Have the "Custom_meta" type implement json.Umarshaler by first unquoting the source string and then unmarshaling as usual.
    2. Sort "Maininfo.Meta" by the nested "Custom_meta.Part" field separately or as part of a custom unmarshaler for that type.

    For example (Go Playground):

    type MainInfo struct {
      Id        string     `json:"id"`
      MetaInfos []MetaInfo `json:"meta"`
    }
    
    type MetaInfo struct {
      Filename    string     `json:"filename"`
      Custom      CustomMeta `json:"custom_meta"`
      Size        int        `json:"size"`
      ContentHash string     `json:"content_hash"`
    }
    
    type CustomMeta struct {
      PartNum int `json:"part_num"`
    }
    
    func (cm *CustomMeta) UnmarshalJSON(bs []byte) error {
      // Unquote the source string so we can unmarshal it.
      unquoted, err := strconv.Unquote(string(bs))
      if err != nil {
        return err
      }
    
      // Create an aliased type so we can use the default unmarshaler.
      type CustomMeta2 CustomMeta
      var cm2 CustomMeta2
    
      // Unmarshal the unquoted string and assign to the original object.
      if err := json.Unmarshal([]byte(unquoted), &cm2); err != nil {
        return err
      }
      *cm = CustomMeta(cm2)
      return nil
    }
    

    Then you can sort after parsing like so:

    var doc MainInfo
    err := json.Unmarshal([]byte(jsonstr), &doc)
    if err != nil {
      panic(err)
    }
    sort.Slice(doc.MetaInfos, func(i, j int) bool {
      p1 := doc.MetaInfos[i].Custom.PartNum
      p2 := doc.MetaInfos[j].Custom.PartNum
      return p1 < p2
    })
    

    Of course, you could also perform the sorting as part of a custom UnmarshalJSON method for the "MainInfo" type.

    点赞 打赏 评论

相关推荐 更多相似问题