Làm cách nào tôi có thể in JSON đẹp bằng Go?


190

Có ai biết một cách đơn giản để in đầu ra JSON đẹp trong Go không?

Cổ phiếu http://golang.org/pkg/encoding/json/ gói dường như không bao gồm chức năng cho điều này (EDIT: nó, xem câu trả lời được chấp nhận) và một google nhanh chóng không bật lên bất cứ điều gì rõ ràng.

Các ứng dụng tôi đang tìm kiếm đều đẹp - in kết quả json.Marshalvà chỉ định dạng một chuỗi đầy JSON từ mọi nơi, vì vậy dễ đọc hơn cho mục đích gỡ lỗi.


Cảnh báo: trong các thử nghiệm của tôi, trong từ điển JSON, các chỉ mục chuỗi phải được đặt trong ngoặc đơn. Vì vậy, {name: "value"}sẽ không ổn, mặc dù hầu hết các trình thông dịch Javascript sử dụng nó . Chỉ {"name": "value"} sẽ hoạt động với các chức năng thư viện Go JSON.
peterh - Phục hồi Monica

2
@peterh Tôi nghĩ bạn đang nhầm lẫn cú pháp chữ JavaScript với JSON đúng. Thông số JSON ( json.org ) chỉ rõ rằng chỉ cho phép các chuỗi ký tự chuỗi (có nghĩa là nó cần dấu ngoặc kép), trong khi cú pháp đối tượng ngôn ngữ JS không có hạn chế đó. Thư viện Go đang theo thông số kỹ thuật.
Brad Peabody

Câu trả lời:


295

Bằng cách in đẹp, tôi giả sử bạn có nghĩa là thụt lề, như vậy

{
    "data": 1234
}

thay vì

{"data":1234}

Cách dễ nhất để làm điều này là với MarshalIndent, nó sẽ cho phép bạn chỉ định cách bạn muốn nó thụt lề thông qua indentđối số. Do đó, json.MarshalIndent(data, "", " ")sẽ in đẹp bằng cách sử dụng bốn khoảng trắng để thụt lề.


17
Vâng, có vẻ như chỉ là một thứ - nó đã được tích hợp sẵn, chỉ còn lại là bao gồm từ khóa "in đẹp" trong tài liệu pkg để người tìm kiếm tiếp theo tìm thấy nó. (Sẽ để lại một ghi chú phản hồi cho những người duy trì tài liệu.) Tks!
Brad Peabody

37
json.MarshalIndent(data, "", "\t")nếu bạn muốn các tab.
Kyle Brandt

77
json.MarshalIndent(data, "", "🐱")nếu bạn muốn mèo. xin lỗi
briiC

43
json.MarshalIndent(data, "", "\t🐱")nếu bạn muốn ... mèo tabby ... xin lỗi
Davos

78

Câu trả lời được chấp nhận là tuyệt vời nếu bạn có một đối tượng bạn muốn biến thành JSON. Câu hỏi cũng đề cập đến việc in đẹp bất kỳ chuỗi JSON nào và đó là điều tôi đang cố gắng thực hiện. Tôi chỉ muốn ghi nhật ký một số JSON từ yêu cầu POST (cụ thể là báo cáo vi phạm CSP ).

Để sử dụng MarshalIndent, bạn sẽ phải Unmarshalđiều đó thành một đối tượng. Nếu bạn cần điều đó, đi cho nó, nhưng tôi đã không. Nếu bạn chỉ cần in một mảng byte, đơn giản Indentlà bạn của bạn.

Đây là những gì tôi đã kết thúc với:

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

48

Để sử dụng bộ nhớ tốt hơn, tôi đoán điều này tốt hơn:

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

Đã SetIndentđược thêm gần đây? Nó hầu như không được biết đến với hầu hết.
chappjc

1
@chappjc SetIndent(tên ban đầu Indent) rõ ràng đã được thêm vào tháng 3 năm 2016 và được phát hành trong Go 1.7, tức là khoảng 3 năm sau khi câu hỏi này ban đầu được hỏi: github.com/golang/go/commit/ tựa github.com/golang/go/commit/ Tiết
aoeu

20

Tôi đã thất vọng vì thiếu một cách nhanh chóng, chất lượng cao để sắp xếp JSON thành một chuỗi được tô màu trong Go nên tôi đã viết Marshaller của riêng mình có tên là ColorJSON .

Với nó, bạn có thể dễ dàng tạo đầu ra như thế này bằng cách sử dụng rất ít mã:

Đầu ra mẫu 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))
}

Tôi đang viết tài liệu cho nó bây giờ nhưng tôi rất hào hứng chia sẻ giải pháp của mình.


17

Chỉnh sửa Nhìn lại, đây không phải là thành ngữ Go. Các hàm trợ giúp nhỏ như thế này thêm một bước phức tạp. Nói chung, triết lý Go thích bao gồm 3 dòng đơn giản hơn 1 dòng khó.


Như @robyoder đã đề cập, json.Indentlà con đường để đi. Tôi nghĩ tôi sẽ thêm prettyprintchức năng nhỏ này :

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 hoặc http://play.golang.org/p/R4LWpkkHIN


7

Đây là những gì tôi sử dụng. Nếu nó không in được JSON, nó chỉ trả về chuỗi gốc. Hữu ích cho việc in các phản hồi HTTP nên chứa JSON.

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

6

Đây là giải pháp của tôi :

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
}

2

Một đơn giản tắt kệ máy in đẹp trong Go. Người ta có thể biên dịch nó thành một nhị phân thông qua:

go build -o jsonformat jsonformat.go

Nó đọc từ đầu vào tiêu chuẩn, ghi vào đầu ra tiêu chuẩn và cho phép đặt thụt lề:

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

Nó cho phép chạy một lệnh bash như:

cat myfile | jsonformat | grep "key"

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

Trông nó thế nào


1

Tôi sắp xếp mới, nhưng đây là những gì tôi đã thu thập được cho đến nay:

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
}

Đây là việc thực hiện chức năng, và chỉ là tiêu chuẩn

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

Mã số:

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)

}

0
//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, Users{1, "Saturn Rings"})
 //Use json package the blank spaces are for the indent
 data, _ := json.MarshalIndent(user, "", "  ")
 //Print json formatted
 fmt.Println(string(data))
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.