2014-10-10 20 views
5

Marjinali, bağlamına bağlı olarak JSON'a farklı bir yapıya sahip yapıyorum.JSON marshalling/unmarshalling aynı yapıya farklı JSON biçiminde mi gidiyor?

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

Ve bazen böyle sıralamakta istiyorum:

Örneğin, bazen böyle sıralamakta istiyorum

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

olmadan bunu yapmak için basit bir yolu var mı:

  1. 2 ayrı yapı oluşturma.
  2. Özel bir mareşal yazarak.
  3. PhoneNumber ve MailingAddress öğesinin dize değerlerini (etikette bir ihmalkarlıkla) geçici olarak kaldırarak, sonraları yeniden birleştirip yeniden ekleyin.

    1. etiketleri 2 takım belirtin ve hangilerinin kullanmak sıralayıcısı söyleyin:

    Keşke bir yolu yoktu.

  4. Etiketleri çalışma zamanında dinamik olarak değiştirin.

cevap

10

Ben açıkça "Bir özel Sıralayıcı yazmadan" söz biliyorum, ama durumda birileri bunu görür ve bunun nedeni karmaşıklığı kaçınılmalıdır düşünür, bir Özel Sıralayıcı size ne yapacağını yapmak istediğim gerçekten basittir:

all alan, harici paket tarafından ayarlanması gerekir, o zaman bir yöntem yapı veya alan cou üzerinde tanımlanabilir
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) 
} 

Herkese açıklanmalı (JSON'u özel marş motoru ile kodlandığından etkilemez). oyun alanında

Runnable örnek: http://play.golang.org/p/1N_iBzvuW4

+0

Bu hayal çok daha basit oldu. Bu yaklaşımın bir kombinasyonunu ve burada anlatılanları kullanarak sona erdim: http://attilaolah.eu/2014/09/10/json-and-struct-composition-in-go/ –

+0

Referans için bazı linkler: Marshaler http://golang.org/pkg/encoding/json/#Marshaler yazın. Blog makale: http://blog.golang.org/json-and-go –

+0

Aynı prensip, unshashalling için de geçerli olacaktır - http://golang.org/pkg/encoding/json/#Unmarshaler –

-1

Yansıma özelliğini kullanabilirsiniz, gerçekten en verimli çözümü değil, ancak kullanışlı.

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