YUI recommends YUI3.

YUI 2 has been deprecated since 2011. This site acts as an archive for files and documentation.

This documentation is no longer maintained.

YUI 2: JSON utility

YUI 2: JSON utility

The JSON Utility provides methods for translating data to and from JavaScript Object Notation. JSON is a safe, efficient, and reliable data interchange format. This utility defers to native JSON methods in browsers that have support, and provides JavaScript implementations that conform to the ECMAScript 5 specification for those that don't yet.

Upgrade Notes

As of version 2.8.0, browser native JSON.parse and JSON.stringify will be used if present. The native implementations are much faster and safer than any implementation done in JavaScript.

In versions prior to 2.8, the signature and behavior of YAHOO.lang.JSON.stringify differed slightly from the reference implementation at JSON.org and the ECMAScript version 5 specification that grew from that. In order to leverage native methods as browsers adopt the ECMAScript 5 spec, the YUI implementation of stringify had to change so the behavior would be consistent across browsers with and without native JSON support.

Specifically, the stringify behavior that has changed from 2.7.0 to 2.8.0 is:

  • Cyclical object references are no longer replaced with null, but now throw an Error. It is therefore recommended to wrap both parse and stringify calls in try/catch blocks.
  • The third parameter no longer limits the depth of object serialization, but is now used to trigger formatted output.
  • Objects with a toJSON method will be first transformed using this method.
  • Object keys are no longer sorted alphabetically. This is possible to do with a replacer function.
  • Overriding YAHOO.lang.JSON.dateToString is no longer recommended because the default ISO 8601 serialization is defined in the spec. If Dates must be formatted differently, either preprocess the data or set useNativeStringify to false after overriding dateToString.

The implementation of YAHOO.lang.JSON.parse has not changed in a few versions and remains a safe approximation of the spec. If your application requires specific functionality from 2.7.0 or prior, you can continue to use prior versions. They should correctly parse and produce valid JSON.

Getting Started

To use the JSON Utility, include the following source files in your web page with the script tag:

  1. <!-- Dependencies -->
  2. <script src="http://yui.yahooapis.com/2.9.0/build/yahoo/yahoo-min.js"></script>
  3.  
  4. <!-- Source file -->
  5. <script src="http://yui.yahooapis.com/2.9.0/build/json/json-min.js"></script>
  6.  
<!-- Dependencies -->
<script src="http://yui.yahooapis.com/2.9.0/build/yahoo/yahoo-min.js"></script>
 
<!-- Source file -->
<script src="http://yui.yahooapis.com/2.9.0/build/json/json-min.js"></script>
 

YUI dependency configurator.

YUI Dependency Configurator:

Instead of copying and pasting the filepaths above, try letting the YUI dependency Configurator determine the optimal file list for your desired components; the Configurator uses YUI Loader to write out the full HTML for including the precise files you need for your implementation.

Note: If you wish to include this component via the YUI Loader, its module name is json. (Click here for the full list of module names for YUI Loader.)

Where these files come from: The files included using the text above will be served from Yahoo! servers. JavaScript files are minified, meaning that comments and white space have been removed to make them more efficient to download. To use the full, commented versions or the -debug versions of YUI JavaScript files, please download the library distribution and host the files on your own server.

Order matters: As is the case generally with JavaScript and CSS, order matters; these files should be included in the order specified above. If you include files in the wrong order, errors may result.

YAHOO.lang.JSON is a static class that does not require instantiation. Simply access the methods you need from YAHOO.lang.JSON.

Using YAHOO.lang.JSON

The JSON Utility extends YAHOO.lang, providing two static methods used for transforming data to and from JSON string format. These methods are described in the following sections.

Parsing JSON string data into JavaScript data

Pass a JSON string to YAHOO.lang.JSON.parse to convert it into live data. Optionally provide a second argument to filter or format the parsed object data during deserialization.

  1. var jsonString = '{"productId":1234,"price":24.5,"inStock":true,"bananas":null}';
  2.  
  3. // Parsing JSON strings can throw a SyntaxError exception, so we wrap the call
  4. // in a try catch block
  5. try {
  6. var prod = YAHOO.lang.JSON.parse(jsonString);
  7.  
  8. // We can now interact with the data
  9. if (prod.price < 25) {
  10. prod.price += 10; // Price increase!
  11. }
  12. }
  13. catch (e) {
  14. alert("Invalid product data");
  15. }
  16.  
var jsonString = '{"productId":1234,"price":24.5,"inStock":true,"bananas":null}';
 
