JavaScript Object Notation (JSON)


JSON1

JSON (JavaScript Object Notation) è un semplice formato per lo scambio di dati. Per le persone è facile da leggere e scrivere, mentre per le macchine risulta facile da generare e analizzarne la sintassi. Si basa su un sottoinsieme del Linguaggio di Programmazione JavaScript, Standard ECMA-262 Terza Edizione - Dicembre 1999.

JSON è un formato di testo completamente indipendente dal linguaggio di programmazione, ma utilizza convenzioni conosciute dai programmatori di linguaggi della famiglia del C, come C, C++, C#, Java, JavaScript, Perl, Python, e molti altri; questa caratteristica fa di JSON un linguaggio ideale per lo scambio di dati.

JSON si basa sull'impiego di due strutture:

  • Un insieme di coppie nome/valore. In diversi linguaggi, questo è realizzato come un oggetto, un record, uno struct, un dizionario, una tabella hash, un elenco di chiavi o un array associativo.
  • Un elenco ordinato di valori. Nella maggior parte dei linguaggi questo si realizza con un array, un vettore, un elenco o una sequenza.

Queste sono strutture di dati universali. Virtualmente tutti i linguaggi di programmazione moderni li supportano in entrambe le forme. E' sensato che un formato di dati che è interscambiabile con linguaggi di programmazione debba essere basato su queste strutture.

In JSON, assumono queste forme:

Un oggetto è una sequenza non ordinata di nomi/valori. Un oggetto inizia con { (parentesi graffa sinistra) e finisce con } (parentesi graffa destra). Ogni nome è seguito da : (due punti) e la coppia di nome/valore sono separata da , (virgola).


Un array è una raccolta ordinata di valori. Un array comincia con [ (parentesi quadra sinistra) e finisce con ] (parentesi quadra destra). I valori sono separati da , (virgola).


Un valore può essere una stringa tra virgolette, o un numero, o vero o falso o nullo, o un oggetto o un array. Queste strutture possono essere annidate.


Una stringa è una raccolta di zero o più caratteri Unicode, tra virgolette; per le sequenze di escape utilizza la barra rovesciata. Un singolo carattere è rappresentato come una stringa di caratteri di lunghezza uno. Una stringa è molto simile ad una stringa C o Java.


Un numero è molto simile ad un numero C o Java, a parte il fatto che i formati ottali e esadecimali non sono utilizzati.


I caratteri di spaziatura possono essere inseriti in mezzo a qualsiasi coppia di token.

A parte alcuni dettagli di codifica, questo descrive totalmente il linguaggio.

In base a quanto si apprende da Wikipedia JSON è nato dalla necessità di un protocollo di comunicazione server-to-browser in real-time che evitasse il ricorso a plugin sotto forma di applet Flash o Java,come accadeva alla fine degli anni '90.

L'ideazione di JSON si deve a Douglas Crockford della State Software (originariamente denominata Veil Networks, Inc.) che con i suoi soci si pose il problema di sviluppare un sistema che utilizzando le funzionalità standard dei browser, allora disponibili, fornisse un livello di astrazione capace di consentire agli sviluppatori di creare delle applicazioni Web capaci di supportare una connessione duplex persistente con un server Web tenendo aperte due connessioni HTTP, mantenendo il tempo di latenza entro i tempi consentiti dai browser in maniera tale da evitare il time-out previsto nel caso di mancato scambio dati.


Sebbene fosse originariamente destinato ad essere un sottoinsieme del linguaggio di JavaScript (Standard ECMA-262 3rd Edition—December 1999), data la facilità di implementazione JSON è stato preso integrato in molti altri linguaggi, sino a diventare uno standard internazionale nel 2013 (standard ECMA-404).

Nello stesso anno la RFC 7158 adottò ECMA-404 come riferimento. Mentre nel 2014 fu emanata la RFC 7159 che è attualmente il principale riferimento per gli usi internet di JSON (Applicazioni MIME/JSON).


I pregi della soluzione proposta appaiono immediatamente evidenti dal confronto di un qualsiasi testo in formato JSON con equivalenti rappresentazioni alternative in formati diversi, in particolare XML (vedi figura 1).

JSON

