如何使用 Go 漂亮地打印 JSON?
Posted
技术标签:
【中文标题】如何使用 Go 漂亮地打印 JSON?【英文标题】:How can I pretty-print JSON using Go? 【发布时间】:2013-10-03 00:47:38 【问题描述】:有人知道在 Go 中漂亮打印 JSON 输出的简单方法吗?
stock http://golang.org/pkg/encoding/json/ 包似乎不包含此功能(编辑:确实如此,请参阅已接受的答案)并且快速谷歌并没有发现任何明显的东西。
我正在寻找的用途既可以漂亮地打印 json.Marshal
的结果,也可以从任何地方格式化一个充满 JSON 的字符串,因此更易于阅读以进行调试。
【问题讨论】:
警告:在我的实验中,在 JSON 字典中,字符串索引必须括在括号中。所以,name: "value"
不行,尽管大多数 javascript 解释器都使用它。 仅 "name": "value"
将与 Go JSON 库函数一起使用。
@peterh 我认为您将 JavaScript 文字语法与 JSON 本身混淆了。 JSON 规范 (json.org) 明确指出只允许使用字符串文字(这意味着它需要引号),而 JS 语言对象语法没有这个限制。 Go 库遵循规范。
【参考方案1】:
推荐的答案
Go Language
通过漂亮的打印,我假设你的意思是缩进,像这样
"data": 1234
而不是
"data":1234
最简单的方法是使用MarshalIndent
,它可以让您通过indent
参数指定您希望缩进的方式。因此,json.MarshalIndent(data, "", " ")
将使用四个空格缩进进行漂亮打印。
【讨论】:
是的,看起来就是这样——它已经内置了,只剩下在 pkg 文档中包含关键字“pretty-print”,以便下一个搜索的人找到它。 (将为文档维护者留下反馈说明。)谢谢!json.MarshalIndent(data, "", "\t")
如果你想要标签。
json.MarshalIndent(data, "", "\t?")
如果你想要...虎斑猫... 对不起
json.MarshalIndent(data, "", " ?")
如果你想要 .... 间隔猫... 对不起
如果您尝试将此 json 打印到控制台:MarshalIndent 返回 ([]byte, error)。只需将 []byte 传递给 string() 并打印,例如j, _ := json.MarshalIndent(data, "", "?"); fmt.Println(string(j))
【参考方案2】:
如果您有一个想要转换为 JSON 的对象,那么接受的答案是很好的。该问题还提到漂亮打印任何 JSON 字符串,这就是我想要做的。我只是想从 POST 请求(特别是 CSP violation report)中漂亮地记录一些 JSON。
要使用MarshalIndent
,您必须将Unmarshal
放入一个对象中。如果你需要,就去吧,但我没有。如果你只需要漂亮地打印一个字节数组,plain Indent
是你的朋友。
这就是我最终得到的结果:
import (
"bytes"
"encoding/json"
"log"
"net/http"
)
func HandleCSPViolationRequest(w http.ResponseWriter, req *http.Request)
body := App.MustReadBody(req, w)
if body == nil
return
var prettyJSON bytes.Buffer
error := json.Indent(&prettyJSON, body, "", "\t")
if error != nil
log.Println("JSON parse error: ", error)
App.BadRequest(w)
return
log.Println("CSP Violation:", string(prettyJSON.Bytes()))
【讨论】:
谢谢!这很有帮助。只是一个小评论,而不是string(prettyJSON.Bytes())
你可以做prettyJSON.String()
【参考方案3】:
为了更好地使用内存,我想这样更好:
var out io.Writer
enc := json.NewEncoder(out)
enc.SetIndent("", " ")
if err := enc.Encode(data); err != nil
panic(err)
【讨论】:
最近添加了SetIndent
吗?大多数人基本上都不知道它。
@chappjc SetIndent
(最初名为Indent
)显然是在2016年3月添加并在Go 1.7中发布的,大约在这个问题最初提出3年后:github.com/golang/go/commit/…github.com/golang/go/commit/…
这个和json.MarshalIndent(..)
的使用有什么内存比较吗?
@ChenA。这似乎并不需要。两种实现都非常清楚它们的优缺点。对于任何在内存中的大小 > 用于流式编组它的缓冲区长度的对象,流编码器将比非流编码器消耗更少的内存。最后一个编码器需要在内存中保存相同数据的表示形式,即原始版本及其编码版本。【参考方案4】:
我对在 Go 中将 JSON 编组为彩色字符串缺乏快速、高质量的方法感到沮丧,因此我编写了自己的 Marshaller,名为 ColorJSON。
有了它,你可以用很少的代码轻松地产生这样的输出:
package main
import (
"fmt"
"encoding/json"
"github.com/TylerBrock/colorjson"
)
func main()
str := `
"str": "foo",
"num": 100,
"bool": false,
"null": null,
"array": ["foo", "bar", "baz"],
"obj": "a": 1, "b": 2
`
var obj map[string]interface
json.Unmarshal([]byte(str), &obj)
// Make a custom formatter with indent set
f := colorjson.NewFormatter()
f.Indent = 4
// Marshall the Colorized JSON
s, _ := f.Marshal(obj)
fmt.Println(string(s))
我现在正在为其编写文档,但我很高兴能分享我的解决方案。
【讨论】:
非常感谢!非常酷的包,用于我的商业需求!【参考方案5】:编辑 回过头来看,这不是惯用的 Go。像这样的小辅助函数增加了额外的复杂性。一般来说,围棋哲学更喜欢包含 3 条简单的行而不是 1 条棘手的行。
正如@robyoder 提到的,json.Indent
是要走的路。以为我会添加这个小的prettyprint
函数:
package main
import (
"bytes"
"encoding/json"
"fmt"
)
//dont do this, see above edit
func prettyprint(b []byte) ([]byte, error)
var out bytes.Buffer
err := json.Indent(&out, b, "", " ")
return out.Bytes(), err
func main()
b := []byte(`"hello": "123"`)
b, _ = prettyprint(b)
fmt.Printf("%s", b)
https://go-sandbox.com/#/R4LWpkkHIN 或http://play.golang.org/p/R4LWpkkHIN
【讨论】:
【参考方案6】:这是我使用的。如果它无法漂亮地打印 JSON,它只会返回原始字符串。对于打印应该包含 JSON 的 HTTP 响应很有用。
import (
"encoding/json"
"bytes"
)
func jsonPrettyPrint(in string) string
var out bytes.Buffer
err := json.Indent(&out, []byte(in), "", "\t")
if err != nil
return in
return out.String()
【讨论】:
【参考方案7】:package cube
import (
"encoding/json"
"fmt"
"github.com/magiconair/properties/assert"
"k8s.io/api/rbac/v1beta1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"testing"
)
func TestRole(t *testing.T)
clusterRoleBind := &v1beta1.ClusterRoleBinding
ObjectMeta: v1.ObjectMeta
Name: "serviceaccounts-cluster-admin",
,
RoleRef: v1beta1.RoleRef
APIGroup: "rbac.authorization.k8s.io",
Kind: "ClusterRole",
Name: "cluster-admin",
,
Subjects: []v1beta1.Subject
Kind: "Group",
APIGroup: "rbac.authorization.k8s.io",
Name: "system:serviceaccounts",
,
,
b, err := json.MarshalIndent(clusterRoleBind, "", " ")
assert.Equal(t, nil, err)
fmt.Println(string(b))
【讨论】:
【参考方案8】:Here is my solution:
import (
"bytes"
"encoding/json"
)
const (
empty = ""
tab = "\t"
)
func PrettyJson(data interface) (string, error)
buffer := new(bytes.Buffer)
encoder := json.NewEncoder(buffer)
encoder.SetIndent(empty, tab)
err := encoder.Encode(data)
if err != nil
return empty, err
return buffer.String(), nil
【讨论】:
【参考方案9】://You can do it with json.MarshalIndent(data, "", " ")
package main
import(
"fmt"
"encoding/json" //Import package
)
//Create struct
type Users struct
ID int
NAME string
//Asign struct
var user []Users
func main()
//Append data to variable user
user = append(user, Users1, "Saturn Rings")
//Use json package the blank spaces are for the indent
data, _ := json.MarshalIndent(user, "", " ")
//Print json formatted
fmt.Println(string(data))
【讨论】:
【参考方案10】:Go 中一个简单的现成漂亮打印机。可以通过以下方式将其编译为二进制文件:
go build -o jsonformat jsonformat.go
它从标准输入读取,写入标准输出并允许设置缩进:
package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"os"
)
func main()
indent := flag.String("indent", " ", "indentation string/character for formatter")
flag.Parse()
src, err := ioutil.ReadAll(os.Stdin)
if err != nil
fmt.Fprintf(os.Stderr, "problem reading: %s", err)
os.Exit(1)
dst := &bytes.Buffer
if err := json.Indent(dst, src, "", *indent); err != nil
fmt.Fprintf(os.Stderr, "problem formatting: %s", err)
os.Exit(1)
if _, err = dst.WriteTo(os.Stdout); err != nil
fmt.Fprintf(os.Stderr, "problem writing: %s", err)
os.Exit(1)
它允许运行 bash 命令,例如:
cat myfile | jsonformat | grep "key"
【讨论】:
【参考方案11】:http.ResponseWriter 的另一个例子。
import (
"encoding/json"
"net/http"
)
func main()
var w http.ResponseWriter
type About struct
ProgName string
Version string
goObj := AboutProgName: "demo", Version: "0.0.0"
beautifulJsonByte, err := json.MarshalIndent(goObj, "", " ")
if err != nil
panic(err)
_, _ = w.Write(beautifulJsonByte)
输出
"ProgName": "demo",
"Version": "0.0.0"
【讨论】:
【参考方案12】:我有点新手,但这是我到目前为止收集的内容:
package srf
import (
"bytes"
"encoding/json"
"os"
)
func WriteDataToFileAsJSON(data interface, filedir string) (int, error)
//write data as buffer to json encoder
buffer := new(bytes.Buffer)
encoder := json.NewEncoder(buffer)
encoder.SetIndent("", "\t")
err := encoder.Encode(data)
if err != nil
return 0, err
file, err := os.OpenFile(filedir, os.O_RDWR|os.O_CREATE, 0755)
if err != nil
return 0, err
n, err := file.Write(buffer.Bytes())
if err != nil
return 0, err
return n, nil
这是函数的执行,只是标准的
b, _ := json.MarshalIndent(SomeType, "", "\t")
代码:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
minerals "./minerals"
srf "./srf"
)
func main()
//array of Test struct
var SomeType [10]minerals.Test
//Create 10 units of some random data to write
for a := 0; a < 10; a++
SomeType[a] = minerals.Test
Name: "Rand",
Id: 123,
A: "desc",
Num: 999,
Link: "somelink",
People: []string"John Doe", "Aby Daby",
//writes aditional data to existing file, or creates a new file
n, err := srf.WriteDataToFileAsJSON(SomeType, "test2.json")
if err != nil
log.Fatal(err)
fmt.Println("srf printed ", n, " bytes to ", "test2.json")
//overrides previous file
b, _ := json.MarshalIndent(SomeType, "", "\t")
ioutil.WriteFile("test.json", b, 0644)
【讨论】:
【参考方案13】:如果你想创建一个命令行实用程序来漂亮地打印 JSON
package main
import ("fmt"
"encoding/json"
"os"
"bufio"
"bytes"
)
func main()
var out bytes.Buffer
reader := bufio.NewReader(os.Stdin)
text, _ := reader.ReadString('\n')
err := json.Indent(&out, []byte(text), "", " ")
if err != nil
fmt.Println(err)
fmt.Println(string(out.Bytes()))
echo "\"boo\":\"moo\"" | go run main.go
将产生以下输出:
"boo": "moo"
随意构建二进制文件
go build main.go
并将其放入/usr/local/bin
【讨论】:
以上是关于如何使用 Go 漂亮地打印 JSON?的主要内容,如果未能解决你的问题,请参考以下文章