// Parsing JSON strings can throw a SyntaxError exception, so we wrap the call
// in a try catch block
try {
    var prod = YAHOO.lang.JSON.parse(jsonString);
 
    // We can now interact with the data
    if (prod.price < 25) {
        prod.price += 10; // Price increase!
    }
}
catch (e) {
    alert("Invalid product data");
}
 

You can filter out data or format data during parse by passing a function as the second argument to parse. Values returned from the function will take the place of the original value. Return undefined to omit a key:value pair from the returned object.

  1. var currencySymbol = "$"
  2. function myFilter(key,val) {
  3. // format price as a string
  4. if (key == "price") {
  5. var f_price = currencySymbol + val.toFixed(2);
  6. }
  7.  
  8. // omit keys by returning undefined
  9. if (key == "bananas") {
  10. return undefined;
  11. }
  12. }
  13.  
  14. var formattedProd = YAHOO.lang.JSON.parse(jsonString, myFilter);
  15.  
  16. // key "bananas" is not present in the formattedProd object
  17. if (YAHOO.lang.isUndefined(formattedProd.bananas)) {
  18. alert("We have no bananas today");
  19. }
  20.  
  21. // and the price is the formatted string "$24.50"
  22. alert("Your price: " + formattedProd.price)
  23.  
var currencySymbol = "$"
function myFilter(key,val) {
    // format price as a string
    if (key == "price") {
        var f_price = currencySymbol + val.toFixed(2);
    }
 
    // omit keys by returning undefined
    if (key == "bananas") {
        return undefined;
    }
}
 
var formattedProd = YAHOO.lang.JSON.parse(jsonString, myFilter);
 
// key "bananas" is not present in the formattedProd object
if (YAHOO.lang.isUndefined(formattedProd.bananas)) {
    alert("We have no bananas today");
}
 
// and the price is the formatted string "$24.50"
alert("Your price: " + formattedProd.price)
 

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 safe. eval is capable of executing JavaScript's full notation, including calling functions and accessing cookies with all the privileges of a <script>.

To ensure that the data is safe in browsers that don't yet support native JSON functionality, YAHOO.lang.JSON.parse inspects the incoming string for potentially malevolent content (using methods derived from Douglas Crockford's json2.js) before giving it the green light to parse.

  1. // UNSAFE
  2. var data = eval('(' + shouldBeJsonData + ')');
  3.  
  4. // Safe
  5. var data = YAHOO.lang.JSON.parse(shouldBeJsonData);
  6.  
// UNSAFE
var data = eval('(' + shouldBeJsonData + ')');
 
// Safe
var data = YAHOO.lang.JSON.parse(shouldBeJsonData);
 

Stringifying JavaScript data into a JSON string

To convert a JavaScript object (or any permissable value) to a JSON string, pass that object to YAHOO.lang.JSON.stringify and capture the returned string.

  1. var myData = {
  2. puppies : [
  3. { name: "Ashley", age: 12 },
  4. { name: "Abby", age:9 }
  5. ]
  6. };
  7.  
  8. var jsonStr = YAHOO.lang.JSON.stringify(myData);
  9.  
  10. // jsonStr now contains the string (without the leading comment slashes)
  11. // {"puppies":[{"name":"Ashley","age":12},{"name":"Abby","age":9}]}
  12.  
var myData = {
    puppies : [
        { name: "Ashley", age: 12 },
        { name: "Abby", age:9 }
    ]
};
 
var jsonStr = YAHOO.lang.JSON.stringify(myData);
 
// jsonStr now contains the string (without the leading comment slashes)
// {"puppies":[{"name":"Ashley","age":12},{"name":"Abby","age":9}]}
 

Stringify's full signature is

  1. YAHOO.lang.JSON.stringify = function (data, filter, indent) { ... };
  2.  
YAHOO.lang.JSON.stringify = function (data, filter, indent) { ... };
 

The following sections will discuss the second and third arguments.

Filtering data before serialization

