一尘不染

在golang json.Unmarshal中处理单个或数组结构的好方法是什么?

go

我正在使用Go和Yahoo API构建股票报价网络应用。

问题是如何在数组和单个结构之间切换而无需编写另一个结构。我不确定如何用语言解释它。这是示例:

从Yahoo API获得一个符号引号如下所示:

{"query":{"count":1,"created":"2016-05-11T02:12:33Z","lang":"en-US","results":{"quote":{"Change":"+0.21","DaysLow":"9.32","DaysHigh":"9.68","Name":"Alcoa Inc. Common Stock","Open":"9.56","PreviousClose":"9.46","Symbol":"aa","Volume":"22266533","PercentChange":"+2.22%"}}}}

从Yahoo API获取多个报价:

{"query":{"count":2,"created":"2016-05-11T02:17:48Z","lang":"en-us","results":{"quote":[{"Change":"+0.21","DaysLow":"9.32","DaysHigh":"9.68","Name":"Alcoa Inc. Common Stock","Open":"9.56","PreviousClose":"9.46","Symbol":"aa","Volume":"22266533","PercentChange":"+2.22%"},{"Change":"+0.63","DaysLow":"92.11","DaysHigh":"93.57","Name":"Apple Inc.","Open":"93.35","PreviousClose":"92.79","Symbol":"aapl","Volume":"33686836","PercentChange":"+0.68%"}]}}}

不同之处在于引号成为一个数组[]

使用时如何处理json.Unmarshal(quoteResultRawJSON, &queryResult)

我的结构看起来像:

type QueryResult struct {
  Id bson.ObjectId `bson:"_id,omitempty"`
  Query Query `json:"query"`
}

type Query struct {
  Count int `json:"count"`
  Created string `json:"created"`
  Lang string `json:"lang"`
  Results Quote `json:"results"`
}

type Quote struct {
  Quote StockQuote `json:"quote"` //Here is the difference. Do I need to re-write the whole struct in order to handle []
}

type StockQuote struct {
  Change string `json:"change"`
  PercentChange string `json:"percentChange"`
  DaysLow string `json:"daysLow"`
  DaysHigh string `json:"daysHigh"`
  Open string `json:"open"`
  PreviousClose string `json:"previousClose"`
  Symbol string `json:"symbol"`
  Name string `json:"name"`
  Volume string `json:"volume"`
 }

我是否需要编写另一个结构来处理数组?


阅读 433

收藏
2020-07-02

共1个答案

一尘不染

通过UnmarshalJSON()覆盖控制解组过程。

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

package main

import (
    "log"
    "encoding/json"
    "bytes"
)

const(
    s1=`{"query":{"count":1,"created":"2016-05-11T02:12:33Z","lang":"en-US","results":{"quote":{"Change":"+0.21","DaysLow":"9.32","DaysHigh":"9.68","Name":"Alcoa Inc. Common Stock","Open":"9.56","PreviousClose":"9.46","Symbol":"aa","Volume":"22266533","PercentChange":"+2.22%"}}}}`
    s2=`{"query":{"count":2,"created":"2016-05-11T02:17:48Z","lang":"en-us","results":{"quote":[{"Change":"+0.21","DaysLow":"9.32","DaysHigh":"9.68","Name":"Alcoa Inc. Common Stock","Open":"9.56","PreviousClose":"9.46","Symbol":"aa","Volume":"22266533","PercentChange":"+2.22%"},{"Change":"+0.63","DaysLow":"92.11","DaysHigh":"93.57","Name":"Apple Inc.","Open":"93.35","PreviousClose":"92.79","Symbol":"aapl","Volume":"33686836","PercentChange":"+0.68%"}]}}}`
)
type QueryResult struct {
    //Id bson.ObjectId `bson:"_id,omitempty"`
    Query Query `json:"query"`
}

type Query struct {
    Count int `json:"count"`
    Created string `json:"created"`
    Lang string `json:"lang"`
    Results Quote `json:"results"`
}

type structOrArray struct{
    parent *Quote
    s StockQuote
    a []StockQuote
}

func (this *structOrArray)UnmarshalJSON(data []byte) error{
    d := json.NewDecoder(bytes.NewBuffer(data))
    t, err := d.Token();
    if err != nil{
        return err
    }
    if t==json.Delim('['){
        if err := json.Unmarshal(data, &this.a);err != nil {
            return err
        }
        return nil
    }
    if err := json.Unmarshal(data, &this.s);err != nil {
        return err
    }
    return nil
}

type fakeQuote struct{
    Load structOrArray `json:"quote"` //Here is the difference. Do I need to re-write the whole struct in order to handle []
}
type Quote struct {
    Quote *StockQuote
    Quotes []StockQuote
}
func (this *Quote)UnmarshalJSON(data []byte) error{
    fq := fakeQuote{}
    if err := json.Unmarshal(data, &fq);err != nil{
        return err
    }
    this.Quote = &fq.Load.s
    this.Quotes = fq.Load.a
    return nil
}
type StockQuote struct {
    Change string `json:"change"`
    PercentChange string `json:"percentChange"`
    DaysLow string `json:"daysLow"`
    DaysHigh string `json:"daysHigh"`
    Open string `json:"open"`
    PreviousClose string `json:"previousClose"`
    Symbol string `json:"symbol"`
    Name string `json:"name"`
    Volume string `json:"volume"`
}
func main() {
    r := QueryResult{}
    err := json.Unmarshal([]byte(s1), &r)
    if err != nil {
        log.Fatalln(err)
    }
    log.Println(r.Query.Results.Quote)
    log.Println(r.Query.Results.Quotes)

    err = json.Unmarshal([]byte(s2), &r)
    if err != nil {
        log.Fatalln(err)
    }
    log.Println(r.Query.Results.Quote)
    log.Println(r.Query.Results.Quotes)
}
2020-07-02