2014-10-10 16 views
5

Tôi có một cấu trúc mà tôi muốn Soạn thành JSON khác nhau tùy thuộc vào ngữ cảnh.JSON marshalling/unmarshalling cùng một cấu trúc để định dạng JSON khác nhau trong đi?

Ví dụ, đôi khi tôi muốn sắp xếp như thế này:

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

Và đôi khi tôi muốn sắp xếp như thế này:

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

Có một cách đơn giản để làm điều này mà không cần:

  1. Tạo 2 cấu trúc riêng biệt.
  2. Viết trình chỉnh sửa tùy chỉnh.
  3. Tạm thời xóa các giá trị chuỗi cho PhoneNumber và MailingAddress (với bỏ qua trên thẻ), marshaling và sau đó thêm lại chúng.

Nếu chỉ có một cách để:

  1. Xác định 2 bộ thẻ và nói với marshaler nào để sử dụng.
  2. Tự động thay đổi thẻ khi chạy.

Trả lời

10

Tôi biết bạn rõ ràng đề cập đến "mà không cần viết một marshaler tùy chỉnh", nhưng trong trường hợp ai đó nhìn thấy điều này và nghĩ rằng nó nên tránh vì sự phức tạp, một marshaler tùy chỉnh để làm những gì bạn muốn làm là thực sự đơn giản:

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) 
} 

Nếu trường all nên được thiết lập bởi một gói bên ngoài, sau đó là một phương pháp có thể được xác định trên các cấu trúc, hoặc các lĩnh vực cou ld được công khai (sẽ không ảnh hưởng đến JSON vì nó được mã hóa thông qua trình sắp xếp tùy chỉnh).

Ví dụ có thể chạy trên sân chơi: http://play.golang.org/p/1N_iBzvuW4

+0

Điều này đơn giản hơn nhiều so với tôi tưởng tượng. Tôi đã kết thúc bằng cách sử dụng một sự kết hợp của phương pháp này và một trong những mô tả ở đây: http://attilaolah.eu/2014/09/10/json-and-struct-composition-in-go/ –

+0

Dưới đây là một số liên kết để tham khảo: Loại Marshaler http://golang.org/pkg/encoding/json/#Marshaler. Bài viết trên blog: http://blog.golang.org/json-and-go –

+0

Nguyên tắc tương tự sẽ áp dụng cho unmarshalling - http://golang.org/pkg/encoding/json/#Unmarshaler –

-1

Bạn có thể sử dụng phản chiếu, không thực sự là giải pháp hiệu quả nhất nhưng thuận tiện.

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

Các vấn đề liên quan