The optional second argument to stringify accepts either an array of strings or a function. Array values become a whitelist of object properties that should be serialized. A function value is known as a "replacer", and will be called for each object property:value pair, allowing you to modify the values or object structure as the input object is stringified.

  1. // a detailed object record set
  2. var records = [
  3. {id:1, name: "Bob", age: 47, favorite_color: "blue"},
  4. {id:2, name: "Sally", age: 30, favorite_color: "mauve"},
  5. {id:3, name: "Tommy", age: 13, favorite_color: "black"},
  6. {id:4, name: "Chaz", age: 26, favorite_color: "plaid"}
  7. ];
  8.  
  9. // Use an array of acceptable object key names as a whitelist.
  10. // To create a JSON string with only age and id
  11. var jsonStr = YAHOO.lang.JSON.stringify(records,["id","age"]);
  12.  
  13. // jsonStr now contains the string
  14. // [{"id":1,"age":47},{"id":2,"age":30},{"id":3,"age":13},{"id":4,"age":26}]
  15.  
  16. // OR use a replacer function to modify the object en route
  17. function replacer(key, value) {
  18. if (key === 'age') {
  19. return value > 35 ? '36-' :
  20. value > 25 ? '26-35' :
  21. value > 15 ? '16-25' :
  22. 'under 16';
  23. } else if (key === 'name') {
  24. return value; // also accept the name property
  25. } else {
  26. return undefined; // This will filter any other keys
  27. }
  28. }
  29. var jsonStr = YAHOO.lang.JSON.stringify(records, replacer);
  30.  
  31. // jsonStr now contains the string
  32. // [{"name":"Bob","age":"36-"},{"name":"Sally","age":"26-35"},...
  33.  
// 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 = YAHOO.lang.JSON.stringify(records,["id","age"]);
 
// jsonStr now contains the string
// [{"id":1,"age":47},{"id":2,"age":30},{"id":3,"age":13},{"id":4,"age":26}]
 
// OR use a replacer function to modify the object en route
function replacer(key, value) {
    if (key === 'age') {
        return value > 35 ? '36-' :
               value > 25 ? '26-35' :
               value > 15 ? '16-25' :
               'under 16';
    } else if (key === 'name') {
        return value;     // also accept the name property
    } else {
        return undefined; // This will filter any other keys
    }
}
var jsonStr = YAHOO.lang.JSON.stringify(records, replacer);
 
// jsonStr now contains the string
// [{"name":"Bob","age":"36-"},{"name":"Sally","age":"26-35"},...
 
Using toJSON to customize object serialization

Another option for including a special serialization strategy for your objects and classes is to assign a toJSON method. The return value of yourObject.toJSON() will be used in place of the object itself, and before the replacer is executed on that value.

  1. function Student(first, last, level, grades) {
  2. this.firstName = first;
  3. this.lastName = last;
  4. this.gradeLevel = level;
  5. this.grades = grades;
  6. }
  7.  
  8. // Offer a different object structure for JSON serialization
  9. Student.prototype.toJSON = function () {
  10. var gpa = 0,
  11. i = this.grades.length;
  12.  
  13. while (i--) {
  14. gpa += this.grades[i];
  15. }
  16.  
  17. return {
  18. name: this.lastName + ', ' + this.firstName,
  19. gpa: ((gpa / this.grades.length) / 25).toFixed(1)
  20. };
  21. };
  22.  
  23. var students = [];
  24. students.push( new Student("John", "Schmidt", 1, [95,90,92,87,100,100]) );
  25. students.push( new Student("Irene", "Gamel", 1, [72,70,88,76,100,95]) );
  26. students.push( new Student("Francis", "Yeh", 1, [53,67,100,0,78,88]) );
  27.  
  28. var studentJSON = YAHOO.lang.JSON.stringify(students);
  29.  
  30. // studentsJSON now contains the string
  31. // [{"name":"Schmidt, John","gpa":"3.8"},{"name":"Gamel, Irene","gpa":"3.3"},{"name":"Yeh, Francis","gpa":"2.6"}]
  32.  
function Student(first, last, level, grades) {
    this.firstName = first;
    this.lastName = last;
    this.gradeLevel = level;
    this.grades = grades;
}
 
// Offer a different object structure for JSON serialization
Student.prototype.toJSON = function () {
    var gpa = 0,
        i = this.grades.length;
 
    while (i--) {
        gpa += this.grades[i];
    }
 
    return {
        name: this.lastName + ', ' + this.firstName,
        gpa: ((gpa / this.grades.length) / 25).toFixed(1)
    };
};
 
var students = [];
students.push( new Student("John", "Schmidt", 1, [95,90,92,87,100,100]) );
students.push( new Student("Irene", "Gamel", 1, [72,70,88,76,100,95]) );
students.push( new Student("Francis", "Yeh", 1, [53,67,100,0,78,88]) );
 
var studentJSON = YAHOO.lang.JSON.stringify(students);
 
// studentsJSON now contains the string
// [{"name":"Schmidt, John","gpa":"3.8"},{"name":"Gamel, Irene","gpa":"3.3"},{"name":"Yeh, Francis","gpa":"2.6"}]
 

