如果我理解正確的問題,從您的其他評論,然後 輸入可能包含任何任意未知名額外的字段(和類型?) 和你想/這些需要訪問。 如果只是爲了以後重新編組,那麼json.RawMessage
類型將是有趣的。
理想encoding/json
將有一個特殊的標記 (如",any"
encoding/xml
標籤) 會自動收集任何多餘/未引用JSON物品放入或者是 map[string]interface{}
或map[string]json.RawMessage
場。 然而,我找不到任何這樣的功能,也沒有找到一個明顯的方式來模仿匿名結構(但我沒有很努力)。
編輯:有an open issue in the Go project for this feature。很顯然,一個變更已經提交併部分回顧了Go 1.2,但最終沒有被接受。
做不到這一點,有幾個方法,你可以做的正是你有什麼建議, 作出X定製的(聯合國)和編組回調到JSON包處理[]A
和[]B
。
下面是一個快速拋出的例子, 可能有更好/更清晰/更安全的方法來做到這一點。 (在本例中,A和B可以是任意複雜的,也許包含本身具有自定義(UN)編組方法的類型。)
package main
import (
"encoding/json"
"fmt"
)
type A struct {
AF1 string
}
type B struct {
BF1 string
}
type X struct {
Things []A
Thangs []B
// Or perhaps json.RawMessage if you just
// want to pass them through.
// Or map of string/int/etc if the value type is fixed.
Extra map[string]interface{}
}
// Marshal Way 1: call unmarshal twice on whole input
type xsub struct {
Things []A `json:"things"`
Thangs []B `json:"thangs"`
}
func (x *X) _UnmarshalJSON(b []byte) error {
// First unmarshall the known keys part:
var tmp xsub
if err := json.Unmarshal(b, &tmp); err != nil {
return err
}
// Then unmarshall the whole thing again:
var vals map[string]interface{}
if err := json.Unmarshal(b, &vals); err != nil {
return err
}
// Everything worked, chuck the map entries for
// "known" fields and store results.
delete(vals, "things")
delete(vals, "thangs")
x.Things = tmp.Things
x.Thangs = tmp.Thangs
x.Extra = vals
return nil
}
// Way 2:
func (x *X) UnmarshalJSON(b []byte) error {
// Only partially decode:
var tmp map[string]json.RawMessage
if err := json.Unmarshal(b, &tmp); err != nil {
return err
}
// Now handle the known fields:
var things []A
if err := json.Unmarshal(tmp["things"], &things); err != nil {
return err
}
var thangs []B
if err := json.Unmarshal(tmp["thangs"], &thangs); err != nil {
return err
}
// And the unknown fields.
var extra map[string]interface{}
// Either:
if true {
// this has more calls to Unmarshal, but may be more desirable
// as it completely skips over the already handled things/thangs.
delete(tmp, "things")
delete(tmp, "thangs")
// If you only needed to store the json.RawMessage for use
// in MarshalJSON then you'd just store "tmp" and stop here.
extra = make(map[string]interface{}, len(tmp))
for k, raw := range tmp {
var v interface{}
if err := json.Unmarshal(raw, &v); err != nil {
return err
}
extra[k] = v
}
} else { // Or:
// just one more call to Unmarshal, but it will waste
// time with things/thangs again.
if err := json.Unmarshal(b, &extra); err != nil {
return err
}
delete(extra, "things")
delete(extra, "thangs")
}
// no error, we can store the results
x.Things = things
x.Thangs = thangs
x.Extra = extra
return nil
}
func (x X) MarshalJSON() ([]byte, error) {
// abusing/reusing x.Extra, could copy map instead
x.Extra["things"] = x.Things
x.Extra["thangs"] = x.Thangs
result, err := json.Marshal(x.Extra)
delete(x.Extra, "things")
delete(x.Extra, "thangs")
return result, err
}
func main() {
inputs := []string{
`{"things": [], "thangs": []}`,
`
{
"things": [
{
"AF1": "foo"
},
{
"AF1": "bar"
}
],
"thangs": [
{
"BF1": "string value"
}
],
"xRandomKey": "not known ahead of time",
"xAreValueTypesKnown": 172
}`,
}
for _, in := range inputs {
fmt.Printf("\nUnmarshal(%q):\n", in)
var x X
err := json.Unmarshal([]byte(in), &x)
if err != nil {
fmt.Println("unmarshal:", err)
} else {
fmt.Printf("\tas X: %+v\n", x)
fmt.Printf("\twith map: %v\n", x.Extra)
out, err := json.Marshal(x)
if err != nil {
fmt.Println("marshal:", err)
continue
}
fmt.Printf("\tRemarshals to: %s\n", out)
}
}
}
Run on Playground
如果我理解下面的評論,請編輯的問題(可能帶有示例JSON輸入)來明確輸入可以具有任何鍵/值,而不僅僅是「Item1」(例如,它聽起來像是「{/ * A和B的* /,」somekey「:」someval「,」otherkey 「:42}'可能是有效的輸入 – 2015-04-06 03:20:01
嗨,我不確定你是否看到過這個,或者它是否有幫助(這就是爲什麼我只寫評論,也許有人在這個問題上磕磕碰碰會覺得這很有用),但一些偉大的東西有關JSON和Go的內容將在本次演講中討論:https://www.youtube.com/watch?v = YgnD27GFcyA 看來你想編寫自己的Unmarshall for struct X,因爲他會討論如果我理解你的問題 – user3591723 2015-04-06 06:27:02