2014-10-10 77 views
5

我有一個結構,我想不同的上下文元素到JSON不同。JSON編組/將相同的結構解組到不同的JSON格式中去?

例如,有時我想元帥是這樣的:

type MyStruct struct { 
     Nickname  string `json:"nickname"` 
     EmailAddress string `json:"email_address"` 
     PhoneNumber string `json:"-"` 
     MailingAddress string `json:"-"` 
    } 

有時我想元帥是這樣的:

type MyStruct struct { 
     Nickname  string `json:"nickname"` 
     EmailAddress string `json:"email_address"` 
     PhoneNumber string `json:"phone_number"` 
     MailingAddress string `json:"mailing_address"` 
    } 

有沒有一種簡單的方法來做到這一點沒有:

  1. 製作2個單獨的結構。
  2. 編寫自定義編組器。
  3. 暫時刪除PhoneNumber和MailingAddress的字符串值(標記爲omitempty),封送然後再添加回去。

如果只是有一個辦法:

  1. 指定2套標籤,告訴使用哪些封送拆。
  2. 在運行時動態更改標籤。

回答

10

我知道你明確提到「無需編寫自定義封」,但如果有人看到這一點,並認爲它應該被避免,因爲複雜的,一個自定義封做什麼你想要做的是非常簡單的:

type MyStruct struct { 
    Nickname  string `json:"nickname"` 
    EmailAddress string `json:"email_address"` 
    PhoneNumber string `json:"phone_number"` 
    MailingAddress string `json:"mailing_address"` 
    all   bool 
} 

func (ms MyStruct) MarshalJSON() ([]byte, error) { 
    m := map[string]interface{}{} // ideally use make with the right capacity 
    m["nickname"] = ms.Nickname 
    m["email_address"] = ms.EmailAddress 
    if ms.all { 
     m["phone_number"] = ms.PhoneNumber 
     m["mailing_address"] = ms.MailingAddress 
    } 
    return json.Marshal(m) 
} 

如果all領域應該由一個外部包裝進行設置,那麼方法可以在結構或現場湊定義ld被公開(不會影響JSON,因爲它是通過自定義封送拆分器編碼的)。在操場上

Runnable的例子:http://play.golang.org/p/1N_iBzvuW4

+0

這比我想象的要簡單得多。我最終使用了這種方法和這裏描述的方法的組合:http://attilaolah.eu/2014/09/10/json-and-struct-composition-in-go/ – 2014-10-10 17:44:58

+0

這裏有一些鏈接供參考: Marshaler type http://golang.org/pkg/encoding/json/#Marshaler。 博客文章:http://blog.golang.org/json-and-go – 2014-10-11 16:12:09

+0

同樣的原則適用於解組 - http://golang.org/pkg/encoding/json/#Unmarshaler – 2014-10-11 16:13:50

-1

您可以使用反射,而不是最有效的解決方案,但它很方便。

func MarshalSubset(obj interface{}, fields ...string) ([]byte, error) { 
    if len(fields) == 0 { 
     return json.Marshal(obj) 
    } 
    out := make(map[string]interface{}, len(fields)) 
    val := reflect.ValueOf(obj) 
    if val.Kind() == reflect.Ptr { 
     val = val.Elem() 
    } 
    if val.Kind() != reflect.Struct { 
     panic("not a struct") 
    } 
    typ := val.Type() 
    for _, f := range fields { 
     val := val.FieldByName(f).Interface() 
     rfld, _ := typ.FieldByName(f) 
     tag := strings.Split(rfld.Tag.Get("json"), ",") 
     if len(tag) > 0 { 
      f = tag[0] 
     } 
     out[f] = val 
    } 

    return json.Marshal(out) 
} 

playground