Some native objects include a toJSON method. For the most part, they do what you'd expect. new Boolean(true) => true, for example. One notable exception are Date instances, which serialize into an ISO 8601 format that looks like "1987-12-25T21:04:32Z".

Formatting the JSON output

To have stringify output JSON that's more human readable, pass either a string or number as the third parameter. Numbers will be translated into that number of spaces. Including the third parameter will trigger the output to be formatted with carriage returns and indentation using the specified string.

  1. var records = [
  2. {id:1, name: "Bob", age: 47, favorite_color: "blue"},
  3. {id:2, name: "Sally", age: 30, favorite_color: "mauve"},
  4. {id:3, name: "Tommy", age: 13, favorite_color: "black"},
  5. {id:4, name: "Chaz", age: 26, favorite_color: "plaid"}
  6. ];
  7.  
  8. var formattedJsonStr = YAHOO.lang.JSON.stringify(records,["name","age"],4);
  9.  
  10. /* formattedJsonStr now contains the string
  11. [
  12.   {
  13.   "name": "Bob",
  14.   "age": 47
  15.   },
  16.   {
  17.   "name": "Sally",
  18.   "age": 30
  19.   },
  20.   {
  21.   "name": "Tommy",
  22.   "age": 13
  23.   },
  24.   {
  25.   "name": "Chaz",
  26.   "age": 26
  27.   }
  28. ]
  29. */
  30.  
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"}
];
 
var formattedJsonStr = YAHOO.lang.JSON.stringify(records,["name","age"],4);
 
/* formattedJsonStr now contains the string
[
    {
        "name": "Bob",
        "age": 47
    },
    {
        "name": "Sally",
        "age": 30
    },
    {
        "name": "Tommy",
        "age": 13
    },
    {
        "name": "Chaz",
        "age": 26
    }
]
*/
 

Native implementations may differ slightly in their formatted output, but it should continue to be readable.

About the JSON format

JSON is a lightweight data format based on the object notation of the JavaScript language. It does not require JavaScript to read or write; it is easy to parse by any language and libraries and tools exist in many languages to handle JSON. You'll find several examples of support for JSON data in the YUI Library.

There is a wealth of good information about JSON and its distinction from XML as a data interchange format at Douglas Crockford's site, JSON.org.

JSON data is characterized as a collection of objects, arrays, booleans, strings, numbers, and null. The notation follows these guidelines:

  • Objects begin and end with curly braces ({}).
  • Object members consist of a string key and an associated value separated by a colon ( "key" : VALUE ).
  • Objects may contain any number of members, separated by commas ({ "key1" : VALUE1, "key2" : VALUE2 }).
  • Arrays begin and end with square braces and contain any number of values, separated by commas ([ VALUE1, VALUE2 ]).
  • Values can be a string, a number, an object, an array, or the literals true, false, and null.
  • Strings are surrounded by double quotes and can contain Unicode characters and common backslash escapes ("new\nline").

JSON.org has helpful format diagrams and specific information on allowable string characters.

Here is a simple example of a valid JSON string:

  1. {
  2. "Image": {
  3. "Width":800,
  4. "Height":600,
  5. "Title":"View from 15th Floor",
  6. "Thumbnail":
  7. {
  8. "Url":"http:\/\/scd.mm-b1.yimg.com\/image\/481989943",
  9. "Height": 125,
  10. "Width": "100"
  11. },
  12. "IDs":[ 116, 943, 234, 38793 ]
  13. }
  14. }
  15.  
{
  "Image": {
    "Width":800,
    "Height":600,
    "Title":"View from 15th Floor",
    "Thumbnail":
    {
      "Url":"http:\/\/scd.mm-b1.yimg.com\/image\/481989943",
      "Height": 125,
      "Width": "100"
    },
    "IDs":[ 116, 943, 234, 38793 ]
  }
}
 

This structure should look familiar to JavaScript programmers (for good reason). Note, however the solidus (forward slash) characters in the "Url" value are escaped.

Notes about current native JSON support

Native JSON support in JavaScript is defined in the ECMAScript 5 specification (still in draft as of August 2009). However, most of the major browser vendors have already implemented this feature in recent versions of their JavaScript engines. Because the feature is new and the specification was still in draft while they were implementing the JSON API, there are gotchas involved in leveraging the disparate native behaviors.

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, YUI's JSON Utility will leverage native behavior in implementing browsers by default. However, as of version 2.8.0, you can choose to use the JavaScript implementation of parse or stringify or both, by setting some new static properties.

  1. // Always use the JavaScript implementation for parsing
  2. YAHOO.lang.JSON.useNativeParse = false;
  3.  
  4. // Always use the JavaScript implementation for stringifying
  5. YAHOO.lang.JSON.useNativeStringify = false;
  6.  