{
  firstName: John,
  lastName: Smith,
  isAlive: true,
  age: 18,
  address: {
    streetAddress: 21 2nd Street,
    city: New York,
    state: NY,
    postalCode: 10021-3100
  },
  phoneNumbers: [
    {
      type: home,
      number: 212 555-1234
    },
    {
      type: office,
      number: 646 555-4567
    },
    {
      type: mobile,
      number: 123 456-7890
    }
  ],
  children: [],
  spouse: null
}


XML

<?xml version=1.0 encoding=UTF-8 ?>
    <firstName>John</firstName>
    <lastName>Smith</lastName>
    <isAlive>true</isAlive>
    <age>18</age>
    <address>
        <streetAddress>21 2nd Street</streetAddress>
        <city>New York</city>
        <state>NY</state>
        <postalCode>10021-3100</postalCode>
    </address>
    <phoneNumbers>
        <type>home</type>
        <number>212 555-1234</number>
    </phoneNumbers>
    <phoneNumbers>
        <type>office</type>
        <number>646 555-4567</number>
    </phoneNumbers>
    <phoneNumbers>
        <type>mobile</type>
        <number>123 456-7890</number>
    </phoneNumbers>
    <spouse />


Figura 1) confronto fra le rappresentazioni in formato JSON e XML dei dati di una persona.

Intelligibilità di JSON e XML.

Mentre i testi JSON risultano immediatamente leggibili e comprensibili non si può dire altrettanto dei loro equivalenti in formato XML, come si verifica facilmente dando uno sguardo ai testi precedenti previa la rimozione dei colori. Vedi Figura 2.
Considerazioni analoghe valgono per la redazione dei documenti.
Scrivere un documento in formato JSON non è molto più gravoso che redigere un normale file di testo, basta prestare attenzione alle regole di punteggiatura; redigere un simile documento conformandosi ai vincoli imposti da XML è decisamente più impegnativo data la necessità di bilanciare i tag aperti e chiusi riscrivendo il nome dell'attributo per non parlare del maggiore lavoro di digitazione.

JSON

{
  "firstName": "John",
  "lastName": "Smith",
  "isAlive": true,
  "age": 18,
  "address": {
    "streetAddress": "21 2nd Street",
    "city": "New York",
    "state": "NY",
    "postalCode": "10021-3100"
  },
  "phoneNumbers": [
    {
      "type": "home",
      "number": "212 555-1234"
    },
    {
      "type": "office",
      "number": "646 555-4567"
    },
    {
      "type": "mobile",
      "number": "123 456-7890"
    }
  ],
  "children": [],
  "spouse": null
}


XML

<?xml version="1.0" encoding="UTF-8" ?>
    <firstName>John</firstName>
    <lastName>Smith</lastName>
    <isAlive>true</isAlive>
    <age>18</age>
    <address>
        <streetAddress>21 2nd Street</streetAddress>
        <city>New York</city>
        <state>NY</state>
        <postalCode>10021-3100</postalCode>
    </address>
    <phoneNumbers>
        <type>home</type>
        <number>212 555-1234</number>
    </phoneNumbers>
    <phoneNumbers>
        <type>office</type>
        <number>646 555-4567</number>
    </phoneNumbers>
    <phoneNumbers>
        <type>mobile</type>
        <number>123 456-7890</number>
    </phoneNumbers>
    <spouse />


Figura 2)  i testi di figura 1) senza l'ausilio dei colori.

2 – JSON e oggetti JavaScript.

Di primo acchito si potrebbe pensare una corrispondenza quasi perfetta fra il formalismo degli oggetti JavaScript e specifiche del formato JSON. Ad esempio la seguente assegnazione è conforme sia alle specifiche di JavaScript che a quelle di JSON:

“ “ “ “
var John_Smith = {
  "firstName": "John",
  "lastName": "Smith",
  "isAlive": true,
  "age": 18,
  "address": {
    "streetAddress": "21 2nd Street",
    "city": "New York",
    "state": "NY",
    "postalCode": "10021-3100"
  },
  "phoneNumbers": [
    {
      "type": "home",
      "number": "212 555-1234"
    },
    {
      "type": "office",
      "number": "646 555-4567"
    },
    {
      "type": "mobile",
      "number": "123 456-7890"
    }
  ],
  "children": [],
  "spouse": null
};

