JavaScript Object Notation: The Definite Guide
In de wereld van web services is XML de status quo. Sommigen vinden XML niet gepast voor kleine web applicaties, gezien de omvang van XML data weleens groot kan zijn. Er worden teveel bytes verstuurd voor de data waar het omdraait. Douglas Crockford heeft daarom een nieuw data exchange formaat bedacht. In dit artikel zullen we het uitgebreid hebben over JavaScript Object Notation (JSON).
Javascript arrays en object literals
JSON is in feite niets meer dan een speciale notatie voor de definitie van objecten en arrays. Met deze notatie kun je in een enkele regel bijvoorbeeld een object met verschillende eigenschappen definieren. Een voorbeeldje:
-
var colors = ["Red", "Blue", "Green"];
-
alert(colors[1]); // Blue
De arrays die je op deze wijze definieert hebben de gewone eigenschappen zoals je die al gewend bent van Javascript arrays. Zo kun je gewoon verschillende data types gebruiken:
-
var types = [null, true, 1337, "str"];
Zoals gezegd kun je ook objecten definieren. Dit doe je met een sleutel-waarde combinatie:
-
var product = {
-
"naam" : "The Da Vinci Code",
-
"prijs" : 10,
-
"betaald" : false,
-
};
-
-
alert(product.naam); // The Da Vinci Code
-
alert(product["naam"]); // The Da Vinci Code
-
alert(product.prijs); // 10
-
alert(product.["prijs"]); // 10
Je kunt op twee manieren een waarde ophalen uit een Javascript object. Een manier is met de punt notatie, de ander is met rechte haken.
Eerder zeiden we al dat je allerlei data types in een Javascript array kon plaatsen. Ditzelfde geldt natuurlijk ook voor Objecten. Wil je een array van objecten? No problem!
-
var product =
-
[
-
{
-
"naam" : "The Da Vinci Code",
-
"prijs" : 10,
-
"betaald" : false,
-
},
-
{
-
"naam" : "Angels and Demons",
-
"prijs" : 11,
-
"betaald" : true,
-
}
-
];
-
alert(product[0].naam); // The Da Vinci Code
-
alert(product[1].betaald); // true
Andersom kan natuurlijk ook, een array in een object:
-
var product =
-
{
-
"naam" : ["The Da Vinci Code", "Angels and Demons"],
-
"prijs" : [10, 11],
-
"betaald" : [false, true]
-
};
-
-
alert(product.naam[1]); // Angels and Demons
-
alert(product.prijs[0]); // 10
The Fat-Free Alternative to XML
Wat hebben javascript arrays en object literals te maken met JSON? Zoals we al eerder zagen bestaat JSON voornamelijk uit een speciale notatie voor de definitie van arrays en objecten. Het enige wat je eigenlijk mist zijn variabelen. Het laatste voorbeeld ziet er zo uit in JSON formaat.
-
{
-
"naam" : ["The Da Vinci Code", "Angels and Demons"],
-
"prijs" : [10, 11],
-
"betaald" : [false, true]
-
}
Wie ziet het verschil? Je mist alleen de variabele naam en de puntkomma.
Hoe verwerk je deze data in Javascript? Stel dat je deze data via enig vorm van input krijgt (denk aan XMLHttpRequest), dan moet je deze data toch op een of andere manier omzetten in object of array of enig ander bewerkbare vorm. Gelukkig gaat dat in Javascript heel simpel. We kunnen het omzetten in een object met behulp van eval().
-
var json_object = eval( '(' + json_data + ')' );
Door de JSON data tussen haken te zetten, wordt de data door eval() als Javascript geinterpreteerd. Het gevolg is dat het wordt omgezet in een object zoals product van zo even. Pas hier op!
Er zit wel een nadeel aan het gebruik van eval(). Alle code die aan eval() wordt doorgegeven wordt ge-evalueerd als Javascript code. Dat vormt een groot veiligheidsrisico. Daarom heeft Douglas Crockford hiervoor handige functies geschreven. De functie eval() wordt vervangen door parseJSON().
-
var json_object = json_data.parseJSON();
Let hier goed op de syntax! Het is dus:
-
jouw_json_object_met_data.methode()
Om een object om te zetten in JSON formaat gebruik je toJSONString(), Javascript heeft geen ingebouwde functie voor dit.
-
var product =
-
{
-
"naam" : ["The Da Vinci Code", "Angels and Demons"],
-
"prijs" : [10, 11],
-
"betaald" : [false, true]
-
};
-
document.write(product.toJSONString());
Dit geeft als output:
-
{"naam":["The Da Vinci Code","Angels and Demons"],"prijs":[10,11],"betaald":[false,true]}
Hetzelfde zoals daarboven, maar zonder spaties en tabs. Je kunt dus een Javascript array omzetten in JSON formaat en dan versturen naar je server-side script. Een ander voorbeeld is het ontvangen van JSON data in Javascript. Nadat je parseJSON() hebt aangeroepen, heb je een object aangemaakt. Dan kun je de waardes benaderen zoals we dat voorheen hebben gedaan. Een contreet voorbeeld:
-
<html>
-
<head>
-
<script language="JavaScript" type="text/javascript" src="json.js"></script>
-
<title></title>
-
</head>
-
<body>
-
<script language="Javascript">
-
var product =
-
{
-
"naam" : ["The Da Vinci Code", "Angels and Demons"],
-
"prijs" : [10, 11],
-
"betaald" : [false, true]
-
};
-
-
// we simuleren alsof we json_data uit XMLHttpRequest
-
// hebben gehaald
-
var json_data = product.toJSONString(); // zet om in JSON formaat
-
-
var obj = json_data.parseJSON();
-
document.write(obj.naam[0]); //The Da Vinci Code
-
</script>
-
</body>
-
</html>
NOOT: Wanneer je Javascript's Object gebruikt, dan moet je nu goed opletten. Het decoden van JSON serialized Javascript Object()-en gaat niet zomaar. Daarvoor moet je het casten naar een array in PHP, wanneer je dat niet doet krijg je een stdClass object terug. Daar kan PHP niet mee omgaan en zul je een fatal error krijgen. Hieronder heb ik een voorbeeld. Het gebruik van de class wordt in het volgende gedeelte uitgelegd.
-
<html>
-
<head>
-
<script language="JavaScript" type="text/javascript" src="json.js"></script>
-
<title>Scriptorama.nl</title>
-
</head>
-
<body>
-
<script language="Javascript">
-
var arr = new Object();
-
-
arr['title'] = 'titel hier';
-
arr['description'] = 'desc hier';
-
-
var json_data = arr.toJSONString();
-
-
// quick-n-dirty een XHR request maken
-
// gebruik liever prototype: http://prototype.conio.net/
-
var request = false;
-
try {
-
request = new XMLHttpRequest();
-
} catch (trymicrosoft) {
-
try {
-
request = new ActiveXObject("Msxml2.XMLHTTP");
-
} catch (othermicrosoft) {
-
try {
-
request = new ActiveXObject("Microsoft.XMLHTTP");
-
} catch (failed) {
-
request = false;
-
}
-
}
-
}
-
-
if (!request)
-
alert("Error");
-
-
var url = "script.php?data=" + json_data;
-
request.open("GET", url, true);
-
request.onreadystatechange = updatePage;
-
request.send(null);
-
-
function updatePage() {
-
if (request.readyState == 4) {
-
if (request.status == 200) {
-
-
alert(request.responseText);
-
}
-
}
-
}
-
</script>
-
</body>
-
</html>
Hieronder staat het PHP script:
Show me the tools
Je zult vaak AJAX en JSON hand in hand zien. Met XMLHttpRequest wordt een server-side script aangeroepen die data terugstuurt in JSON formaat. Dit is beter dan data scheiden door tokens. Wat je veel terugziet in andere tutorials is dat je data gaat scheiden door tokens zoals || of ##. Stel dat je een lijst van namen terugkrijgt van een server-side script, dan geeft deze vaak zulke output:
-
Tri||Mathieu||Daniel
Je loopt al snel tegen limieten aan. Wat als je || letterlijk een keer nodig hebt? Of je wilt gegroepeerde data hebben? Dat lukt dus niet. Gelukkig biedt JSON uitkomst. Hieronder staat een voorbeeld hoe we een PHP array omzetten in JSON formaat. In PHP maken we een product array aan, zetten deze om in JSON formaat en sturen het resultaat terug naar de browser.
-
<?php
-
include('json.php');
-
-
// onze product array
-
'naam' =>
-
'prijs' =>
-
'betaald' =>
-
);
-
-
$json = new Services_JSON();
-
//output: {"naam":["The Da Vinci Code","Angels and Demons"],"prijs":[10,11],"betaald":[false,true]}
-
?>
Ik heb hier gebruik gemaakt van de class Services_JSON. Dit is een PEAR package en is hier te vinden. PHP heeft nog geen ingebouwde functies voor het encode-en / decode-en van JSON. Al ligt er wel een voorstel op tafel. Misschien binnenkort in PHP5! Tot die tijd kun je wel een extensie voor PHP gebruiken, deze moet je compileren met PHP.
Voor andere talen, hieronder staat een lijst met beschikbare tools:
C: http://oss.metaparadigm.com/json-c/
C++: http://cvs.sourceforge.net/viewcvs.py/zoolib/zoolib/src_other/misc/
C#: http://jayrock.berlios.de/
Delphi: https://sourceforge.net/projects/is-webstart/
Perl: http://search.cpan.org/dist/JSON/
Python: http://undefined.org/python/#simple_json
Ruby: http://rubyforge.org/snippet/detail.php?type=snippet&id=29
JSONRequest
Weet je nog waar AJAX voor stond? Asynchronous Javascript And XML. In meeste gevallen klopt die XML niet. In veel gevallen wordt met plain text gewerkt, met de data opgeslagen in XMLHttpRequest.responseText. Je zou dus een TextHttpRequest object moeten hebben (deze bestaat niet). Maar wat als je met JSON werkt?
Douglas Crockford is van mening dat er een JSONRequest object moet komen. Hij argumenteert dat het XMLHttpRequest model verschillende limieten heeft. Als eerste heeft het een 'same domain' beleid. Je kunt alleen een server-side script aanroepen die op het zelfde domein zit. Een XHR call vanaf www.a.nl naar www.b.nl kan dus niet (dit kun je makkelijk oplossen door de server-side script als proxy te laten functioneren). Daarnaast zegt Crockford dat XHR gevoelig is voor XSS (Cross Site Scripting). Een oplossing is het JSONRequest object. Deze zou alleen met data in JSON formaat kunnen werken, waardoor XSS tot het verleden hoort. Het domein beleid kun je hiermee dus ook elimineren. Op de pagina staat ook een specificatie. Wellicht wordt het een onderdeel van browsers in de toekomst. Zodra dat het geval is, weet je dat natuurlijk als eerst op Scriptorama!
XML vs JSON
Je kunt dus je AJAX web applicaties gebruiken met XML en JSON als data exchange formaten. Welke moet je nou gebruiken? Peter-Paul Koch heeft hier een interessante blog post erover, met voordelen en nadelen van het gebruik van HTML, XML en JSON. Douglas Crockford zet de overeenkomsten en verschillen nog even op een rijtje.
Dan heb je nog het debat over de snelheden. Welke is het snelst? Laten we eerst data vergelijken. Hieronder staat ons product array in JSON en XML formaat.
-
{
-
"naam" : ["The Da Vinci Code", "Angels and Demons"],
-
"prijs" : [10, 11],
-
"betaald" : [false, true]
-
}
-
<product>
-
<naam>The Da Vinci Code</naam>
-
<prijs>10</prijs>
-
<betaald>false</betaald>
-
-
<naam>Angels and Demons</naam>
-
<prijs>11</prijs>
-
<betaald>true</betaald>
-
</product>
De output van JSON is aanzienlijk kleiner. Betekent dit dan automatisch dat JSON parsen sneller is dan XML? Daar zijn de meningen nog uiteenlopend. Volgens deze benchmark scoort XML beter dan JSON als het gaat om grote hoeveelheden data. Dat komt vooral door XSL, wat erg snel werkt. Een ander groot verschil tussen JSON en XML is dat een JSON string altijd volledig in het geheugen geladen moet worden, terwijl je met XSL of XPATH juist kleine dingen kunt opzoeken. Aan de andere kant veronderstel ik dat JSON sneller is als het gaat om kleine hoeveelheden data, XML is wellicht dan overkill. Het ligt dus aan de situatie welke data exchange formaat je moet gebruiken.
Volg Scriptorama via RSS!
Reageer ook!
Mybic combineert ze allebei en is best wel handig.
http://www.litfuel.net/mybic/
Door brossiekoppie
op 05.05.06 @ 8:14 am | Permalink
Ook interessant qua leesbaarheid: YAML (superset van JSON, http://www.yaml.org/). De Syck extensie mag wat mij betreft standaard in elke PHP release (http://whytheluckystiff.net/syck/).
Door Michel
op 05.05.06 @ 10:06 am | Permalink
@Michel:
Ik heb me nog niet enorm verdiept in YAML, so correct me if I'm wrong, maar het grote nadeel lijkt alvast te zijn dat Javascript aparte support zal moeten krijgen voor YAML (user implemented) terwijl JSON juist gebaseerd is op een feature (object literal notation) uit de bestaande Javascript implementaties.
Door Mathieu Kooiman
op 05.05.06 @ 11:05 am | Permalink
Bedankt voor de heldere uitleg! Deze was mij erg behulpzaam! Daarbij moet ik wel opmerken dat een aantal van de voorbeelden (aan het begin) niet werken in IE7. Ik heb getracht te achterhalen waarom maar ben er nog niet achter...
Door Efraim Meulenberg
op 01.30.07 @ 3:58 pm | Permalink
Line and paragraph breaks automatic, e-mail address never displayed, HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>