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.
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.
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()))
}
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)
}
É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
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:
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.
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()
}
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
}
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"
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)
}