+ The JSON module is an implementation of the ECMA 5 specification for + transforming data to and from JavaScript Object + Notation. JSON is a safe, efficient, and reliable data interchange + format. This module provides a JavaScript implementation of the spec, + based on Douglas + Crockford's json2.js. For browsers with native support it defers + to the native implementation. +
+Getting Started
+ ++To include the source files for JSON and its dependencies, first load +the YUI seed file if you haven't already loaded it. +
+ +<script src="http://yui.yahooapis.com/3.10.3/build/yui/yui-min.js"></script>+ + +
+Next, create a new YUI instance for your application and populate it with the
+modules you need by specifying them as arguments to the YUI().use() method.
+YUI will automatically load any dependencies required by the modules you
+specify.
+
<script>
+// Create a new YUI instance and populate it with the required modules.
+YUI().use('json-parse', 'json-stringify', function (Y) {
+ // JSON is available and ready for use. Add implementation
+ // code here.
+});
+</script>
+
+
+
+For more information on creating YUI instances and on the
+use() method, see the
+documentation for the YUI Global Object.
+
Using the JSON Utility
+ +JSON module overview
+ +
+ The JSON module adds the namespace JSON to your YUI instance.
+ Its methods are static, available from this namespace.
+
+ To minimize the code footprint when some functionality is not required, + JSON has been broken up into the following modules: +
+ +-
+
json-parse
+ -
+ Adds
Y.JSON.parse(..)method to the YUI instance. Use + this module if all you will be doing is parsing JSON strings. +
+
+ json-stringify
+ -
+ Adds
Y.JSON.stringify(..)method and its supporting + methods and properties to the YUI instance. Use this module if all you + will be doing is serializing JavaScript objects to JSON strings. +
+
+ json
+ -
+ A rollup of
json-parseandjson-stringify+ modules. Use this if you need to both parse JSON strings and serialize + objects to JSON strings. +
+
Parsing JSON strings into native JavaScript values
+ +
+ Provided a string containing data in JSON format, simply pass the string to
+ parse and capture the return value.
+
YUI().use('json-parse', function (Y) {
+
+var jsonString = '{"products":['+
+ '{"id":1,"price":0.99,"inStock":true,"name":"grapes"},'+
+ '{"id":2,"price":3.5,"inStock":false,"name":"passion fruit"},'+
+ '{"id":3,"price":2.5,"inStock":true,"name":"bananas"}'+
+']}';
+
+// JSON.parse throws a SyntaxError when passed invalid JSON
+try {
+ var data = Y.JSON.parse(jsonString);
+}
+catch (e) {
+ alert("Invalid product data");
+}
+
+// We can now interact with the data
+for (var i = data.products.length - 1; i >= 0; --i) {
+ var p = data.products[i];
+ if (p.price < 1) {
+ p.price += 1; // Price increase!
+ }
+}
+
+});
+
+
+Using the "reviver" parameter
+ +
+ The optional second parameter to parse accepts a function that
+ will be executed on each member of the parsed JavaScript object. Each call
+ to the reviver function is passed the key and associated value, and is
+ executed from the context of the object containing the key. If the return
+ value of the reviver is undefined, the key will be omitted
+ from the returned object.
+
+ Typical uses of reviver functions are filtering, formatting, and value + conversion. +
+ + +YUI().use('json-parse', function (Y) {
+
+ var jsonString = '{"products":['+
+ '{"id":1,"price":0.99,"inStock":true,"name":"grapes"},'+
+ '{"id":2,"price":3.5,"inStock":false,"name":"passion fruit"},'+
+ '{"id":3,"price":2.5,"inStock":true,"name":"bananas"}'+
+ ']}';
+
+ // Remove all out of stock entries and bananas. Format prices.
+ var currencySymbol = '$';
+ var reviver = function (key,val) {
+ if (key === 'inStock' && !val) {
+ return undefined;
+ } else if (val === 'bananas') {
+ return undefined;
+ } else if (key === 'price') {
+ val += val % 1 ? "0" : ".00";
+ var pIdx = val.indexOf('.');
+ val = pIdx ? "0" + val : val;
+ val = currencySymbol + val.substr(0,pIdx + 3);
+ }
+
+ return val;
+ };
+
+ // JSON.parse throws a SyntaxError when passed invalid JSON
+ try {
+ var data = Y.JSON.parse(jsonString,reviver);
+ }
+ catch (e) {
+ alert("Invalid product data");
+ }
+
+ // We can now interact with the data
+ alert(data.products.length); // 1
+ alert(data.products[0].price); // $0.99
+
+});
+
+
+A word of caution against using eval
+
+
+ JSON data format is a subset of JavaScript notation, meaning that
+ it is possible to use JavaScript eval to transform JSON data
+ to live data. However, it is unsafe practice to assume that data reaching
+ your code is not malicious. eval is capable of executing
+ JavaScript's full syntax, including calling functions and accessing cookies
+ with all the privileges of a <script>. To ensure that
+ the data is safe, the JSON module's parse method inspects the
+ incoming string (using methods derived from Douglas Crockford's json2.js)
+ and verifies that it is safe before giving it the green light to parse.
+
// UNSAFE
+var data = eval('(' + shouldBeJsonData + ')');
+
+// Safe
+var data = Y.JSON.parse(shouldBeJsonData);
+
+
+Creating JSON strings from JavaScript objects
+ +
+ To convert a JavaScript object (or any permissable value) to a JSON string,
+ pass that object to Y.JSON.stringify and capture the returned
+ string.
+
YUI().use("json-stringify", function (Y) {
+
+ var myData = {
+ troop : [
+ { name: "Ashley", age: 12 },
+ { name: "Abby", age:9 }
+ ]
+ };
+
+ var jsonStr = Y.JSON.stringify(myData);
+
+ alert(jsonStr); // {"troop":[{"name":"Ashley","age":12},{"name":"Abby","age":9}]}
+});
+
+
+Using a whitelist
+ +
+ To serialize only a fixed subset of keys, provide an array of key names as
+ the second parameter to stringify.
+
YUI().use("json-stringify", function (Y) {
+
+ // a detailed object record set
+ var records = [
+ {id:1, name: "Bob", age: 47, favorite_color: "blue"},
+ {id:2, name: "Sally", age: 30, favorite_color: "mauve"},
+ {id:3, name: "Tommy", age: 13, favorite_color: "black"},
+ {id:4, name: "Chaz", age: 26, favorite_color: "plaid"}
+ ];
+
+ // Use an array of acceptable object key names as a whitelist.
+ // To create a JSON string with only age and id
+ var jsonStr = Y.JSON.stringify(records,["id","age"]);
+
+ alert(jsonStr);
+ // [{"id":1,"age":47},{"id":2,"age":30},{"id":3,"age":13},{"id":4,"age":26}]
+
+});
+
+
+Using a custom "replacer" function
+ +
+ For more granular control of how values in your object are serialized, you
+ can pass a replacer function as the second parameter to
+ stringify. The replacer will be called for each key value
+ pair, and executed from the context of the key's host object. The return
+ value of the replacer will be serialized in place of the raw value.
+
YUI().use("json-stringify", function (Y) {
+
+ // a detailed object record set
+ var records = [
+ {id:1, name: "Bob", birthdate: "2/27/1964", favorite_color: "blue"},
+ {id:2, name: "Sally", birthdate: "9/30/1983", favorite_color: "mauve"},
+ {id:3, name: "Tommy", birthdate: "3/11/1990", favorite_color: "black"},
+ {id:4, name: "Chaz", birthdate: "5/22/1975", favorite_color: "plaid"}
+ ];
+
+ // Create a replacer to blacklist the id and convert the birthdate to a Date
+ var replacer = function (key,val) {
+ // blacklist id and favorite_color
+ if (key === 'id' || key === 'favorite_color') {
+ return undefined;
+
+ // convert birthdate to a Date instance (serialized as UTC date string)
+ } else if (key === 'birthdate') {
+ var d = new Date(),
+ bd = val.split('/');
+ d.setFullYear(bd[2],bd[0]-1,bd[1]);
+ d.setHours(0,0,0);
+ return d;
+ }
+
+ return val;
+ };
+
+ var jsonStr = Y.JSON.stringify(records,replacer);
+
+ alert(jsonStr);
+ // [{"name":"Bobby","birthdate":"1964-02-28T08:00:00Z"},{"name":"Sally","birthdate":"1983-09-30T07:00:00Z"},{"name":"Tommy","birthdate":"1990-03-11T08:00:00Z"},{"name":"Chaz","birthdate":"1975-05-23T07:00:00Z"}]
+
+});
+
+
+Formatting JSON output
+ +
+ To create readable JSON, pass a string or number as the third parameter to
+ stringify. Object and Array members will be separated with
+ newlines and indented. If a string is supplied, that string will be used
+ for the indentation. If a number is passed, that number of spaces will be
+ used.
+
YUI().use('json-stringify', function (Y) {
+
+ var fam = {
+ family: "Franklin",
+ children: [ "Bob", "Emily", "Sam" ]
+ };
+
+ // format serialization with four spaces
+ var jsonStr = Y.JSON.stringify(fam,null,4);
+
+ alert(jsonStr);
+ /*
+ {
+ "family": "Franklin",
+ "children": [
+ "Bob",
+ "Emily",
+ "Sam"
+ ]
+ }
+ */
+
+});
+
+
+Catching JSON errors
+ +
+ ECMA 5 states that parse should throw an error when an invalid
+ JSON string is input. It also states that stringify should
+ throw an error when an object with cyclical references is input.
+
+ For this reason, it is recommended that both parse and
+ stringify be called from within
+ try/catch blocks.
+
try {
+ // BOOM
+ Y.JSON.parse("{'this string': is, not_valid: ['J','S','O','N'] }");
+}
+catch (e) {
+ alert("A string may eval to the same object, but might not be valid JSON");
+}
+
+// This is safe to stringify
+var myData = {
+ troop : [
+ { name: "Ashley", age: 12 },
+ { name: "Abby", age:9 }
+ ]
+};
+
+// Create a cyclical reference
+myData.troop[0]["NEWKEY"] = myData;
+
+try {
+ // BOOM
+ jsonStr = Y.JSON.stringify(myData);
+} catch (e) {
+ alert("Cyclical references can sneak in. Remember to wrap stringify.");
+}
+
+
+Notes about native JSON support
+ ++ Native JSON support in JavaScript is defined in the ECMAScript 5 + specification, which was finalized in September 2009. However, most of the + major browser vendors had already implemented this feature in their + JavaScript engines while the spec was still in draft. As + a result of the timing and the fact that native JSON is a new feature, + there are gotchas involved in leveraging the disparate native + behaviors in certain browsers. +
+ +
+ In general, it is preferable to use the native behavior for
+ JSON.parse as it is much faster and safer than any JavaScript
+ implementation. There are also very few known critical issues with
+ supporting browsers.
+
+ Stringify has more pitfalls and inconsistencies, but they may not affect
+ your use cases. As with parse, the native implementation of
+ stringify is faster, but only marginally so with reasonably
+ sized input. In most cases, choosing the JavaScript implementation will
+ not affect performance and may be preferable for its cross browser
+ consistency.
+
+ As noted above, the JSON module will leverage native behavior in
+ implementing browsers by default. However, you can choose to opt out of
+ leveraging native parse or stringify by setting
+ the useNativeJSONParse and
+ useNativeJSONStringify configuration options.
+
YUI({
+ // Always use the JavaScript implementation for parsing
+ useNativeJSONParse: false,
+
+ // Always use the JavaScript implementation for stringifying
+ useNativeJSONStringify: false
+}).use('json', function (Y) {
+ //...
+});
+
+
+Changes in 3.9.0
+ +
+ As of version 3.9.0 YUI has changed to loading the JavaScript
+ implementation of JSON only when the browser does not provide a native
+ API. You can no longer change the desired implementation at run-time
+ by changing Y.JSON.useNativeParse. Since native JSON implementations
+ have become much more stable this results in a smaller download
+ for most users. You can still chose to use the JavaScript fallback
+ by calling Y.use('json-parse-shim') or Y.use('json-stringify-shim').
+
Known Issues
+-
+
-
+
Native JSON.stringify treats regex values as a function on Android 2.3.
+Y.JSON.stringify([{ + "str" : "string", + "arr" : [5, /some regex/] +}]); +//modern browsers return +[{"str":"string","arr":[5,{}]}] +//Android 2.3.4 returns +[{"str":"string","arr":[5,null]}]+ +
+
