¿Cómo puedo imprimir JSON con Go?


¿Alguien conoce una forma sencilla de imprimir la salida JSON en Go?

La población http://golang.org/pkg/encoding/json / el paquete no parece incluir funcionalidad para esto (EDITAR: lo hace, ver respuesta aceptada) y un rápido Google no muestra nada obvio.

Los usos que estoy buscando son bonitos: imprimir el resultado de json.Marshal y simplemente formatear una cadena llena de JSON desde cualquier lugar, por lo que es más fácil de leer para fines de depuración.

Author: Brad Peabody, 2013-09-27

8 answers

Por pretty-print, supongo que te refieres a sangría, así

{
    "data": 1234
}

En lugar de

{"data":1234}

La forma más fácil de hacer esto es con MarshalIndent, lo que le permitirá especificar cómo le gustaría que se sangrara a través del argumento indent. Por lo tanto, json.MarshalIndent(data, "", " ") se imprimirá bastante usando cuatro espacios para la sangría.

 181
Author: Alexander Bauer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-26 21:17:58

La respuesta aceptada es genial si tienes un objeto que quieres convertir en JSON. La pregunta también menciona bastante-impresión de cualquier cadena JSON, y eso es lo que estaba tratando de hacer. Solo quería bastante-registro de algunos JSON de una solicitud POST (específicamente un informe de violación CSP).

Para usar MarshalIndent, tendrías que Unmarshal eso en un objeto. Si usted necesita que, ir a por ello, pero yo no. Si sólo necesita pretty-imprimir una matriz de bytes, llano Indent es su amigo.

Esto es lo que terminé con:

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
Author: robyoder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-28 18:13:54

Para un mejor uso de la memoria, supongo que esto es mejor:

var out io.Writer
enc := json.NewEncoder(out)
enc.SetIndent("", "    ")
if err := enc.Encode(data); err != nil {
    panic(err)
}
 29
Author: mh-cbon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-26 18:08:46

Edit Mirando hacia atrás, esto es Ir no idiomático. Pequeñas funciones auxiliares como esta añaden un paso adicional de complejidad. En general, la filosofía Go prefiere incluir las 3 líneas simples sobre 1 línea complicada.


Como @robyoder mencionó, json.Indent es el camino a seguir. Pensé en añadir esta pequeña función 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 o http://play.golang.org/p/R4LWpkkHIN

 10
Author: jpillora,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-15 03:33:47

Me sentí frustrado por la falta de una forma rápida y de alta calidad para combinar JSON con una cadena coloreada en Go, así que escribí mi propio Marshaller llamado ColorJSON .

Con él, puede producir fácilmente una salida como esta usando muy poco código:

Salida de muestra ColorJSON

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

Estoy escribiendo la documentación para ello ahora, pero estaba emocionado de compartir mi solución.

 7
Author: Tyler Brock,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-08 05:59:05

Esto es lo que uso. Si no logra imprimir el JSON simplemente devuelve la cadena original. Útil para imprimir respuestas HTTP que debería contener 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()
}
 4
Author: Timmmm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-16 19:12:43

Aquí está mi solución:

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
}
 3
Author: Raed Shomali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-05 00:17:50

Una simple impresora lista para usar en Go. Uno puede compilarlo en un binario a través de:

go build -o jsonformat jsonformat.go

Lee desde la entrada estándar, escribe en la salida estándar y permite establecer sangría:

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

Permite ejecutar comandos bash como:

cat myfile | jsonformat | grep "key"
 1
Author: Paweł Szczur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-25 13:49:32