// Always use the JavaScript implementation for parsing
YAHOO.lang.JSON.useNativeParse = false;
 
// Always use the JavaScript implementation for stringifying
YAHOO.lang.JSON.useNativeStringify = false;
 

Known Issues

Older versions of PrototypeJS, and possibly other libraries, add several toJSON methods to native prototypes. Most harmful is the Array.prototype.toJSON method which behaves differently than the ES5 specification recommends for toJSON implementations. The result is that stringifying objects that contain arrays will result in incorrect output. The array will be double serialized. For example:

  1. var obj = {
  2. property: "value",
  3. boom: ["this", "is", "the", "bug"]
  4. };
  5.  
  6. var output = YAHOO.lang.JSON.stringify(obj);
  7.  
  8. // output should look like
  9. // {"property":"value","boom":["this","is","the","bug"]}
  10.  
  11. // but with Array.prototype.toJSON added, results in
  12. // {"property":"value","boom":"[\"this\",\"is\",\"the\",\"bug\"]"}
  13.  
  14. // Note the value of the "boom" property is a string, not an array
  15.  
var obj = {
    property: "value",
    boom: ["this", "is", "the", "bug"]
};
 
var output = YAHOO.lang.JSON.stringify(obj);
 
// output should look like
// {"property":"value","boom":["this","is","the","bug"]}
 
// but with Array.prototype.toJSON added, results in
// {"property":"value","boom":"[\"this\",\"is\",\"the\",\"bug\"]"}
 
// Note the value of the "boom" property is a string, not an array
 

This is the result from both the JavaScript implementation of stringify as well as the native implementation in modern browsers.

The workaround for this recommended by Tobie Langel (maintainer of PrototypeJS) is:

  1. delete Number.prototype.toJSON;
  2. delete Boolean.prototype.toJSON;
  3. delete String.prototype.toJSON;
  4. delete Array.prototype.toJSON;
  5.  
  6. Hash.prototype.toJSON = function() {
  7. return this.toObject();
  8. };
  9.  
  10. Object.toJSON = YAHOO.lang.JSON.stringify;
delete Number.prototype.toJSON;
delete Boolean.prototype.toJSON;
delete String.prototype.toJSON;
delete Array.prototype.toJSON;
 
Hash.prototype.toJSON = function() {
    return this.toObject();
};
 
Object.toJSON = YAHOO.lang.JSON.stringify;

YUI on Mobile: Using JSON Utility with "A-Grade" Mobile Browsers

About this Section: YUI generally works well with mobile browsers that are based on A-Grade browser foundations. For example, Nokia's N-series phones, including the N95, use a browser based on Webkit — the same foundation shared by Apple's Safari browser, which is found on the iPhone. The fundamental challenges in developing for this emerging class of full, A-Grade-derived browsers on handheld devices are:

  • Screen size: You have a much smaller canvas;
  • Input devices: Mobile devices generally do not have mouse input, and therefore are missing some or all mouse events (like mouseover);
  • Processor power: Mobile devices have slower processors that can more easily be saturated by JavaScript and DOM interactions — and processor usage affects things like battery life in ways that don't have analogues in desktop browsers;
  • Latency: Most mobile devices have a much higher latency on the network than do terrestrially networked PCs; this can make pages with many script, css or other types of external files load much more slowly.

There are other considerations, many of them device/browser specific (for example, current versions of the iPhone's Safari browser do not support Flash). The goal of these sections on YUI User's Guides is to provide you some preliminary insights about how specific components perform on this emerging class of mobile devices. Although we have not done exhaustive testing, and although these browsers are revving quickly and present a moving target, our goal is to provide some early, provisional advice to help you get started as you contemplate how your YUI-based application will render in the mobile world.

More Information:

There are no known concerns with the JSON Utility on mobile browsers at this time.

Support & Community

The YUI Library and related topics are discussed on the on the YUILibrary.com forums.

Also be sure to check out YUIBlog for updates and articles about the YUI Library written by the library's developers.

Filing Bugs & Feature Requests

The YUI Library's public bug tracking and feature request repositories are located on the YUILibrary.com site. Before filing new feature requests or bug reports, please review our reporting guidelines.

Copyright © 2013 Yahoo! Inc. All rights reserved.

Privacy Policy - Copyright Policy - Job Openings