如何在Go中自定义JSON编码输出?

时间:2015-04-21 10:13:49

标签: json go

我想自定义结构的编码格式但出错: json:为类型main.Info调用MarshalJSON时出错:文字中的无效字符'o'为false(期待'a') 我的代码出了什么问题?

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "log"
)

type Info struct {
    name string
    flag bool
}

func (i Info) MarshalJSON() ([]byte, error) {
    var b bytes.Buffer
    b.Write([]byte(i.name))
    if i.flag {
        b.Write([]byte(`"true"`))
    } else {
        b.Write([]byte(`"false"`))
    }   
    return b.Bytes(), nil 
}

func main() {
    a := []Info{
        {"foo", true},
        {"bar", false},
    }   
    out, err := json.Marshal(a)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf(string(out))
}

3 个答案:

答案 0 :(得分:2)

您的代码生成无效的JSON文本。

您也应该写出字段的名称,为了安全起见,字段名称和string不引用bool值(否则Go json包不会将其解组为bool(例如)。同样将您的值括在括号{}中,如下所示:

b.Write([]byte(`{"name":"`))       // started with {
b.Write([]byte(i.name))
b.Write([]byte(`","flag":`))       // note the , between values
if i.flag {
    b.Write([]byte(`true`))        // don't quote boolean value
} else {
    b.Write([]byte(`false`))       // don't quote boolean value
}
b.Write([]byte(`}`))               // must close with }

输出(尝试Go Playground上的完整申请):

[{"name":"foo","flag":true},{"name":"bar","flag":false}]

但是因为你在编组期间没有做任何特别的事情,只需导出字段(通过用大写字母开头),json包将自动编组/解组它:

type Info struct {
    Name string
    Flag bool
}

Go Playground上试用此版本。

输出(请注意大写字母"Name""Flag"):

[{"Name":"foo","Flag":true},{"Name":"bar","Flag":false}]

如果要在JSON文本中使用不同的名称,也可以使用标记,如下所示:

type Info struct {
    Name string `json:"name"`
    Flag bool   `json:"flag"`
}

这将再次产生一个带有较低名称的输出:

[{"name":"foo","flag":true},{"name":"bar","flag":false}]

阅读json.Marshal()函数的文档,了解使用struct标签可以执行的其他选项和自定义。

答案 1 :(得分:0)

将自己的字符串写入缓冲区会消除json.Marshal()的目的。也许是这样的:

type Info struct {
    Name string `json:"name"` // Struct fields should have capital first letter
                              // if you want it to be found by the marshaller.
    Flag bool `json:"flag"`   // json:"flag" assigns the object key in json format
}

然后像:

myInfo := Info {
    Name: "Foo",
    Flag: true,
}
slc, _ := json.Marshal(myInfo)
fmt.Println(string(slc))

答案 2 :(得分:0)

问题在于,在MarshalJSON的实施过程中,您期望为您带来很多神奇的事情。不幸的是,您需要查看它,就像您从头开始构建字符串一样。意思是这个;

func (i Info) MarshalJSON() ([]byte, error) {
    var b bytes.Buffer
    b.Write([]byte(i.name))
    if i.flag {
        b.Write([]byte(`"true"`))
    } else {
        b.Write([]byte(`"false"`))
    }   
    return b.Bytes(), nil 
}

需要看起来更像这样;

func (i Info) MarshalJSON() ([]byte, error) {
    var b bytes.Buffer
    b.Write([]byte(`{"name":"`))       
    b.Write([]byte(i.name))
    b.Write([]byte(`","flag":`))        
    if i.flag {
        b.Write([]byte(`"true"`))        
    } else {
       b.Write([]byte(`"false"`))       
    }
    b.Write([]byte(`}`))
}

另外,我假设你合法地想要一个字符串作为布尔值(否则为什么要实现这个方法,对吧?),如果没有,那么你会想要摆脱if而只是使用{{1 }}