2015-04-17 22 views
5

Việc ra khỏi hộp JSON mã hóa trong Go là thực sự tốt đẹp, nhưng tôi cần để có được đầu ra để phù hợp với một định dạng nhất định bằng cách thêm một lớp. Tôi đã tìm ra một cách, nhưng hy vọng rằng sẽ có một cách dễ dàng hơn cách tôi đang làm.Có cách nào dễ dàng hơn để thêm một lớp trên một đối tượng JSON bằng cách sử dụng Mã hóa JSON Golang không?

Dưới đây là ví dụ về cách tôi đang thực hiện.

import (
    "bytes" 
    "encoding/json" 
    "encoding/xml" 
    "fmt" 
) 
type Query struct { 
    XMLName xml.Name  `xml:"http://marklogic.com/appservices/search query" json:"-"` 
    Format int   `xml:"-" json:"-"` 
    Queries []interface{} `xml:",any" json:"queries"` 
} 
type TermQuery struct { 
    XMLName xml.Name `xml:"http://marklogic.com/appservices/search term-query" json:"-"` 
    Terms []string `xml:"http://marklogic.com/appservices/search text" json:"text"` 
    Weight float64 `xml:"http://marklogic.com/appservices/search weight,omitempty" json:"weight,omitempty"` 
} 
// use fakeQuery to avoid an infinite loop 
type fakeQuery Query 

//MarshalJSON for Query struct in a special way to add wraping {"query":...} 
func (q Query) MarshalJSON() ([]byte, error) { 
    return wrapJSON(`query`, fakeQuery(q)) 
} 
// use fakeTermQuery to avoid an infinite loop 
type fakeTermQuery TermQuery 

//MarshalJSON for TermQuery struct in a special way to add wraping {"term-query":...} 
func (q TermQuery) MarshalJSON() ([]byte, error) { 
    return wrapJSON(`term-query`, fakeTermQuery(q)) 
} 

func wrapJSON(name string, item interface{}) ([]byte, error) { 
    var buffer bytes.Buffer 
    b, err := json.Marshal(item) 
    buffer.Write([]byte(`{"`)) 
    buffer.Write([]byte(name)) 
    buffer.Write([]byte(`":`)) 
    buffer.Write(b) 
    buffer.Write([]byte(`}`)) 
    return buffer.Bytes(), err 
} 

Tôi có nhiều cấu trúc được xác định mà tôi cần thực hiện, vì vậy tôi hy vọng sẽ có một giải pháp tốt hơn sẽ không cho phép tôi với hơn 100 dòng mã để chỉ thêm trình bao bọc xung quanh đối tượng JSON. Lý tưởng nhất là tôi muốn một cái gì đó có thể đạt được ở tên phần tử XML được định nghĩa cho bộ mã hóa XML và sử dụng nó để bọc JSON.

Trong trường hợp của tôi, tôi đang sử dụng các hàm MarshalJSON vì các cấu trúc này có thể được lồng vào nhau. Nếu nó giúp tôi luôn biết rằng cấu trúc truy vấn là cấu trúc gốc.

Trả lời

2

Có lẽ tôi đang thiếu một cái gì đó, nhưng là điều này bạn đang tìm kiếm cho?

Tôi bắt đầu với ý tưởng tương tự như @Manawasp (sử dụng giao diện [string] {}) nhưng quyết định cố gắng lấy tên từ thẻ cấu trúc như bạn đã hỏi ... đây là những gì tôi đã đưa ra (* lưu ý: có thể có trường hợp lỗi unhandled, và điều này có thể overcomplicate cái gì đó có thể được xử lý khá dễ dàng với các giải pháp khác)

http://play.golang.org/p/qO6tDZjtXA

package main 

import (
    "fmt" 
    "reflect" 
    "strings" 
) 
import (
    "encoding/json" 
    "encoding/xml" 
    "errors" 
) 

type Query struct { 
    XMLName xml.Name `xml:"http://marklogic.com/appservices/search query" json:"-"` 
    Field1 string 
    Field2 int64 
} 

type TermQuery struct { 
    XMLName xml.Name `xml:"http://marklogic.com/appservices/search term-query" json:"-"` 
    Field3 string 
    Field4 int64 
} 

func getXmlName(d interface{}, label string) (string, bool) { 
    switch reflect.TypeOf(d).Kind() { 
    case reflect.Struct: 
     v, _ := reflect.TypeOf(d).FieldByName(label) 
     parts := strings.Split(v.Tag.Get("xml"), " ") 
     return parts[1], true 
    } 
    return "", false 
} 

func wrapJson(item interface{}) ([]byte, error) { 
    if n, ok := getXmlName(item, "XMLName"); ok { 
     b, err := json.Marshal(map[string]interface{}{n: item}) 
     if err != nil { 
      return nil, err 
     } 
     return b, nil 
    } 
    return nil, errors.New("You failed") 
} 

func main() { 
    // create a Query and encode it as {"query": {struct}} 
    q := Query{Field1: "hello", Field2: 42} 
    wrappedQ, err := wrapJson(q) 
    if err != nil { 
     fmt.Println(err) 
     return 
    } 
    fmt.Println(string(wrappedQ)) 

    // create a TermQuery and encode it as {"term-query": {struct}} 
    tq := TermQuery{Field3: "world", Field4: 99} 
    wrappedTQ, err := wrapJson(tq) 
    if err != nil { 
     fmt.Println(err) 
     return 
    } 
    fmt.Println(string(wrappedTQ)) 

} 

OUTPUT

{"query":{"Field1":"hello","Field2":42}} 
{"term-query":{"Field3":"world","Field4":99}} 

