JSON - JavaScript Object Notation : Présentation
13 janvier 2007 —JSON est l'abréviation de "JavaScript Object Notation".
En quelques mots, JSON est une manière d'écrire des objets basée sur la syntaxe Javascript.
Le format JSON est défini par la RFC 4627, postée en Juillet 2006 par Douglas Crockford :
(extrait)
JavaScript Object Notation (JSON) is a text format for the serialization of structured data. It is derived from the object literals of JavaScript, as defined in the ECMAScript Programming Language Standard, Third Edition [ECMA].
(La traduction suivante est de moi)
La Notation Objet JavaScript est un format texte pour la sérialisation de données structurées. Il est dérivé des objets litéraux de JavaScript, tels qu'ils sont définis dans le Standard du Langage de Programmation ECMAScript, 3ème édition
Cela signifie que JSON est un format que l'on peut utiliser pour représenter des objets sous forme d'une chaîne de caractères, en utilisation une notation compatible avec JavaScript...
... le principal avantage étant que cette notation JavaScript permettra une manipulation aisée de ces objets sérialisés[1].
Données utilisant la Notation JavaScript Objet
Pour commencer, quelques mots sur la notation litéral objet de JavaScript, dont JSON est un sous-ensemble.
Déclarer un Objet
En JavaScript, un objet (simple, dans cet exemple) se déclare comme ceci :
var personne = {
nom: 'Lerdorf',
prenom: 'Rasmus'
};
Et l'accès à ses propriétés se fait à l'aide de la syntaxe objet.propriete
.
Par exemple, pour afficher le prénom et le nom de notre personne[2], nous pourrions écrire :
alert(personne.prenom + ' ' + personne.nom);
Ce qui afficherait effectivement :
Rasmus Lerdorf
Déclarer un tableau
En suivant la syntaxe de JavaScript, nous pouvons créer un tableau d'objets[3] :
var personnes = [
{
nom: 'Lerdorf',
prenom: 'Rasmus'
},
{
nom: 'Gutmans',
prenom: 'Andi'
},
{
nom: 'Suraski',
prenom: 'Zeev'
}
];
Et l'accès à ses composantes se fait comme pour tout tableau/objet JavaScript.
Par exemple :
alert(personnes[1].prenom + ' ' + personnes[1].nom);
Affichera :
Andi Gutmans
JSON et données sérialisées
Savoir comment déclarer un objet en JavaScript, c'est bien... Mais ce n'est pas le but de cet article.
En effet, un objet JavaScript est propre au JavaScript : il ne peut pas être généré, ni n'est compréhensible, par d'autres langages.
Par contre, un chaîne de caractères, elle, est une notion commune à la plupart des langages de programmation.
Que donnerait un de nos objets une fois écrit sous forme d'une chaîne de caractères ?
Objet sérializé
En JavaScript, voici ce qu'on obtiendrait :
var strPersonne = "{nom: 'Lerdorf', prenom: 'Rasmus'}";
Nous avons juste entouré notre déclaration d'objet par des guillemets, et supprimé les espace d'indentation.
Et nous avons maintenant une chaîne de caractères JS valide :
alert(strPersonne);
Affichera :
{nom: 'Lerdorf', prenom: 'Rasmus'}
Ce qui n'est pas utilisable tel quel...
eval
Mais JavaScript propose une fonction nommée eval
, qui permet d'exécuter du code stocké dans une chaîne de caractères.
Et JSON est un sous-ensemble de la notation litérale objet de JavaScript... ce qui signifie qu'il s'agit de code JS valide - et donc, eval
uable.
Il faut juste rajouter des parenthèses autour de la déclaration d'objet, comme ceci :
var personne = eval('(' + strPersonne + ')');
Et personne
sera exactement le même objet que le tout premier que nous avons présenté.
Ainsi,
alert(personne.prenom + ' ' + personne.nom);
affichera bien
Rasmus Lerdorf
Types de données JSON
JSON permet d'utiliser plusieurs types de données :
- Numérique : nombres entiers ou à virgule :
18
,3.1415
- Chaîne de caractères : suite de caractères Unicode, encadrés par des guillemets doubles. Le caractère d'échappement est l'antislash[4] :
"Hello World"
,"Retour\nà la ligne\tet tabulation"
- Booléen :
true
oufalse
- Tableau (Array) : Une liste ordonnées de valeurs, séparées par des virgules, et entourée de crochets :
[3.1415, 10, "coucou", true]
- Objet : Collection de couples clef/valeur, séparés par des virgules, et entourée d'accolades :
{"pi": 3.1415, "mot": "coucou", "actif": true}
. Les clefs sont des chaînes de caractères, donc, entre guillemets doubles[5]. null
Chaque valeur d'un tableau ou d'un objet peut être d'un de ces types.
Encore une fois, attention : les noms de propriétés d'objets sont des chaînes de caractères, donc, doivent être entourés de guillemets doubles ! Même si ce n'est pas nécessaire en JavaScript, ça l'est pour être conforme au format JSON !
Pour quelques illustrations, vous pouvez consulter la documentation en français de json.org.
JSON : Uniquement des données
Notation Litérale Objet JavaScript et méthodes
En utilisant la notation litérale d'objets de JavaScript, nous pouvons créer un objet représentant une personne habitant à Lyon et se nommant John Smith :
var personne = {
nom: 'Smith',
prenom: 'John',
ville: 'Avignon',
saluer: function (nom) {
alert(this.prenom + ' '
+ this.nom
+ ' salue ' + nom);
},
demenager: function (nouvelleVille) {
this.ville = nouvelleVille;
alert(this.prenom + ' '
+ this.nom
+ ' habite maintenant '
+ this.ville);
}
};
Cette personne peut en saluer d'autre, et déménager.
Par exemple, pour saluer Bob, puis déménager à Lyon :
personne.saluer('Bob');
personne.demenager('Lyon');
Ce qui affichera successivement :
John Smith salue Bob
et :
John Smith habite maintenant Lyon
Et, bien entendu, la propriété ville
de notre personne vaudra 'Lyon
'.
JSON : un format d'échange de données
Cependant, JSON n'est qu'un sous-ensemble de la notation litérale d'objets de JavaScript, créé pour servir de format d'échange de données.
En conséquence, une chaîne de caractères au format JSON ne doit pas contenir de déclaration de méthode, mais uniquement des données.
La chaîne suivante (découpée uniquement pour des raisons de présentation, pour limiter le défilement horizontal) :
var strPersonne = '{"nom": "Smith", "prenom": "John", "ville": "Avignon", '
+ '"saluer": function (nom) {alert(this.prenom + \' \' + this.nom + '
+ '\' salue \' + nom);}, "demenager": function (nouvelleVille) '
+ '{this.ville = nouvelleVille; alert(this.prenom + \' \' + '
+ 'this.nom + \' habite maintenant \' + this.ville);}}';
(oui, les guillemets doubles tout le long ne simplifient pas la lecture... Mais ils sont requis par la spécification JSON)
... passe parfaitement si on l'appelle avec eval
:
var personne = eval('(' + strPersonne + ')');
personne.saluer('Bob');
personne.demenager('Lyon');
... et elle causera les deux mêmes affichages que précédemment.
Mais ce n'est pas une chaîne de caractères JSON valide, puisqu'elle contient des définitions de méthodes - ceci, pour raisons de sécurité : si vous vous assurez qu'une chaîne est du JSON valide avant de l'eval
uer, vous saurez que l'objet obtenu ne contient que des données, et pas de méthode.
Autrement dit, en validant une chaîne de caractères JSON avant de l'évaluer, vous protégez votre application contre d'éventuelles injections de méthodes.
Validation de données JSON
Pour valider qu'une chaîne est du JSON valide avant de l'évaluer, utilisez le code suivant (donné en exemple au sein de la RFC 4627 évoquée plus haut) :
var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
text.replace(/"(\\.|[^"\\])*"/g, ''))) &&
eval('(' + text + ')');
Le code suivant :
var strPersonne = '{"nom": "Smith", "prenom": "John", "ville": "Avignon"}';
var personne = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
strPersonne.replace(/"(\\.|[^"\\])*"/g, '')))
&& eval('(' + strPersonne + ')');
if (personne !== false)
{
alert(personne.prenom + ' ' + personne.nom);
}
else
{
alert('JSON invalide');
}
affichera
John Smith
En effet, la chaîne de caractères utilisée est du JSON valide :
- uniquement des propriétés
- les chaînes de caractères, y compris les noms de propriétés, sont entre guillemets doubles
Par contre, la portion de code suivante :
var strPersonne = '{"nom": "Smith", "prenom": "John", "ville": "Avignon", '
+ '"saluer": function (nom) {alert(this.prenom + \' \' + this.nom + '
+ '\' salue \' + nom);}, "demenager": function (nouvelleVille) '
+ '{this.ville = nouvelleVille; alert(this.prenom + \' \' + '
+ 'this.nom + \' habite maintenant \' + this.ville);}}';
var personne = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
strPersonne.replace(/"(\\.|[^"\\])*"/g, '')))
&& eval('(' + text + ')');
if (personne !== false)
{
personne.saluer('Bob');
}
else
{
alert('JSON invalide');
}
affichera
JSON invalide
Puisque la chaîne de caractère que nous avons essayé de valider contient des définitions de méthodes, ce qui n'est pas permis par la spécification JSON.
Pour résumer, les données JSON sont stockées sous forme d'un texte, et de manière simple à encoder/décoder.
Cela explique pourquoi JSON peut être employé pour transmettre des données entre différents programmes, tels un programme serveur, et du JavaScript au sein d'un navigateur Web.
En particulier, il n'est pas rare d'utiliser JSON plutôt que XML pour la transmission de données lors de requêtes Ajax... Nous en reparlerons !
Notes
[1] La sérialisation étant le processus visant à encoder l'état d'un objet qui est en mémoire sous la forme d'une chaîne d'octets dans un flux de données - Wikipedia : Sérialisation
[2] Rasmus Lerdorf est le créateur du langage PHP
[3] Andi Gutmans et Zeev Suraski sont les créateurs de PHP3, en 1997 ; ils ont écrit la nouvelle version du Parser du futur PHP, le nommant Zend Engine ; ils sont les créateurs de Zend Technologies
[4] Notez que, selon le langage de programmation à partir duquel vous générez la chaîne JSON, il faudra que l'antislash soit lui-même échappé !
[5] J'insiste, mais je sais à quel point ils sont faciles à oublier, puisqu'ils ne sont pas obligatoires en JavaScript...