2017-12-12 10 views
0

現在、私のアプリケーションに入ってくるjsonオブジェクトのストリームを扱っています。それらを解析する最善の方法が何であるかを理解することがいくつか困難です。ストリームは、定義された型を持つオブジェクトで構成されます。問題は、オブジェクト内のフィールドの1つがタイプを変更することです。変更するタイプのストリームを構造体にアンマーシャリングする

[{ 
    "status": "closed", 
    "type": "transaction", 
    "transaction": { 
    "TransactionType": "TypeA", 
    "Account": "Some string", 
    "Fee": "14", 
    "date": 45325680 
    }, 
    "validated": true 
}, 

{ 
    "status": "closed", 
    "type": "transaction", 
    "transaction": { 
    "TransactionType" : "TypeB", 
    "Account" : "Some string", 
    "Fee": "42", 
    "Destination" : "Some string" 
    }, 
    "validated": true 
}] 

「親」は変更されていませんが、「トランザクション」は変更されていないことがわかります。私は説明しやすくするために "トランザクション"フィールドから多くのフィールドを削除しましたが、これは10-ish共通フィールドとそのタイプに依存する10-ish変更フィールドを持つタイプです。また、10種類のトランザクションタイプがあります。これは、すべてを1つの構造体に入れて、オプションのフィールドをたくさん持っていることをかなり面倒にしています。私はまた、トランザクションの種類ごとに1つの構造体について考えていましたが、これは機能しません。なぜなら、フィールドがどの型を親に持つべきかを指定する方法がないからです。

これらのオブジェクトを効果的に解析するにはどうすればよいですか?残念ながら、私はストリームから出てくる要素の構造を変更することはできません。これを解決する最良の方法は何でしょうか?

+1

異なるオブジェクトタイプの配列を持つ[Gson Parse Json]の可能な複製(https://stackoverflow.com/questions/14713736/gson-parse-json-with-array-with-different-object-types) –

+0

' TransactionType'はまだ文字列です。私は、 'transaction'構造体のどのフィールドが重要であるかを伝えるために使われていると思います。これは、可能なすべてのフィールドの信頼できるリストが存在し、トランザクションのタイプに基づいたフィールドを含むか含まないことを意味します。あなたは何を試しましたか、なぜそれは機能しませんでしたか? – Marc

+0

修正。問題は、そのような構造をアンマーシャリングする最も効率的な方法が何であるかを理解できない(またはわかりません)ということです。私は実際に、例えば 'RawMessage'のcontainsを使ってトランザクションフィールドをアンマーシャリングする方法を見つけ出すことができますが、どこにこの結果を置くのですか? "親"構造体にはトランザクションの種類ごとにフィールドが必要ですか?あるいは、私は 'interface {}'型のフィールドと "親"型構造体のトランザクションのタイプを示す文字列を持っていますか? – martijn9612

答えて

0

おそらくhttps://play.golang.com/p/j_u_ztw04M

package main 

import (
    "encoding/json" 
    "fmt" 
) 

type Stream []struct { 
    Status string `json:"status"` 
    Type string `json:"type"` 

    // map instead of struct 
    Transaction map[string]interface{} `json:"transaction"` 

    Validated bool `json:"validated"` 
} 

func main() { 

    stream := Stream{} 

    err := json.Unmarshal(rawj, &stream) 
    if err != nil { 
     fmt.Println("error:", err) 
     return 
    } 

    for i, s := range stream { 
     fmt.Println("thing:", i) 
     for k, v := range s.Transaction { 

      // do manual stuff here, perhaps long switch on k and/or 
      // as suggested by Cerise Limón type switch on v 
      fmt.Printf("key: %s, val: %v, val type: %T\n", k, v, v) 

     } 
     fmt.Println() 
    } 

} 

var rawj = []byte(`[{ 
    "status": "closed", 
    "type": "transaction", 
    "transaction": { 
    "TransactionType": "TypeA", 
    "Account": "Some string", 
    "Fee": "14", 
    "date": 45325680 
    }, 
    "validated": true 
}, 

{ 
    "status": "closed", 
    "type": "transaction", 
    "transaction": { 
    "TransactionType" : "TypeB", 
    "Account" : "Some string", 
    "Fee": "42", 
    "Destination" : "Some string" 
    }, 
    "validated": true 
}]`) 

あなたtransaction

map[string]interface{}として例を保つお楽しみに!

0
「トランザクション」構造体の

私は共通鍵直接的なタイプになるだろう(例えばstringint、など)とオプションのキーポインタ「omitemptyとその種類(*string*intなど)へ

type Transaction struct { 
    // Common fields are direct types... 
    TransactionType string 
    Account   string 
    Fee    string 

    // Optional fields are pointers with "omitempty"... 
    Date  *int `json:",omitempty"` 
    Destination *string `json:",omitempty"` 
} 

共通フィールドが常に存在しているが、おそらく存在するがnilの場合は、デフォルト(空)の値とオプションのフィールドが移入され、この方法:彼らは発生が存在しない場合、彼らはnilに設定されているように、「タグ省略した場合:

ts[0].Date = (*int) 45325680 
ts[0].Destination = nil 
ts[1].Date = nil 
ts[1].Destination = (*string) "Some string" 
0

各トランザクションタイプの構造体を定義し、2つのステップでアンマーシャリングを行います。まず、使用

type Stream []struct { 
    ... 
    TransactionRaw json.RawMessage `json:"transaction"` 
    ... 
} 

その後

type Transaction struct { 
    TransactionType string `json:"TransactionType"` 
    Account   string `json:"Account"` 
    Fee    string `json:"Fee"` 
} 

type TypeA struct { 
    Transaction 
    Date int `json:"date"` 
} 

等...

Playground example here

0

json.Unmarshalに2回目の呼び出しのためのタイプを決定するためにTransactionRawRegexp.FindStringSubmatchを使用し、私は反映使用していると思います片道[]map[string]interface{}

this answerには、反射型の変更型の使用についての例がありました。

関連する問題