EDIT
Ok, đây là bản cập nhật ngay bây giờ mà tôi có thể thấy vấn đề của bạn là gì. Nó có thể là xấu xí, và nó có thể không được chống đạn (xử lý lỗi, vv) ... nhưng đối với thử nghiệm của tôi nó dường như làm những gì bạn muốn.

http://play.golang.org/p/8MloLP3X4H

package main 

import (
    "fmt" 
    "reflect" 
    "strings" 
) 
import (
    //"encoding/json" 
    "encoding/json" 
    "encoding/xml" 
    "errors" 
) 

type Query struct { 
    XMLName xml.Name `xml:"http://marklogic.com/appservices/search query" json:"-"` 
    Field1 string 
    Field2 int64 
    Queries []interface{} `xml:",any" json:"queries"` 
} 

type TermQuery struct { 
    XMLName xml.Name `xml:"http://marklogic.com/appservices/search term-query" json:"-"` 
    Field3 string 
    Field4 int64 
} 

func getXmlName(d interface{}, label string) (string, bool) { 
    switch reflect.TypeOf(d).Kind() { 
    case reflect.Struct: 
     v, _ := reflect.TypeOf(d).FieldByName(label) 
     parts := strings.Split(v.Tag.Get("xml"), " ") 
     return parts[1], true 
    default: 
     fmt.Println(reflect.TypeOf(d).Kind()) 
    } 
    return "", false 
} 

func wrapJson(item interface{}) (map[string]interface{}, error) { 
    if n, ok := getXmlName(item, "XMLName"); ok { 

     if k := reflect.ValueOf(item).FieldByName("Queries"); k.IsValid() { 
      for i := 0; i < k.Len(); i++ { 
       b, err1 := wrapJson(k.Index(i).Interface()) 
       if err1 != nil { 

        continue 
       } 
       k.Index(i).Set(reflect.ValueOf(b)) 

      } 

     } 
     return map[string]interface{}{n: item}, nil 
    } 
    return nil, errors.New("You failed") 
} 

func asJson(i interface{}) []byte { 
    b, err := json.Marshal(i) 
    if err != nil { 
     return []byte(`{"error": "too bad"}`) 
    } 
    return b 
} 

func main() { 

    // create a TermQuery and encode it as {"term-query": {struct}} 
    tq := TermQuery{Field3: "world", Field4: 99} 
    wrappedTQ, err := wrapJson(tq) 
    if err != nil { 
     fmt.Println(err) 
     return 
    } 

    fmt.Println(string(asJson(wrappedTQ))) 

    // create a Query and encode it as {"query": {struct}} 
    q := Query{ 
     Field1: "hello", 
     Field2: 42, 
     Queries: []interface{}{ 
      TermQuery{Field3: "world", Field4: 99}, 
      TermQuery{Field3: "yay, it works!", Field4: 666}, 
      Query{ 
       Field1: "Hi", 
       Field2: 21, 
       Queries: []interface{}{ 
        TermQuery{ 
         Field3: "omg", 
         Field4: 1, 
        }, 
       }, 
      }, 
     }, 
    } 
    wrappedQ, err := wrapJson(q) 
    if err != nil { 
     fmt.Println(err) 
     return 
    } 
    fmt.Println(string(asJson(wrappedQ))) 

} 

PRETTY-IN outout

{ 
    "query": { 
     "Field1": "hello", 
     "Field2": 42, 
     "queries": [ 
      { 
       "term-query": { 
        "Field3": "world", 
        "Field4": 99 
       } 
      }, 
      { 
       "term-query": { 
        "Field3": "yay, it works!", 
        "Field4": 666 
       } 
      }, 
      { 
       "query": { 
        "Field1": "Hi", 
        "Field2": 21, 
        "queries": [ 
         { 
          "term-query": { 
           "Field3": "omg", 
           "Field4": 1 
          } 
         } 
        ] 
       } 
      } 
     ] 
    } 
} 
+0

Điều này rất gần. Thật không may tôi có những tình huống các cấu trúc được lồng nhau. Vì vậy, một ví dụ đầu ra là '{" truy vấn ": {" truy vấn ": [{" thuật ngữ truy vấn ": {" văn bản ": [" dữ liệu "]}}]}}'. Đó là lý do tại sao tôi sử dụng các hàm MarshalJSON. – justdewit

+0

@justdewit Xem câu trả lời đã sửa đổi. Hãy cho tôi biết nếu điều này giải quyết câu hỏi ban đầu của bạn chính xác hơn. – sberry

+0

Cảm ơn bạn! Tốt hơn nhiều so với những gì tôi đang làm. – justdewit

2

Khi tôi bắt đầu sử dụng Go & Json Tôi cũng gặp phải vấn đề tương tự. Tôi giải quyết nó bằng cách đó

func wrapJSON(name string, item interface{}) ([]byte, error) { 
    wrapped := map[string]interface{}{ 
     name: item, 
    } 
    converted, err := json.Marshal(wrapped) 
    return converted 
} 

Lý tưởng nhất, đổi tên phương pháp của bạn wrapJSON-wrap trả lại một giao diện và sau khi chuyển đổi giao diện này để JSON hay XML

+0

Cảm ơn. Đó là sạch hơn những gì tôi có trong chức năng của tôi. Tôi đã hy vọng cho một giải pháp mà sẽ giúp đỡ với các mặt hàng lồng nhau, mặc dù. Đó là lý do tại sao tôi đã sử dụng các hàm MarshalJSON, vì TermQuery có thể là một trong các truy vấn của cấu trúc truy vấn. – justdewit

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