“ “ “ “


In realtà i due formalismi non sono esattamente coincidenti, la più importante differenza è costituita dal fatto che i testi in formato JSON sono codificati come delle stringhe di caratteri mentre gli oggetti JavaScript sono delle entità ben più complesse.


Figura 3) un oggetto JavaScript visto con il debugger di Chrome.

2.1 - Rappresentazione di strutture dati JSON come oggetti JavaScript

Prescindendo dalla rappresentazione interna degli oggetti JavaScript2, è sufficiente sapere che le applicazioni JavaScript, generalmente, non manipolano direttamente le stringhe corrispondenti ai documenti in formato JSON, ma le loro rappresentazioni sotto forma di oggetti equivalenti.
Dato il testo di un documento JSON il corrispondente oggetto può essere "costruito" in vari modi.
Se il testo non è molto lungo l'oggetto può essere costruito in sede di dichiarazione della corrispondente variabile mediante una semplice assegnazione, scrivendo ad esempio:

var John_Smith0 = {
  "firstName": "John",
  "lastName": "Smith",
  "age": 18
};


In alternativa si può cominciare dichiarando un oggetto vuoto (indicato da parentesi graffa aperta e chiusa {}), per poi decorarlo aggiungendo le proprietà richieste una ad una :

var John_Smith1 = {};
John_Smith.firstName = "John";
John_Smith.lastName = "Smith";
John_Smith.age = 18;


Il risultato che si ottiene nei due casi è del tutto identico, come si può verificare con il debugger utilizzando il programma di prova di figura 4).

2.2 – Accesso agli elementi degli oggetti JavaScript

Il linguaggio JavaScript consente di far riferimento alle entità contenute all'interno degli oggetti utilizzando due sintassi alternative; si può ricorrere alla notazione basata sull'uso del carattere punto (dotted notation) analogamente a quanto previsto dalla sintassi del linguaggio C oppure, in alternativa, si può specificare la chiave  costituita dal nome dell'argomento della coppia argomento valore.
Si osservi che quest'ultima dovrà essere specificata fra apici e parentesi quadre.
Ad esempio: volendo conoscere l'età di John Smith potremmo pertanto ricorrere alla notazione:

var age = John_Smith.age;

o alternativamente a:

var age = John_Smith['age'];

in entrambi i casi si otterrà lo stesso risultato consistente nell'assegnazione alla variabile age del valore 18.
Considerazioni analoghe valgono per quanto concerne la modifica dei valori degli attributi degli oggetti.
Volendo cambiare l'età memorizzata nell'oggetto considerato potremmo utilizzare la notazione:

John_Smith.age = 81;

oppure

John_Smith['age'] = 81;


<!DOCTYPE html>
<html>
  <head>
    <meta content="text/html; charset=windows-1252" http-equiv="content-type">
    title>Object Initialization</title>
    <meta content="Luigi D. CAPRA" name="author">
  </head>
  <body>
    This is an example of an HTML document containing JavaScript's Object initialization.

<script>

var John_Smith = {
  "firstName": "John",
  "lastName": "Smith",
  "age": 18
};

var John_Smith2 = {};
John_Smith2.firstName = "John";
John_Smith2.lastName = "Smith";
John_Smith2.age = 18;

/*-----U_Init --------------------------------------------------------
*
*/
function U_Init()
{
  var John0 = John_Smith;
  var John1 = John_Smith2;
  var age0 = John_Smith.age;
  var age1 = John_Smith['age'];
  John_Smith.age = 81;
  John_Smith2['age'] = 81;

  var iTmp = 0;
} /* U_Init */

U_Init(); 
</script>
  </body>
</html>

Figura 4) programma di prova (vedi obj_init.html).

in entrambi i casi otterremo il risultato di trasformare l'adolescente John Smith in un ottuagenario.

