首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否有更简单的方法可以使用Golang编码在JSON对象上添加层?

是否有更简单的方法可以使用Golang编码在JSON对象上添加层?
EN

Stack Overflow用户
提问于 2015-04-17 02:15:40
回答 4查看 2.7K关注 0票数 6

Go中的开箱即用JSON编码非常好,但是我需要通过添加一个层来获得与特定格式相匹配的输出。我想出了一个办法,但我希望有一个比我现在做的更容易的方法。

下面是我如何做这件事的一个例子。

代码语言:javascript
复制
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
}

我有很多已定义的结构,我需要这样做,所以我希望有一个更好的解决方案,它不会留给我100+代码行,只需在JSON对象周围添加一个包装器。理想情况下,我希望能够在为XML编码器定义的XML元素名称上达到峰值,并使用它包装JSON。

在我的例子中,我使用MarshalJSON函数,因为这些结构可以嵌套。如果有帮助的话,我总是知道查询结构是根结构。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-04-17 04:15:38

当我开始使用Go & Json时,我也遇到了同样的问题。我解决了这个问题

代码语言:javascript
复制
func wrapJSON(name string, item interface{}) ([]byte, error) {
    wrapped := map[string]interface{}{
       name: item,
    }
    converted, err := json.Marshal(wrapped)
    return converted
}

理想情况下,将方法wrapJSON重命名为返回接口的wrap,并在将该接口转换为JSON或XML之后

票数 6
EN

Stack Overflow用户

发布于 2015-04-17 04:37:08

也许我错过了什么,但这就是你要找的吗?

我一开始与@Manawasp (使用映射接口{})的想法相同,但决定尝试从struct标记中获取名称,就像您询问的那样.下面是我想出的(*注意:可能有一些未处理的错误案例,这可能会使其他解决方案很容易处理的事情变得过于复杂)

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

代码语言:javascript
复制
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))

}

输出

代码语言:javascript
复制
{"query":{"Field1":"hello","Field2":42}}
{"term-query":{"Field3":"world","Field4":99}}

编辑

好的,这是一个更新,现在我可以看到你的问题是什么。它可能很难看,也可能不是防弹(错误处理等).但对我来说它似乎能做你想做的事。

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

代码语言:javascript
复制
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)))

}

漂亮印刷的OUTOUT

代码语言:javascript
复制
{
    "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
                            }
                        }
                    ]
                }
            }
        ]
    }
}
票数 2
EN

Stack Overflow用户

发布于 2022-07-02 02:42:43

在JSON封送处理程序中,您可以使用各种JSON标记再定义一个(匿名)结构,并添加所需的包装。

由于您已经定义了JSON封送处理程序,所以在原始结构中定义的任何标记都可能被JSON封送处理程序实现覆盖。

高朗游乐场

代码语言:javascript
复制
type Book struct {
    Title     string
    Author    string
    Language  string
    Publisher string
}

func (b Book) MarshalJSON() ([]byte, error) {
    type BookDetailJSON struct {
        Name      string `json:"Title"`
        Author    string
        Language  string `json:",omitempty"`
        Publisher string `json:"-"`
    }
    type BookJSON struct {
        Book BookDetailJSON `json:"Novel"`
    }

    return json.Marshal(BookJSON{BookDetailJSON{
        Name:      b.Title,
        Author:    b.Author,
        Language:  b.Language,
        Publisher: b.Publisher,
    }})
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29689092

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档