Golang에서 커스텀 방식으로 JSON을 언마샬링하는 방법
                                            
                                                
                                                
                                                
                                                
                                                
                                                 28941 단어  go
                    
These are real world examples. (coinex exchange API)
먼저 다음과 같이 요청합니다.
raw_response, _ := http.Get("https://api.coinex.com/v1/market/list")
그리고 우리는 다음과 같은 json 객체를 얻을 것입니다:
{
    "code": 0,
    "data": [
        "LTCBCH",
        "ETHBCH",
        "ZECBCH",
        "DASHBCH"
    ],
    "message": "Ok"
}
하지만 우리는 그것을 파싱해야 합니다.
파싱하는 방법은 다양하지만,
json 패키지의 NewDecoder 또는 Unmarshal 기능을 사용할 수 있습니다.
struct 또는 map[string]interface{}로 디코딩할 수 있습니다.선호도에 따라 다르지만 이 경우 NewDecoder와 구조체 조합을 선호합니다.
따라서 다음과 같은 구조체를 만들어야 합니다.
type AllMarketList struct {
    Code    int    `json:"code"`
    Message string `json:"message"`
    Data    []string
}
또한 포함된 구조체를 가질 수 있습니다. 예를 들어 마지막 구조체를 두 개로 나눕니다.
type GeneralResponse struct {
    Code    int    `json:"code"`
    Message string `json:"message"`
}
type AllMarketList struct {
    GeneralResponse
    Data    []string
}
그리고 차이가 없습니다.
마지막으로 NewDecoder를 사용하여 raw_response를 AllMarketList 구조체로 디코딩합니다.
var allMarketList AllMarketList
json.NewDecoder(raw_response.Body).Decode(&allMarketList)
완성된 코드
package main
import (
    "encoding/json"
    "fmt"
    "net/http"
)
type AllMarketList struct {
    Code    int    `json:"code"`
    Message string `json:"message"`
    Data    []string
}
func main() {
    raw_response, _ := http.Get("https://api.coinex.com/v1/market/list")
    var allMarketList AllMarketList
    if err := json.NewDecoder(raw_response.Body).Decode(&allMarketList); err != nil {
        fmt.Println(err)
    }
    defer raw_response.Body.Close()
    fmt.Printf("%+v\n", allMarketList)
}
예 2
다음과 같은 json이 있다고 생각하십시오.
{
  "code": 0,
  "data": {
    "date": 1513865441609, # server time when returning
    "ticker": {
        "open": "10", # highest price
        "last": "10.00", # latest price 
        "vol": "110" # 24H volume
    }
  },
  "message" : "Ok"
}
디코딩 프로세스에서 몇 가지 사항을 개선할 예정입니다.
문제 1과 2는 디코딩하려는 구조체에 UnmarshalJSON 메서드를 구현하여 해결할 수 있습니다.
문제 3은 json 태그로 쉽게 해결됩니다. (아래 코드에서 언급했습니다)
최종 구조체는 다음과 같아야 합니다.
// Final struct
type SingleMarketStatistics struct {
    Code    int    `json:"code"`
    Message string `json:"message"`
    Data    TickerData
}
// Inner struct that we should implement to solve problem 2
type TickerData struct {
    ServerTime CTime   `json:"date"` // CTime is short for CustomTime
    Open       float64 `json:"open"`
    Close      float64 `json:"last"` // Different Attribute name and tag name
    Volume     float64 `json:"vol"` // Different Attribute name and tag name
}
// Custome time
// Inner struct that we should implement to solve problem 1
type CTime struct {
    time.Time
}
맞춤형 시간 구현
func (t *CTime) UnmarshalJSON(data []byte) error {
    // Ignore null, like in the main JSON package.
    if string(data) == "null" || string(data) == `""` {
        return nil
    }
    // Fractional seconds are handled implicitly by Parse.
    i, err := strconv.ParseInt(string(data), 10, 64)
    update := time.UnixMilli(i)
    *t = CTime{update}
    return err
}
그리고 더 이상 오류가 발생하지 않습니다!
이 메서드는 시간을 CTime으로 디코딩할 때마다 자동으로 사용됩니다(인터페이스 덕분에!)!
맞춤 데이터 구현
func (t *TickerData) UnmarshalJSON(data []byte) error {
    if string(data) == "null" || string(data) == `""` {
        return nil
    }
    // This is how this json really looks like.
    var realTicker struct {
        ServerTime CTime `json:"date"`
        Ticker     struct {
            // tags also can be omitted when we're using UnmarshalJSON.
            Open   string `json:"open"`
            Close  string `json:"last"`
            Volume string `json:"vol"`
        } `json:"ticker"`
    }
    // Unmarshal the json into the realTicker struct.
    if err := json.Unmarshal(data, &realTicker); err != nil {
        return err
    }
    // Set the fields to the new struct,
    // with any shape it has,
    // or anyhow you want.
    *t = TickerData{
        ServerTime: realTicker.ServerTime,
        Open:       realTicker.Ticker.Open,
        Close:      realTicker.Ticker.Close,
        Volume:     realTicker.Ticker.Volume,
    }
    return nil
}
이제 이전처럼 NewDecoder를 사용하면 됩니다. 변경할 필요가 없습니다.
var singleMarketStatistics SingleMarketStatistics 
json.NewDecoder(raw_response.Body).Decode(&allMarketList)
예 3
다음과 같은 JSON을 상상해보십시오.
{
  "asks": [ // This is a array of asks
    [ // This is a array of ONE ask
      "10.00", // Price of ONE ask
      "0.999", // Amount of ONE ask
    ]
  ],
  "bids": [ // Same structure as asks
    [
      "10.00",
      "1.000",
    ]
  ]
}
명확하게 알 수 있듯이 비전문적인 방식으로 "매수"를
[][]string로 디코딩하고 첫 번째 매도 가격asks[0][0] 및 금액asks[0][1]에 액세스해야 합니다.0이 가격이고 1이 금액이라는 것을 누가 기억합니까? 어느 것이 무엇입니까? 😄
따라서 UnmarshalJSON 메서드에서 관리하겠습니다.
또한 여기에도 존재하는 이전 예제의 문제 4를 해결할 것입니다.
type BidAsk struct {
    // Tags are not needed.
    Price  float64 `json:"price"`  // Bid or Ask price
    Amount float64 `json:"amount"` // Bid or Ask amount
}
func (t *BidAsk) UnmarshalJSON(data []byte) error {
    // Ignore null, like in the main JSON package.
    if string(data) == "null" || string(data) == `""` {
        return nil
    }
    // Unmarshal to real type.
    var bisask []string
    if err := json.Unmarshal(data, &bisask); err != nil {
        return err
    }
    // Change value type from string to float64.
    price, err := strconv.ParseFloat(bisask[0], 64)
    if err != nil {
        return err
    }
    amount, err := strconv.ParseFloat(bisask[1], 64)
    if err != nil {
        return err
    }
    // Map old structure to new structure.
    *t = BidAsk{
        Price:  price,
        Amount: amount,
    }
    return err
}
type MarketDepth struct {
    Asks   []BidAsk `json:"asks"` // Ask depth
    Bids   []BidAsk `json:"bids"` // Bid depth
}
다시, 우리는 단순히 다음을 사용합니다.
var marketDepth MarketDepth 
json.NewDecoder(raw_response.Body).Decode(&marketDepth)
결과의 아름다움을 즐기십시오.
for i, ask := range data.Data.Asks {
    fmt.Printf("Ask %v\n", i)
    fmt.Printf("  Price: %v\n", ask.Price) // here is the beauty
    fmt.Printf("  Amount: %v\n", ask.Amount) // here is the beauty
    fmt.Println()
}
for i, bid := range data.Data.Bids {
    fmt.Printf("Bid %v\n", i)
    fmt.Printf("  Price: %v\n", bid.Price) // here is the beauty
    fmt.Printf("  Amount: %v\n", bid.Amount) // here is the beauty
    fmt.Println()
}
                Reference
이 문제에 관하여(Golang에서 커스텀 방식으로 JSON을 언마샬링하는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/arshamalh/how-to-unmarshal-json-in-a-custom-way-in-golang-42m5텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
                                
                                
                                
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)