Ci si potrebbe interrogare circa l'utilità di due notazione alternative che producono risultati identici; in realtà non è così poiché ci sono delle sottili differenze fra ciò che è possibile fare nei due casi.
La dotted notation è più snella e leggibile poiché consente di accedere al valore di un argomento utilizzando un solo carattere di punteggiatura (il punto) anziché quattro (le coppie di apici e di parentesi quadre), ma ha il limite di restringere il novero delle chiavi utilizzabili alle sole stringhe accettabili come identificatori (tipicamente stringhe alfanumeriche che cominciano con una lettera o con il carattere sottolineato).
Il ricorso alla notazione basata sul punto è pertanto preferibile quando si deve accedere a strutture annidate che prevedono più livelli (oggetti contenenti oggetti, eccetera), vedi ad esempio:

var city1 = John_Smith.address.city;
var city2 = John_Smith['address']['city'];


Il ricorso agli apici consente però di impiegare come chiave stringhe di tipo arbitrario con molte meno restrizioni.
Ad esempio 'questa potrebbe essere una chiave valida' ed anche questa '  x,? ' come si vede in figura 5),
oppure più semplicemente noi italiani potremmo volere impiegare come chiave la parola 'città'.


Figura 5) il ricorso agli apici consente l'impiego di chiavi arbitrarie.

Indipendentemente dalla notazione prescelta la creazione degli oggetti JSON2 costa fatica; sarebbe pertanto auspicabile avere la possibilità di salvare le corrispondenti strutture dati o eventualmente trasmetterle ad altri sistemi di elaborazione.
In effetti JSON è stato inventato con il preciso scopo di risolvere il suddetto problema.
Tutto ciò presuppone la capacità di convertire le sequenze binarie corrispondenti agli oggetti JavaScript in una rappresentazione che si presti al salvataggio in un file o alla trasmissione lungo i canali di telecomunicazione.
JSON risolve il problema rappresentando i dati binari sotto forma di stringhe di caratteri.
La conversione dal formato binario alle stringhe e viceversa è reso possibile dai metodi: JSON.stringify e JSON.parse rispettivamente.

La funzione JSON.stringify accetta in input un oggetto JSON e lo converte nella corrispondente stringa, viceversa la funzione JSON.parse analizza la stringa di testo corrispondente ad un oggetto JSON e costruisce il corrispondente oggetto JavaScript.
Ai fini di questo corso possiamo immaginare questi due metodi come dei portali ovvero delle interfacce che aprono l'ambiente del browser verso il mondo esterno, permettendo l'interscambio di dati con il "mondo esterno".
Nel contesto considerato il "mondo esterno" potrebbe consistere di  un server, di un altro client oppure persino del sistema fisico.
Si pensi alla possibilità di salvare lo stato di un'elaborazione che avviene nel browser in un file esterno convertendo gli oggetti JavaScript in oggetti JSON ovvero in stringhe memorizzabili in un disco, sotto forma di file di testo.

Conversioni


I pacchetti JSON differiscono dagli oggetti JavaScript (JavaScript Object Data) per la codifica; i primi sono infatti codificati per mezzo di stringhe di caratteri mentre i secondi sono degli oggetti "veri" rappresentati in memoria in maniera tradizionale.
Affinché sia possibile inviare o memorizzare un oggetto JavaScript bisognerà prima convertirlo in un pacchetto JSON.

Il metodo JSON.stringify converte gli oggetti JavaScript in oggetti JSON codificati sotto forma di stringhe di caratteri:

var obj = { "name":"John", "age":30, "city":"New York"};

var myJSON = JSON.stringify(obj);


A loro volta i pacchetti in formato JSON possono essere convertiti in oggetti JavaScript ricorrendo al metodo JSON.parse che convertirà le corrispondenti stringhe di caratteri in oggetti JavaScript:

var obj = JSON.parse('{ "name":"John", "age":30, "city":"New York"}');

Sfortunatamente non è tutto così semplice e automatico.
Volendo inviare un pacchetto fisico da Aosta a Brindisi non basta metterlo fuori dalla porta ed aspettare che "magicamente" venga recapitato al destinatario; tipicamente occorrerà chiamare un corriere che si incarichi di prelevarlo e portarlo a destinazione.
Considerazioni analoghe valgono anche in campo informatico.
La semplice conversione di un oggetto JSON in una stringa non risolve il problema della trasmissione dei dati; generalmente si dovrà far ricorso ad altri strumenti per completare il processo come ad esempio la tecnologia AJAX.

1) Ripreso testualmente da: http://www.json.org/json-it.html