ฉันจะพิมพ์ JSON โดยใช้ Go ได้อย่างไร


191

ไม่มีใครรู้วิธีง่ายๆในการพิมพ์เอาต์พุต JSON แบบสวยใน Go?

หุ้นhttp://golang.org/pkg/encoding/json/แพคเกจไม่ได้ดูเหมือนจะรวมฟังก์ชันการทำงานสำหรับการนี้ (แก้ไข: มันไม่ดูคำตอบที่ได้รับการยอมรับ) และ Google Quick ไม่ได้เปิดอะไรที่เห็นได้ชัด

ใช้ฉันกำลังมองหามีทั้งพิมพ์สวยผลลัพธ์json.Marshalและเพียงแค่การจัดรูปแบบสตริงที่เต็มไปด้วย JSON จากที่ใดก็ได้ดังนั้นจึงง่ายต่อการอ่านเพื่อวัตถุประสงค์ในการแก้ปัญหา


คำเตือน: ในการทดลองของฉันในพจนานุกรม JSON ดัชนีสตริงจะต้องอยู่ในวงเล็บ ดังนั้น{name: "value"}จะไม่เป็นไรแม้จะว่าส่วนใหญ่การใช้งานจาวาสคริล่ามมัน เพียง แต่ {"name": "value"}จะทำงานร่วมกับ JSON ไปทำงานห้องสมุด
peterh - Reinstate Monica

2
@peterh ฉันคิดว่าคุณสับสนไวยากรณ์ตัวอักษร JavaScript กับ JSON ที่เหมาะสม ข้อมูลจำเพาะ JSON ( json.org ) บ่งชี้อย่างชัดเจนว่าอนุญาตให้ใช้ตัวอักษรสตริงเท่านั้น (หมายถึงต้องการเครื่องหมายคำพูด) ในขณะที่ไวยากรณ์วัตถุภาษา JS ไม่มีข้อ จำกัด ดังกล่าว ไลบรารี Go ปฏิบัติตามข้อกำหนด
แบรดพีบอดี

คำตอบ:


296

โดยการพิมพ์สวยฉันถือว่าคุณหมายถึงเยื้องเช่นนั้น

{
    "data": 1234
}

ค่อนข้างมากกว่า

{"data":1234}

วิธีที่ง่ายที่สุดคือทำด้วยMarshalIndentซึ่งจะช่วยให้คุณระบุวิธีที่คุณต้องการให้เยื้องผ่านการindentโต้แย้ง ดังนั้นjson.MarshalIndent(data, "", " ")จะพิมพ์สวยโดยใช้ช่องว่างสี่สำหรับการเยื้อง


17
ใช่ว่ามีลักษณะเหมือนกัน - มีอยู่แล้วในตัวเหลือเพียงแค่รวมคำหลัก "พิมพ์สวย" ใน pkg doc ดังนั้นการค้นหาคนต่อไปจึงพบ (จะออกความคิดเห็นสำหรับผู้ดูแล doc) Tks!
แบรดพีบอดี

39
json.MarshalIndent(data, "", "\t")ถ้าคุณต้องการแท็บ
Kyle Brandt

81
json.MarshalIndent(data, "", "🐱")ถ้าคุณต้องการแมว ขอโทษ
briiC

45
json.MarshalIndent(data, "", "\t🐱")ถ้าคุณต้องการ ... แมวลายแมว ... ขอโทษ
ดาวอส

78

คำตอบที่ยอมรับนั้นยอดเยี่ยมถ้าคุณมีวัตถุที่คุณต้องการเปลี่ยนเป็น JSON คำถามนี้ยังกล่าวถึงการพิมพ์ที่สวยงามเพียงแค่สตริง JSON ใด ๆ และนั่นคือสิ่งที่ฉันพยายามที่จะทำ ฉันต้องการบันทึก JSON บางส่วนจากคำขอ POST (โดยเฉพาะรายงานการละเมิด CSP )

หากต้องการใช้MarshalIndentคุณจะต้องทำUnmarshalสิ่งนั้นเป็นวัตถุ ถ้าคุณต้องการสิ่งนั้นให้ทำมัน แต่ฉันทำไม่ได้ หากคุณต้องการพิมพ์อาร์เรย์ไบต์แบบธรรมดา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()))
}

48

เพื่อการใช้งานหน่วยความจำที่ดีขึ้นฉันคิดว่ามันดีกว่า:

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

ไม่SetIndentได้รับการเพิ่มเมื่อเร็ว ๆ นี้? ส่วนใหญ่มันไม่เป็นที่รู้จัก
chappjc

1
@chappjc SetIndent(ชื่อเดิมIndent) เห็นได้ชัดว่าถูกเพิ่มในเดือนมีนาคม 2016 และเผยแพร่ใน Go 1.7 ซึ่งเป็นเวลาประมาณ 3 ปีหลังจากที่คำถามนี้ถูกถามครั้งแรก: github.com/golang/go/commit/… github.com/golang/go/commit/ …
aoeu

19

ผมผิดหวังจากการขาดความรวดเร็วในแบบคุณภาพสูงเพื่อ marshal JSON เพื่อสตริง colorized ในไปดังนั้นฉันเขียนของตัวเองที่เรียกว่า Marshaller ColorJSON

ด้วยคุณสามารถสร้างผลลัพธ์เช่นนี้โดยใช้รหัสน้อยมาก:

ตัวอย่างเอาต์พุต 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))
}

ฉันกำลังเขียนเอกสารสำหรับตอนนี้ แต่ฉันรู้สึกตื่นเต้นที่จะแบ่งปันโซลูชันของฉัน


17

แก้ไขมองย้อนกลับไปนี่เป็นไปไม่ได้ ฟังก์ชั่นตัวช่วยขนาดเล็กเช่นนี้เพิ่มความซับซ้อนอีกขั้น โดยทั่วไปแล้วปรัชญาของ 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


7

นี่คือสิ่งที่ฉันใช้ หากล้มเหลวในการพิมพ์สวย JSON เพียงแค่ส่งกลับสตริงเดิม มีประโยชน์สำหรับการพิมพ์การตอบสนอง HTTP ที่ควรมี 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()
}


2

เครื่องพิมพ์ที่เรียบง่ายและสวยงามใน 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"

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

มันมีลักษณะอย่างไร


1

ฉันเป็นคนใหม่ที่จะไป แต่นี่คือสิ่งที่ฉันรวบรวมมา:

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)

}

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))
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.