如何使用 Go 漂亮地打印 JSON?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19038598/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 19:50:43  来源:igfitidea点击:

How can I pretty-print JSON using Go?

jsongopretty-print

提问by Brad Peabody

Does anyone know of a simple way to pretty-print JSON output in Go?

有谁知道在 Go 中漂亮打印 JSON 输出的简单方法?

The stock http://golang.org/pkg/encoding/json/package does not seem to include functionality for this(EDIT: it does, see accepted answer) and a quick google doesn't turn up anything obvious.

股票http://golang.org/pkg/encoding/json/包似乎不包含此功能(编辑:它包含,请参阅已接受的答案)并且快速 google 没有发现任何明显的内容。

Uses I'm looking for are both pretty-printing the result of json.Marshaland just formatting a string full of JSON from wherever, so it's easier to read for debug purposes.

我正在寻找的用途是json.Marshal从任何地方漂亮地打印结果和格式化一个充满 JSON 的字符串,因此为了调试目的更容易阅读。

回答by Alexander Bauer

By pretty-print, I assume you mean indented, like so

通过漂亮的印刷,我假设你的意思是缩进,就像这样

{
    "data": 1234
}

rather than

而不是

{"data":1234}

The easiest way to do this is with MarshalIndent, which will let you specify how you would like it indented via the indentargument. Thus, json.MarshalIndent(data, "", " ")will pretty-print using four spaces for indentation.

最简单的方法是使用MarshalIndent,它可以让您通过indent参数指定您希望它如何缩进。因此,json.MarshalIndent(data, "", " ")将使用四个空格进行缩进进行漂亮打印。

回答by robyoder

The accepted answer is great if you have an object you want to turn into JSON. The question also mentions pretty-printing just any JSON string, and that's what I was trying to do. I just wanted to pretty-log some JSON from a POST request (specifically a CSP violation report).

如果您有一个要转换为 JSON 的对象,那么接受的答案就很好。这个问题还提到了漂亮地打印任何 JSON 字符串,这就是我想要做的。我只是想从 POST 请求(特别是CSP 违规报告)中漂亮地记录一些 JSON 。

To use MarshalIndent, you would have to Unmarshalthat into an object. If you need that, go for it, but I didn't. If you just need to pretty-print a byte array, plain Indentis your friend.

要使用MarshalIndent,您必须将Unmarshal其放入一个对象中。如果你需要那个,去吧,但我没有。如果你只需要漂亮地打印一个字节数组,plainIndent是你的朋友。

Here's what I ended up with:

这是我的结果:

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()))
}

回答by mh-cbon

For better memory usage, I guess this is better:

为了更好地使用内存,我想这更好:

var out io.Writer
enc := json.NewEncoder(out)
enc.SetIndent("", "    ")
if err := enc.Encode(data); err != nil {
    panic(err)
}

回答by Tyler Brock

I was frustrated by the lack of a fast, high quality way to marshal JSON to a colorized string in Go so I wrote my own Marshaller called ColorJSON.

我对在 Go 中缺乏快速、高质量的方式将 JSON 编组为彩色字符串感到沮丧,所以我编写了自己的 Marshaller 称为ColorJSON

With it, you can easily produce output like this using very little code:

有了它,您可以使用很少的代码轻松生成这样的输出:

ColorJSON sample output

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))
}

I'm writing the documentation for it now but I was excited to share my solution.

我现在正在为它编写文档,但我很高兴能分享我的解决方案。

回答by jpillora

EditLooking back, this is non-idiomatic Go. Small helper functions like this add an extra step of complexity. In general, the Go philosophy prefers to include the 3 simple lines over 1 tricky line.

编辑回过头来看,这是非惯用的 Go。像这样的小辅助函数增加了额外的复杂性。一般来说,围棋哲学更喜欢包含 3 条简单的代码而不是 1 条复杂的代码。



As @robyoder mentioned, json.Indentis the way to go. Thought I'd add this small prettyprintfunction:

正如@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/#/R4LWpkkHINor http://play.golang.org/p/R4LWpkkHIN

https://go-sandbox.com/#/R4LWpkkHINhttp://play.golang.org/p/R4LWpkkHIN

回答by Timmmm

Here's what I use. If it fails to pretty print the JSON it just returns the original string. Useful for printing HTTP responses that shouldcontain JSON.

这是我使用的。如果它无法漂亮地打印 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()
}

回答by Raed Shomali

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
}

回答by Clare Chu

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))
}

How it looks like

看起来如何

回答by Pawe? Szczur

A simple off the shelf pretty printer in Go. One can compile it to a binary through:

一个简单的现成漂亮的 Go 打印机。可以通过以下方式将其编译为二进制文件:

go build -o jsonformat jsonformat.go

It reads from standard input, writes to standard output and allow to set indentation:

它从标准输入读取,写入标准输出并允许设置缩进:

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)
    }
}

It allows to run a bash commands like:

它允许运行 bash 命令,例如:

cat myfile | jsonformat | grep "key"

回答by accnameowl

i am sort of new to go, but this is what i gathered up so far:

我有点陌生,但这是我到目前为止收集的内容:

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
}

This is the execution of the function, and just standard

这是函数的执行,只是标准的

b, _ := json.MarshalIndent(SomeType, "", "\t")

Code:

代码:

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)

}