web-dev-qa-db-fra.com

Comment imprimer en JSON avec Go?

Est-ce que quelqu'un connaît un moyen simple d'imprimer joliment une sortie JSON dans Go?

Le paquetage http://golang.org/pkg/encoding/json/ ne semble pas inclure de fonctionnalité pour cela (EDIT: oui, voir réponse acceptée) et un rapide Google ne révèle rien d’évident.

Les utilisations que je recherche sont à la fois une jolie impression du résultat de json.Marshal et un simple formatage d'une chaîne remplie de JSON, d'où il est plus facile de lire à des fins de débogage.

148
Brad Peabody

Par jolies lettres, je suppose que vous voulez dire en retrait, comme si

{
    "data": 1234
}

plutôt que

{"data":1234}

Le moyen le plus simple de procéder consiste à utiliser MarshalIndent , ce qui vous permettra de spécifier comment vous souhaitez qu'il soit mis en retrait via l'argument indent. Ainsi, json.MarshalIndent(data, "", " ") sera joliment imprimé en utilisant quatre espaces pour l'indentation.

233
Alexander Bauer

La réponse acceptée est excellente si vous souhaitez transformer un objet en JSON. La question mentionne également le fait d’imprimer joliment n’importe quelle chaîne JSON et c’est ce que j’essayais de faire. Je voulais juste enregistrer joliment du JSON à partir d'une demande POST (en particulier un rapport de violation CSP ).

Pour utiliser MarshalIndent, vous devez Unmarshal dans un objet. Si vous en avez besoin, allez-y, mais pas moi. Si vous avez juste besoin d’imprimer joliment un tableau d’octets, tout simplement Indent est votre ami.

Voici ce que j'ai fini avec:

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

Pour une meilleure utilisation de la mémoire, je suppose que c'est mieux:

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

Éditer En regardant en arrière, ceci est non idiomatique Go. Les petites fonctions d'assistance comme celle-ci ajoutent une étape supplémentaire à la complexité. En règle générale, la philosophie Go préfère inclure les 3 lignes simples sur 1 ligne complexe.


Comme @robyoder l'a mentionné, json.Indent est la voie à suivre. Je pensais ajouter cette petite fonction 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 ou http://play.golang.org/p/R4LWpkkHH

13
jpillora

J'étais frustré par l'absence d'un moyen rapide et de qualité supérieure de combiner JSON avec une chaîne colorisée dans Go. J'ai donc écrit mon propre Marshaller appelé ColorJSON .

Avec lui, vous pouvez facilement produire une sortie comme celle-ci en utilisant très peu de code:

ColorJSON sample output

package main

import (
    "fmt"
    "github.com/TylerBrock/colorjson"
    "encoding/json"
)

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

J'écris la documentation pour cela maintenant mais j'étais enthousiaste à l'idée de partager ma solution.

11
Tyler Brock

Voici ce que j'utilise. S'il n'imprime pas assez le JSON, il retourne simplement la chaîne d'origine. Utile pour imprimer des réponses HTTP qui devraient contiennent du 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
Timmmm

Voici ma 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
}
5
Raed Shomali

Une jolie imprimante prête à l'emploi dans Go. On peut le compiler en binaire via:

go build -o jsonformat jsonformat.go

Il lit à partir de l'entrée standard, écrit sur la sortie standard et permet de définir l'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)
    }
}

Il permet d’exécuter des commandes bash telles que:

cat myfile | jsonformat | grep "key"
2
Paweł Szczur

je suis un peu nouveau pour y aller, mais voici ce que j'ai recueilli jusqu'à présent:

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
}

Ceci est l'exécution de la fonction, et juste 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)

}
1
accnameowl