JavaScript

43
JavaScript: The Good Parts Part Eleven: JSON Douglas Crockford [email protected]

Transcript of JavaScript

Page 1: JavaScript

JavaScript: The Good Parts

Part Eleven: JSON

Douglas [email protected]

Page 2: JavaScript

JSONThe x in Ajax

Douglas CrockfordYahoo! Inc.

Page 3: JavaScript

The Yoda of lambda programming and

JavaScript

Brendan Eich, 2006-07-31

Page 4: JavaScript

[JSON is] not even XML!Who did this travesty?

Let’s find a tree and string them up. Now.

Dave Winer, 2006-12-20

Page 5: JavaScript

any damn fool could produce a better data

format than XML

James Clark, 2007-04-06

Page 6: JavaScript

I Discovered JSON

• I do not claim to have invented JSON. It already existed in nature.

• I do not claim to have been the first to discover it.

• I gave it a name, a specification, and a little website.

• The rest happened by itself.

Page 7: JavaScript

JSON News

Page 8: JavaScript

Native JSON support in ECMAScript, Fifth Edition.

It is available now in IE8.

http://www.JSON.org/json2.js

Page 9: JavaScript

JSON.parse(text, reviver)

• text is a JSON text to be parsed.• reviver is an optional function that

will be called for each of the values in the new object, giving an opportunity to modify the result.

function reviver(key, value) { return new_value;}

Page 10: JavaScript

Example

• If a property name contains date, convert the value into a Date object.

function my_reviver(key, value) {

return key.indexOf('date') >= 0 ? new Date(value) : value;

}

my_object = JSON.parse(my_text, my_reviver);

Page 11: JavaScript

Recommended Practice

• Design your constructor functions to take a single parameter which is the value produced by JSON.parse.

• The constructor can attach structure and behavior to the data.

Page 12: JavaScript

JSON.stringify(value, replacer, space)

• value is a JavaScript value to be stringified.

• replacer is an optional function that will be called for each of the values, giving an opportunity to modify the result.

• space is an optional pretty printing parameter.

Page 13: JavaScript

toJSON

• An object may have or inherit a toJSON method that will be called by JSON.stringify.

• It allows the object to substitute another value.• It does not return the serialization of the value.• It returns the value to be serialized.

function toJSON(key) {

return new_value;}

Page 14: JavaScript

replacer

• The replacer function is passed the key and the value produced by toJSON.

• this is bound to the object that holds the key, so this[key] is the original value.

function replacer(key, value) { return new_value;}

Page 15: JavaScript

Example

• If a property name contains date, convert the value into string.

function my_reviver(key, value) {

return key.indexOf('date') >= 0 ? value.toISOString() : value;

}

my_object = JSON.stringify(my_text, my_reviver);

Page 16: JavaScript

replacer Whitelist

• If replacer is an array of strings, those strings will be used to select the properties that will be stringified.

Page 17: JavaScript

space

• The optional space parameter can be the number of spaces in each level in indentation, or a string (such as '\t') that will be accumulated for each level of indentation.

• This can produce strings that are easier to read.

Page 18: JavaScript

