Saltar al contenido principal

Módulo JSON

El módulo JSON convierte texto JSON en valores de JARU (mapas, listas, números, cadenas y booleanos) y al revés. Sirve para leer lo que contesta una API con Http, guardar la configuración de un programa en un fichero con File o mandar datos por MQTT.

use JSON

Captura del módulo JSON de JARU para leer, crear y serializar datos estructurados

Funciona igual en Windows y en todas las placas.

Funciones​

FunciónQué haceDevuelve
JSON.parse(texto)Lee un texto JSONEl valor: un mapa, una lista, un número, una cadena o un booleano
JSON.stringify(valor)Escribe un valor como texto JSON, en una líneaUna cadena
JSON.stringify(valor, sangria)Lo mismo, con una línea por elemento y sangria espacios por nivelUna cadena

parse(texto)​

Lee el texto JSON texto y devuelve lo que representa. Un objeto JSON se convierte en un mapa, y sus valores, en los de esta tabla:

En el JSONEn JARU
Objeto { … }Un mapa, con las claves como cadenas
Array [ … ]Una lista
Número sin decimalesUn entero
Número con decimales o con exponente (8.5, 3.0, 1e3)Un decimal
CadenaUna cadena. Los escapes (\n, \", \u00e9…) ya vienen convertidos.
true y falsetrue y false
nullnil

Los valores de un mapa se leen con corchetes, m["clave"], y los de una lista, con su posición, l[0] (ver Listas, mapas y arrays):

use JSON

var texto = '{"nombre": "Ana", "edad": 25, "notas": [7, 8.5], "dir": {"calle": "Mayor", "num": 3}}'
var persona = JSON.parse(texto)
println(persona["nombre"]) // Ana
println(persona["notas"][1]) // 8.5
println(persona["dir"]["calle"]) // Mayor

var lista = JSON.parse("[1, 2, 3]")
println(lista.size()) // 3

El texto también puede ser un valor suelto: JSON.parse("42") devuelve el entero 42, y JSON.parse('"hola"'), la cadena hola.

Es un JSON estricto, con una excepción: admite una coma de más al final de una lista o de un objeto ([1, 2,] da [1, 2]). No admite comillas simples, claves sin comillas ni comentarios. Si una clave se repite, se queda el último valor.

Si el texto no se puede leer, lanza una excepción, que se captura con try (ver Errores y excepciones):

ErrorMensajeCuándo
ERR_INVALID_VALUEString is not valid JSON.El texto no es JSON válido.
ERR_INVALID_VALUEArgument of parse() is an empty string.El texto está vacío.
ERR_INVALID_VALUEJSON object could not be processed.El texto es solo null.
ERR_TYPE_MISMATCHArgument of parse() must be a string.No le pasas una cadena.
ERR_INVALID_ARG_NUMBERparse() expects 1 argument, got 2.No le pasas un argumento.
use JSON

try
var datos = JSON.parse("{nombre: 1}")
catch (var e)
println(e) // ERR_INVALID_VALUE: String is not valid JSON.
end

stringify(valor, sangria)​

Escribe valor como texto JSON y lo devuelve en una cadena. sangria es opcional:

  • Sin sangria, todo va en una línea, con un espacio detrás de cada : y cada ,.
  • Con sangria, un entero, cada elemento va en su línea, con sangria espacios más por cada nivel. Con 0, una línea por elemento y sin sangría.
use JSON

var lectura = {"sensor": "t1", "valor": 21.5, "ok": true, "fallos": nil}
println(JSON.stringify(lectura))
println(JSON.stringify([1, 2.0, "dos"])) // [1, 2, "dos"]
{"valor": 21.5, "fallos": null, "sensor": "t1", "ok": true}
[1, 2, "dos"]

Con sangría, JSON.stringify({"lista": [1, 2]}, 2) da:

{
"lista": [
1,
2
]
}

Cada valor de JARU se escribe así:

En JARUEn el JSON
MapaUn objeto. Sus claves se escriben como cadenas: un entero, como 1, sale "1" (y JSON.parse lo lee como esa cadena); true y false, "true" y "false"; y nil, "null". Con otra clave, como un decimal, lanza ERR_INVALID_VALUE.
ListaUn array
EnteroUn número
DecimalUn número con 6 cifras significativas: 1 / 3 sale 0.333333, y 3000000000.0, 3e+09. Un decimal sin parte decimal se escribe como entero: 2.0 sale 2.
CadenaUna cadena, con ", \ y los saltos de línea y tabuladores escritos como escapes
true y falsetrue y false
nilnull

El orden de las claves de un objeto no es el del mapa: en el ejemplo de arriba, valor sale antes que sensor.

Errores (excepciones):

ErrorMensajeCuándo
ERR_INVALID_VALUEObject is not serializable to JSON.El valor, o uno de los que lleva dentro una lista o un mapa, no es de los de la tabla: una instancia de una clase, un array {…}, un bloque de Bytes, una función… O un mapa tiene una clave que no es una cadena, un entero, un booleano ni nil.
ERR_TYPE_MISMATCHArgument 2 of stringify() (indent) must be an integer.sangria no es un entero.
ERR_INVALID_ARG_NUMBERstringify() expects 1 or 2 arguments, got 0.No le pasas uno o dos argumentos.

Ejemplo completo​

Guarda la configuración de un programa en un fichero y la vuelve a leer:

use JSON, File

// La configuración de serie
var config = {"nombre": "Sensor 1", "intervalo": 30, "umbrales": [18, 26], "activo": true}

// Guardarla en un fichero, con sangría para que se lea bien
var f = File.open("config.json", "w")
f.write(JSON.stringify(config, 2))
f.close()

// Leerla otra vez
var g = File.open("config.json", "r")
var leida = JSON.parse(g.read())
g.close()

println(leida["nombre"]) // Sensor 1
println(leida["umbrales"][1]) // 26
leida["intervalo"] = 60
println(JSON.stringify(leida))

La última línea imprime:

{"nombre": "Sensor 1", "umbrales": [18, 26], "intervalo": 60, "activo": true}

Trampas y problemas conocidos​

  • Los valores, con corchetes. Un objeto JSON es un mapa: su valor se lee con m["nombre"], no con m.nombre.
  • Decimales que no son iguales. Al leer un decimal, puede salir distinto en la última cifra del mismo número escrito en el programa: JSON.parse("1.68") == 1.68 es false. Para comparar decimales, mira si la diferencia es muy pequeña.
  • Decimales con 6 cifras. stringify redondea los decimales a 6 cifras significativas. Si necesitas más, escribe el número como cadena.
  • Enteros grandes. Los enteros de JARU son de 32 bits: un número sin decimales de más de 2147483647 se da la vuelta al leerlo ([3000000000] da [-1294967296]). Escríbelo con decimales (3000000000.0) para que llegue como decimal.
  • null solo no se lee. JSON.parse("null") da error. Dentro de un objeto o una lista sí: llega como nil.

Todos los problemas conocidos de JARU, juntos, están en Problemas conocidos.