Skip to content

Latest commit

 

History

History
238 lines (168 loc) · 8.97 KB

File metadata and controls

238 lines (168 loc) · 8.97 KB

7.2 JSON

JSON (JavaScript Object Notation) es un lenguaje de intercambio de datos ligero que se basado en texto descriptivo, entre sus ventajas se incluyen ser auto-descriptivo, fácil de comprender, etc. A pesar de ser un subconjunto de JavaScript, JSON utiliza un formato de texto diferente para convertirse en lengua independiente, y tiene algunas similitudes con lenguajes de la familia C.

La mayor diferencia entre JSON y XML es que XML es un lenguaje de marca, pero JSON no lo es. JSON es más pequeño y más rápido que XML, por lo tanto, es mucho más fácil y más rápido para analizar en los navegadores, lo cual es una razón importante de que muchas plataformas abiertas elijan utilizar JSON como su lenguaje de interfaz para el intercambio de datos.

Dado que JSON es cada vez más importante en el desarrollo web, vamos a echar un vistazo al nivel de soporte para JSON en Go. Actualmente, la librería estándar tiene un muy buen soporte para la codificación y decodificación de JSON.

Aquí utilizamos JSON para representar el ejemplo de la sección anterior:

{"servers":[{"serverName":"Shanghai_VPN","serverIP":"127.0.0.1"},{"serverName":"Beijing_VPN","serverIP":"127.0.0.2"}]}

El resto de esta sección utilizará estos datos JSON para presentarles cómo manejar JSON en Go.

Parse JSON

Parse a un struct

Supongamos que tenemos el JSON del ejemplo anterior, ¿cómo podemos analizar estos datos y asignarlos a un struct en Go? Go tiene las siguientes funciones para hacer esto:

	func Unmarshal(data []byte, v interface{}) error

Podemos utilizar esta función para lograr nuestro objetivo, este es un ejemplo completo:

	package main
	
	import (
	    "encoding/json"
	    "fmt"
	)
	
	type Server struct {
	    ServerName string
	    ServerIP   string
	}
	
	type Serverslice struct {
	    Servers []Server
	}

	func main() {
	    var s Serverslice
	    str := `{"servers":[{"serverName":"Shanghai_VPN","serverIP":"127.0.0.1"},{"serverName":"Beijing_VPN","serverIP":"127.0.0.2"}]}`
	    json.Unmarshal([]byte(str), &s)
	    fmt.Println(s)
	}

En el ejemplo anterior, hemos definido el struct correspondiente en GO para nuestra JSON, el slice para el array, el nombre del campo para la clave en JSON, pero ¿cómo sabe GO qué datos del JSON son para el campo espesífico del struct? Supongamos que tenemos una clave llamada Foo en el JSON, cómo encontramos el campo correspondiente?

  • Primero, intentamos encontrar el campo exportado (con mayúscula) cuyo nombre contenga Foo.
  • A continuación, tratamos de encontrar el campo que se llamaFoo.
  • Por último, tratamos de encontrar algo como FOO o FoO sin mirar las mayúsculas o minúsculas.

Usted puede notar que todos los campos que van a ser asignados deben ser exportados, y Go sólo asigna los campos que se pueden encontrar, al mismo tiempo, y hace caso omiso de todos los demás. Esto es bueno porque cuando recibe un dato de un JSON muy grande, pero sólo necesita algunos de ellos, los puede descartar fácilmente.

Parse a un interface

Cuando sabemos qué tipo de JSON vamos a tener, se analizan la estructura JSON específica, pero que si no sabemos?

Sabemos que la interfaz {} puede ser todo en Go, así que es el mejor envase para salvar nuestro formato desconocido JSON. Paquete JSON utiliza map[string]interface{} and []interface{} para guardar todo tipo de objetos JSON y matriz. Aquí está una lista de relación de correspondencia:

  • bool representa JSON booleans,
  • float64 representa JSON numbers,
  • string representa JSON strings,
  • nil representa JSON null.

Supongamos que tenemos los siguientes datos JSON:

b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)

Ahora que se analizan este JSON la interface{}:

var f interface{}
err := json.Unmarshal(b, &f)

la f almacena un mapa, donde las claves son cadenas y valores interface{}.

f = map[string]interface{}{
    "Name": "Wednesday",
    "Age":  6,
    "Parents": []interface{}{
        "Gomez",
        "Morticia",
    },
}

Así, la forma de acceder a estos datos? Type assertion.

m := f.(map[string]interface{})

Después de afirmado, puede utilizar siguiente código para acceder a los datos:

for k, v := range m {
    switch vv := v.(type) {
    case string:
        fmt.Println(k, "is string", vv)
    case int:
        fmt.Println(k, "is int", vv)
    case float64:
        fmt.Println(k,"is float64",vv)
    case []interface{}:
        fmt.Println(k, "is an array:")
        for i, u := range vv {
            fmt.Println(i, u)
        }
    default:
        fmt.Println(k, "is of a type I don't know how to handle")
    }
}