{ "value": "=", "arity": "binary", "first": { "value": "make_parse", "arity": "name" }, "second": { "value": "function", "arity": "function", "first": [], "second": [ { "value": "=",

Page 19: JavaScript

JSON Databases

• CouchDB is a distributed, fault-tolerant and schema-free document-oriented database accessible via a RESTful HTTP/JSON API.

• Also, Persevere, DBSlayer, StrokeDB, SpringDB.

Page 20: JavaScript

What about XML?

Page 21: JavaScript

XML Form<recipe name="bread" prep_time="5 mins" cook_time="3 hours"> <title>Basic bread</title> <ingredient amount="8" unit="dL">Flour</ingredient> <ingredient amount="10" unit="grams">Yeast</ingredient> <ingredient amount="4" unit="dL"

state="warm">Water</ingredient> <ingredient amount="1" unit="teaspoon">Salt</ingredient> <instructions> <step>Mix all ingredients together.</step> <step>Knead thoroughly.</step> <step>Cover with a cloth, and leave for one hour in warm

room.</step> <step>Knead again.</step> <step>Place in a bread baking tin.</step> <step>Cover with a cloth, and leave for one hour in warm

room.</step> <step>Bake in the oven at 180(degrees)C for 30 minutes.</step> </instructions> </recipe>

Page 22: JavaScript

Data Form{"recipe": { "name": "bread", "title": "Basic bread" "cook_time": "3 hours", "prep_time": "5 mins", "ingredient": [ {"amount": 8, "content": "Flour", "unit": "dL"}, {"amount": 10, "content": "Yeast", "unit": "grams"}, {"amount": 4, "content": "Water", "state": "warm", "unit": "dL"}, {"amount": 1, "content": "Salt", "unit": "teaspoon"} ], "instructions": {"step": [ "Mix all ingredients together.", "Knead thoroughly.", "Cover with a cloth, and leave for one hour in warm room.", "Knead again.", "Place in a bread baking tin.", "Cover with a cloth, and leave for one hour in warm room.", "Bake in the oven at 180(degrees)C for 30 minutes." ]}}}

Page 23: JavaScript

Data Form{"recipe": { "name": "bread", "title": "Basic bread" "cook_time": "3 hours", "prep_time": "5 mins", "ingredient": [ {"amount": 8, "content": "Flour", "unit": "dL"}, {"amount": 10, "content": "Yeast", "unit": "grams"}, {"amount": 4, "content": "Water", "state": "warm", "unit": "dL"}, {"amount": 1, "content": "Salt", "unit": "teaspoon"} ], "instructions": {"step": [ "Mix all ingredients together.", "Knead thoroughly.", "Cover with a cloth, and leave for one hour in warm room.", "Knead again.", "Place in a bread baking tin.", "Cover with a cloth, and leave for one hour in warm room.", "Bake in the oven at 180(degrees)C for 30 minutes." ]}}}

Page 24: JavaScript

Data Form{"recipe": { "name": "bread", "title": "Basic bread" "cook_time": "3 hours", "prep_time": "5 mins", "ingredient": [ {"amount": 8, "content": "Flour", "unit": "dL"}, {"amount": 10, "content": "Yeast", "unit": "grams"}, {"amount": 4, "content": "Water", "state": "warm", "unit": "dL"}, {"amount": 1, "content": "Salt", "unit": "teaspoon"} ], "instructions": {"step": [ "Mix all ingredients together.", "Knead thoroughly.", "Cover with a cloth, and leave for one hour in warm room.", "Knead again.", "Place in a bread baking tin.", "Cover with a cloth, and leave for one hour in warm room.", "Bake in the oven at 180(degrees)C for 30 minutes." ]}}}

my_object.recipe.instructions.step[0]

my_object.instructions[0]

Page 25: JavaScript

Data Form is more effective than XML at representing

data.It is not effective at

representing documents and semidocuments.

Page 26: JavaScript

Array Form["recipe", {"cook_time": "3 hours", "name": "bread", "prep_time": "5

mins"}, ["title", "Basic bread"], ["ingredient", {"amount": 8, "unit": "dL"}, "Flour"], ["ingredient", {"amount": 10, "unit": "grams"}, "Yeast"], ["ingredient", {"amount": 4, "state": "warm", "unit": "dL"},

"Water"], ["ingredient", {"amount": 1, "unit": "teaspoon"}, "Salt"], ["instructions", ["step", "Mix all ingredients together."], ["step", "Knead thoroughly."], ["step", "Cover with a cloth, and leave for one hour in warm

room."], ["step", "Knead again."], ["step", "Place in a bread baking tin."], ["step", "Cover with a cloth, and leave for one hour in warm

room."], ["step","Bake in the oven at 180(degrees)C for 30 minutes."] ]]

Page 27: JavaScript

Object Form{"tagName": "recipe", "cook_time": "3 hours", "name": "bread", "childNodes": [ {"tagName": "title", "childNodes": ["Basic bread"]}, {"amount": "8", "unit": "dL", "tagName": "ingredient", "childNodes":

["Flour"]}, {"amount": "10", "unit": "grams", "tagName": "ingredient", "childNodes":

["Yeast"]}, {"amount": "4", "unit": "dL", "tagName": "ingredient", "state": "warm",

"childNodes": ["Water"]}, {"amount": "1", "unit": "teaspoon", "tagName": "ingredient", "childNodes":

["Salt"]}, {"tagName": "instructions", "childNodes": [ {"tagName": "step", "childNodes": ["Mix all ingredients together."]}, {"tagName": "step", "childNodes": ["Knead thoroughly."]}, {"tagName": "step", "childNodes": ["Cover with a cloth, and leave for one

hour in warm room."]}, {"tagName": "step", "childNodes": ["Knead again."]}, {"tagName": "step", "childNodes": ["Place in a bread baking tin."]}, {"tagName": "step", "childNodes": ["Cover with a cloth, and leave for one

hour in warm room."]}, {"tagName": "step", "childNodes": ["Bake in the oven at 180(degrees)C for

30 minutes."]}]} ], "prep_time": "5 mins"}

Page 28: JavaScript

XML To Three JSON Forms

• Data Form is most compact.• Data Form is conveniently

manipulated by programs.• Data Form loses document structure.• The Array and Object forms retain

document structure (JSONML).• Array Form is more compact than

Object Form.• Object Form conventions match DOM.

Page 29: JavaScript

JSON.java Reference Implementation

http://www.JSON.org/java/

Page 30: JavaScript

Where did the idea come from that data should be

represented by a document format?

Page 31: JavaScript

RUNOFF.SK 1Text processing and word processing systemstypically require additional information tobe interspersed among the natural text ofthe document being processed. This addedinformation, called "markup", serves twopurposes:.TB 4.OF 4.SK 11.#Separating the logical elements of thedocument; and.OF 4.SK 12.#Specifying the processing functions to beperformed on those elements..OF 0.SK 1

Page 32: JavaScript

GML :h1.Chapter 1: Introduction :p.GML supported hierarchical containers, such as :ol :li.Ordered lists (like this one), :li.Unordered lists, and :li.Definition lists :eol. as well as simple structures. :p.Markup minimization (later generalized and formalized in SGML), allowed the end-tags to be omitted for the "h1" and "p" elements.

Page 33: JavaScript

:eol.

::ol.

</ol>

Page 34: JavaScript

Scribe

@Quote(Any damn fool)

( ) [ ] { } < > " " ' '

@Begin(Quote) Any damn fool@End(Quote)

Page 35: JavaScript

Scribe

@techreport(PUB, key="Tesler", author="Tesler, Larry", title="PUB: The Document Compiler", year=1972, number="ON-72", month="Sep", institution="Stanford University Artificial Intelligence Project")

@book(Volume3, key="Knuth", author="Knuth, Donald E.", title="Sorting and Searching", publisher="Addison-Wesley",year=1973, volume=3,

series="The Art of Computer Programming", address="Reading, Mass.")

Page 36: JavaScript

Languages

• Arabic • Bulgarian • Chinese • Czech • Dutch• French • German • Greek • Hebrew • Hungarian• Indonesian

• Italian• Japanese • Korean • Persian • Polish • Portuguese • Russian • Slovenian • Spanish • Turkish • Vietnamese

Page 37: JavaScript

Languages

• ActionScript• C / C++• C#• Cold Fusion• Delphi• E• Erlang• Haskell• Java• Lisp• Lua

• Perl• Objective-C• Objective CAML• PHP• Prolog• Python• Rebol• Ruby• Scheme• Squeak• TCL

Page 38: JavaScript

Versionless

• JSON has no version number.

• No revisions to the JSON grammar are anticipated.

• JSON is very stable.

• Stability is more valuable than any feature we could add.

Page 39: JavaScript

Supersets

• YAML is a superset of JSON. A YAML decoder is a JSON decoder.

• JavaScript is a superset of JSON. A JavaScript compiler is a JSON decoder.

• New programming languages based on JSON.

Page 40: JavaScript

JSONTvar rules = {

self: '<svg><{closed} stroke="{color}" points="{points}" /></svg>',

closed: function (x) {return x ? 'polygon' : 'polyline';}, 'points[*][*]': '{$} '

};

var data = {"color": "blue", "closed": true, "points": [[10,10], [20,10], [20,20], [10,20]]

};

jsonT(data, rules)

<svg><polygon stroke="blue" points="10 10 20 10 20 20 10 20 " /></svg>

Page 41: JavaScript

http://goessner.net/articles/jsont/

function jsonT(self, rules) { var T = { output: false, init: function () { for (var rule in rules) if (rule.substr(0,4) != "self") rules["self." + rule] = rules[rule]; return this; }, apply: function(expr) { var trf = function (s) { return s.replace(/{([A-Za-z0-9_\$\.\[\]\'@\(\)]+)}/g, function ($0, $1){ return T.processArg($1, expr); }) }, x = expr.replace(/\[[0-9]+\]/g, "[*]"), res; if (x in rules) { if (typeof(rules[x]) == "string") res = trf(rules[x]); else if (typeof(rules[x]) == "function") res = trf(rules[x](eval(expr)).toString()); } else res = T.eval(expr); return res; }, processArg: function (arg, parentExpr) { var expand = function (a, e) { return (e = a.replace(/^\$/,e)).substr(0, 4) != "self" ? ("self." + e) : e; }, res = ""; T.output = true; if (arg.charAt(0) == "@") res = eval(arg.replace(/@([A-za-z0-9_]+)\(([A-Za-z0-9_\$\.\[\]\']+)\)/, function($0, $1, $2){ return "rules['self." + $1 + "'](" + expand($2,parentExpr) + ")"; })); else if (arg != "$") res = T.apply(expand(arg, parentExpr)); else res = T.eval(parentExpr); T.output = false; return res; }, eval: function (expr) { var v = eval(expr), res = ""; if (typeof(v) != "undefined") { if (v instanceof Array) { for (var i = 0; i < v.length; i++) if (typeof(v[i]) != "undefined") res += T.apply(expr + "[" + i + "]"); } else if (typeof(v) == "object") { for (var m in v) if (typeof(v[m]) != "undefined") res += T.apply(expr+"."+m); } else if (T.output) res += v; } return res; } }; return T.init().apply("self");}

Page 42: JavaScript

Don't wrap JSON text in comments

• Intended to close a browser hole. /* jsontext */

• May open a new hole. "*/ evil(); /*"

• Security is not obtained by tricks.• Never put data on the wire unless you

intend that it be delivered. • Do not rely on Same Origin Policy.

Page 43: JavaScript

www.JSON.org