Como puedes ver, podemos analizar formato desconocido JSON a través de interfaz {} y escriba afirman ahora.

El ejemplo anterior es la solución oficial, pero el tipo de aserción no siempre es conveniente, por lo que recomiendo un proyecto de código abierto llamado simplejson y lanzado por bitly. He aquí un ejemplo de cómo utilizar este proyecto para hacer frente a JSON formato desconocido:

js, err := NewJson([]byte(`{
    "test": {
        "array": [1, "2", 3],
        "int": 10,
        "float": 5.150,
        "bignum": 9223372036854775807,
        "string": "simplejson",
        "bool": true
    }
}`))

arr, _ := js.Get("test").Get("array").Array()
i, _ := js.Get("test").Get("int").Int()
ms := js.Get("test").Get("string").MustString()

No es difícil ver lo cómodo que es, ver más información: https://github.com/bitly/go-simplejson.

Producir JSON

En muchas situaciones, tenemos que producir datos JSON y la respuesta a los clientes. En Go, paquete JSON tiene una función llamada Marshal para hacer este trabajo:

func Marshal(v interface{}) ([]byte, error)

Supongamos que necesitamos producir la lista de información del servidor, hemos siguiente ejemplo:

package main

import (
    "encoding/json"
    "fmt"
)

type Server struct {
    ServerName string
    ServerIP   string
}

type Serverslice struct {
    Servers []Server
}

func main() {
    var s Serverslice
    s.Servers = append(s.Servers, Server{ServerName: "Shanghai_VPN", ServerIP: "127.0.0.1"})
    s.Servers = append(s.Servers, Server{ServerName: "Beijing_VPN", ServerIP: "127.0.0.2"})
    b, err := json.Marshal(s)
    if err != nil {
        fmt.Println("json err:", err)
    }
    fmt.Println(string(b))
}

Output:

{"Servers":[{"ServerName":"Shanghai_VPN","ServerIP":"127.0.0.1"},{"ServerName":"Beijing_VPN","ServerIP":"127.0.0.2"}]}

Como ustedes saben, todos los nombres de los campos se capitalizan, pero si usted desea que su nombre clave JSON inicia con minúsculas, se debe utilizar struct tag para hacer esto, de lo contrario go no producirá datos para campos internos.

type Server struct {
    ServerName string `json:"serverName"`
    ServerIP   string `json:"serverIP"`
}

type Serverslice struct {
    Servers []Server `json:"servers"`
}

Tras esta modificación, podemos obtener los mismos datos JSON como principio.

He aquí algunos puntos que hay que tener en cuenta cuando se intenta producir JSON:

  • Si campo contiene "-"no se emite.
  • Si la etiqueta contiene el nombre personalizado, Go utiliza esto en vez de nombre de campo, como serverName en el ejemplo anterior.
  • Si la etiqueta contiene omitempty, este campo no se emite si se trata de su valor cero.
  • Si el tipo de campo es bool, string, int, int64, etc, y su etiqueta contiene ",string", Go convierte este campo para el tipo correspondiente en JSON.

Example:

type Server struct {
    // ID will not be outputed.
    ID int `json:"-"`

    // ServerName2 will be converted to JSON type.
    ServerName  string `json:"serverName"`
    ServerName2 string `json:"serverName2,string"`

    // If ServerIP is empty, it will not be outputed.
    ServerIP   string `json:"serverIP,omitempty"`
}

s := Server {
    ID:         3,
    ServerName:  `Go "1.0" `,
    ServerName2: `Go "1.0" `,
    ServerIP:   ``,
}
b, _ := json.Marshal(s)
os.Stdout.Write(b)

Output:

{"serverName":"Go \"1.0\" ","serverName2":"\"Go \\\"1.0\\\" \""}

Funcion Marshal sólo devuelve los datos cuando se tiene éxito, así que aquí están algunos puntos que debemos tener en cuenta:

  • Objeto JSON sólo admite cadena como clave, por lo que si desea codificar un mapa, su tipo tiene que ser map[string]T, donde T is el tipo en Go.
  • Modelo Como el canal, complejo y función no son capaces de ser codificado en JSON.
  • No trate de codificar datos anidados, llevó bucle muertos cuando los datos JSON productos.
  • Si el campo es un puntero, Ir salidas de datos al que apunta, o salidas nulas si apunta a cero.

En esta sección, le presentamos cómo descodificar y codificar datos JSON en Go, también uno de los proyectos de terceros llamado simplejson que es para analizar JSON formato desconocido. Estos son todos importantes en el desarrollo web.

Enlaces