Path: blob/trunk/third_party/closure/goog/format/jsonprettyprinter.js
2868 views
// Copyright 2010 The Closure Library Authors. All Rights Reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS-IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314/**15* @fileoverview Creates a string of a JSON object, properly indented for16* display.17*18*/1920goog.provide('goog.format.JsonPrettyPrinter');21goog.provide('goog.format.JsonPrettyPrinter.SafeHtmlDelimiters');22goog.provide('goog.format.JsonPrettyPrinter.TextDelimiters');2324goog.require('goog.html.SafeHtml');25goog.require('goog.json');26goog.require('goog.json.Serializer');27goog.require('goog.string');28goog.require('goog.string.format');29303132/**33* Formats a JSON object as a string, properly indented for display. Supports34* displaying the string as text or html. Users can also specify their own35* set of delimiters for different environments. For example, the JSON object:36*37* <code>{"a": 1, "b": {"c": null, "d": true, "e": [1, 2]}}</code>38*39* Will be displayed like this:40*41* <code>{42* "a": 1,43* "b": {44* "c": null,45* "d": true,46* "e": [47* 1,48* 249* ]50* }51* }</code>52* @param {?goog.format.JsonPrettyPrinter.TextDelimiters=} opt_delimiters53* Container for the various strings to use to delimit objects, arrays,54* newlines, and other pieces of the output.55* @constructor56*/57goog.format.JsonPrettyPrinter = function(opt_delimiters) {5859/**60* The set of characters to use as delimiters.61* @private @const {!goog.format.JsonPrettyPrinter.TextDelimiters}62*/63this.delimiters_ =64opt_delimiters || new goog.format.JsonPrettyPrinter.TextDelimiters();6566/**67* Used to serialize property names and values.68* @private @const {!goog.json.Serializer}69*/70this.jsonSerializer_ = new goog.json.Serializer();71};727374/**75* Formats a JSON object as a string, properly indented for display.76* @param {*} json The object to pretty print. It could be a JSON object, a77* string representing a JSON object, or any other type.78* @return {string} Returns a string of the JSON object, properly indented for79* display.80*/81goog.format.JsonPrettyPrinter.prototype.format = function(json) {82var buffer = this.format_(json);83var output = '';84for (var i = 0; i < buffer.length; i++) {85var item = buffer[i];86output += item instanceof goog.html.SafeHtml ?87goog.html.SafeHtml.unwrap(item) :88item;89}90return output;91};929394/**95* Formats a JSON object as a SafeHtml, properly indented for display.96* @param {*} json The object to pretty print. It could be a JSON object, a97* string representing a JSON object, or any other type.98* @return {!goog.html.SafeHtml} A HTML code of the JSON object.99*/100goog.format.JsonPrettyPrinter.prototype.formatSafeHtml = function(json) {101return goog.html.SafeHtml.concat(this.format_(json));102};103104105/**106* Formats a JSON object and returns an output buffer.107* @param {*} json The object to pretty print.108* @return {!Array<string|!goog.html.SafeHtml>}109* @private110*/111goog.format.JsonPrettyPrinter.prototype.format_ = function(json) {112// If input is undefined, null, or empty, return an empty string.113if (!goog.isDefAndNotNull(json)) {114return [];115}116if (goog.isString(json)) {117if (goog.string.isEmptyOrWhitespace(json)) {118return [];119}120// Try to coerce a string into a JSON object.121json = goog.json.parse(json);122}123var outputBuffer = [];124this.printObject_(json, outputBuffer, 0);125return outputBuffer;126};127128129/**130* Formats a property value based on the type of the propery.131* @param {*} val The object to format.132* @param {!Array<string|!goog.html.SafeHtml>} outputBuffer The buffer to write133* the response to.134* @param {number} indent The number of spaces to indent each line of the135* output.136* @private137*/138goog.format.JsonPrettyPrinter.prototype.printObject_ = function(139val, outputBuffer, indent) {140var typeOf = goog.typeOf(val);141switch (typeOf) {142case 'null':143case 'boolean':144case 'number':145case 'string':146// "null", "boolean", "number" and "string" properties are printed147// directly to the output.148this.printValue_(149/** @type {null|string|boolean|number} */ (val), typeOf,150outputBuffer);151break;152case 'array':153// Example of how an array looks when formatted154// (using the default delimiters):155// [156// 1,157// 2,158// 3159// ]160outputBuffer.push(this.delimiters_.arrayStart);161var i = 0;162// Iterate through the array and format each element.163for (i = 0; i < val.length; i++) {164if (i > 0) {165// There are multiple elements, add a comma to separate them.166outputBuffer.push(this.delimiters_.propertySeparator);167}168outputBuffer.push(this.delimiters_.lineBreak);169this.printSpaces_(indent + this.delimiters_.indent, outputBuffer);170this.printObject_(171val[i], outputBuffer, indent + this.delimiters_.indent);172}173// If there are no properties in this object, don't put a line break174// between the beginning "[" and ending "]", so the output of an empty175// array looks like <code>[]</code>.176if (i > 0) {177outputBuffer.push(this.delimiters_.lineBreak);178this.printSpaces_(indent, outputBuffer);179}180outputBuffer.push(this.delimiters_.arrayEnd);181break;182case 'object':183// Example of how an object looks when formatted184// (using the default delimiters):185// {186// "a": 1,187// "b": 2,188// "c": "3"189// }190outputBuffer.push(this.delimiters_.objectStart);191var propertyCount = 0;192// Iterate through the object and display each property.193for (var name in val) {194if (!val.hasOwnProperty(name)) {195continue;196}197if (propertyCount > 0) {198// There are multiple properties, add a comma to separate them.199outputBuffer.push(this.delimiters_.propertySeparator);200}201outputBuffer.push(this.delimiters_.lineBreak);202this.printSpaces_(indent + this.delimiters_.indent, outputBuffer);203this.printName_(name, outputBuffer);204outputBuffer.push(205this.delimiters_.nameValueSeparator, this.delimiters_.space);206this.printObject_(207val[name], outputBuffer, indent + this.delimiters_.indent);208propertyCount++;209}210// If there are no properties in this object, don't put a line break211// between the beginning "{" and ending "}", so the output of an empty212// object looks like <code>{}</code>.213if (propertyCount > 0) {214outputBuffer.push(this.delimiters_.lineBreak);215this.printSpaces_(indent, outputBuffer);216}217outputBuffer.push(this.delimiters_.objectEnd);218break;219// Other types, such as "function", aren't expected in JSON, and their220// behavior is undefined. In these cases, just print an empty string to the221// output buffer. This allows the pretty printer to continue while still222// outputing well-formed JSON.223default:224this.printValue_('', 'unknown', outputBuffer);225}226};227228229/**230* Prints a property name to the output.231* @param {string} name The property name.232* @param {!Array<string|!goog.html.SafeHtml>} outputBuffer The buffer to write233* the response to.234* @private235*/236goog.format.JsonPrettyPrinter.prototype.printName_ = function(237name, outputBuffer) {238outputBuffer.push(239this.delimiters_.formatName(this.jsonSerializer_.serialize(name)));240};241242243/**244* Prints a property name to the output.245* @param {string|boolean|number|null} val The property value.246* @param {string} typeOf The type of the value. Used to customize247* value-specific css in the display. This allows clients to distinguish248* between different types in css. For example, the client may define two249* classes: "goog-jsonprettyprinter-propertyvalue-string" and250* "goog-jsonprettyprinter-propertyvalue-number" to assign a different color251* to string and number values.252* @param {!Array<string|!goog.html.SafeHtml>} outputBuffer The buffer to write253* the response to.254* @private255*/256goog.format.JsonPrettyPrinter.prototype.printValue_ = function(257val, typeOf, outputBuffer) {258var value = this.jsonSerializer_.serialize(val);259outputBuffer.push(this.delimiters_.formatValue(value, typeOf));260};261262263/**264* Print a number of space characters to the output.265* @param {number} indent The number of spaces to indent the line.266* @param {!Array<string|!goog.html.SafeHtml>} outputBuffer The buffer to write267* the response to.268* @private269*/270goog.format.JsonPrettyPrinter.prototype.printSpaces_ = function(271indent, outputBuffer) {272outputBuffer.push(goog.string.repeat(this.delimiters_.space, indent));273};274275276277/**278* A container for the delimiting characters used to display the JSON string279* to a text display. Each delimiter is a publicly accessible property of280* the object, which makes it easy to tweak delimiters to specific environments.281* @constructor282*/283goog.format.JsonPrettyPrinter.TextDelimiters = function() {};284285286/**287* Represents a space character in the output. Used to indent properties a288* certain number of spaces, and to separate property names from property289* values.290* @type {string}291*/292goog.format.JsonPrettyPrinter.TextDelimiters.prototype.space = ' ';293294295/**296* Represents a newline character in the output. Used to begin a new line.297* @type {string|!goog.html.SafeHtml}298*/299goog.format.JsonPrettyPrinter.TextDelimiters.prototype.lineBreak = '\n';300301302/**303* Represents the start of an object in the output.304* @type {string}305*/306goog.format.JsonPrettyPrinter.TextDelimiters.prototype.objectStart = '{';307308309/**310* Represents the end of an object in the output.311* @type {string}312*/313goog.format.JsonPrettyPrinter.TextDelimiters.prototype.objectEnd = '}';314315316/**317* Represents the start of an array in the output.318* @type {string}319*/320goog.format.JsonPrettyPrinter.TextDelimiters.prototype.arrayStart = '[';321322323/**324* Represents the end of an array in the output.325* @type {string}326*/327goog.format.JsonPrettyPrinter.TextDelimiters.prototype.arrayEnd = ']';328329330/**331* Represents the string used to separate properties in the output.332* @type {string}333*/334goog.format.JsonPrettyPrinter.TextDelimiters.prototype.propertySeparator = ',';335336337/**338* Represents the string used to separate property names from property values in339* the output.340* @type {string|!goog.html.SafeHtml}341*/342goog.format.JsonPrettyPrinter.TextDelimiters.prototype.nameValueSeparator = ':';343344345/**346* A string that's placed before a property name in the output. Useful for347* wrapping a property name in an html tag.348* @type {string}349*/350goog.format.JsonPrettyPrinter.TextDelimiters.prototype.preName = '';351352353/**354* A string that's placed after a property name in the output. Useful for355* wrapping a property name in an html tag.356* @type {string}357*/358goog.format.JsonPrettyPrinter.TextDelimiters.prototype.postName = '';359360361/**362* Formats a property name before adding it to the output.363* @param {string} name The property name.364* @return {string|!goog.html.SafeHtml}365*/366goog.format.JsonPrettyPrinter.TextDelimiters.prototype.formatName = function(367name) {368return this.preName + name + this.postName;369};370371372/**373* A string that's placed before a property value in the output. Useful for374* wrapping a property value in an html tag.375* @type {string}376*/377goog.format.JsonPrettyPrinter.TextDelimiters.prototype.preValue = '';378379380/**381* A string that's placed after a property value in the output. Useful for382* wrapping a property value in an html tag.383* @type {string}384*/385goog.format.JsonPrettyPrinter.TextDelimiters.prototype.postValue = '';386387388/**389* Formats a value before adding it to the output.390* @param {string} value The value.391* @param {string} typeOf The type of the value obtained by goog.typeOf.392* @return {string|!goog.html.SafeHtml}393*/394goog.format.JsonPrettyPrinter.TextDelimiters.prototype.formatValue = function(395value, typeOf) {396return goog.string.format(this.preValue, typeOf) + value + this.postValue;397};398399400/**401* Represents the number of spaces to indent each sub-property of the JSON.402* @type {number}403*/404goog.format.JsonPrettyPrinter.TextDelimiters.prototype.indent = 2;405406407408/**409* A container for the delimiting characters used to display the JSON string410* to an HTML <code><pre></code> or <code><code></code> element.411* It escapes the names and values before they are added to the output.412* Use this class together with goog.format.JsonPrettyPrinter#formatSafeHtml.413* @constructor414* @extends {goog.format.JsonPrettyPrinter.TextDelimiters}415*/416goog.format.JsonPrettyPrinter.SafeHtmlDelimiters = function() {417goog.format.JsonPrettyPrinter.TextDelimiters.call(this);418};419goog.inherits(420goog.format.JsonPrettyPrinter.SafeHtmlDelimiters,421goog.format.JsonPrettyPrinter.TextDelimiters);422423424/** @override */425goog.format.JsonPrettyPrinter.SafeHtmlDelimiters.prototype.formatName =426function(name) {427var classes = goog.getCssName('goog-jsonprettyprinter-propertyname');428return goog.html.SafeHtml.create('span', {'class': classes}, name);429};430431432/** @override */433goog.format.JsonPrettyPrinter.SafeHtmlDelimiters.prototype.formatValue =434function(value, typeOf) {435var classes = this.getValueCssName(typeOf);436return goog.html.SafeHtml.create('span', {'class': classes}, value);437};438439440/**441* Return a class name for the given type.442* @param {string} typeOf The type of the value.443* @return {string}444* @protected445*/446goog.format.JsonPrettyPrinter.SafeHtmlDelimiters.prototype.getValueCssName =447function(typeOf) {448// This switch is needed because goog.getCssName requires a constant string.449switch (typeOf) {450case 'null':451return goog.getCssName('goog-jsonprettyprinter-propertyvalue-null');452case 'boolean':453return goog.getCssName('goog-jsonprettyprinter-propertyvalue-boolean');454case 'number':455return goog.getCssName('goog-jsonprettyprinter-propertyvalue-number');456case 'string':457return goog.getCssName('goog-jsonprettyprinter-propertyvalue-string');458case 'array':459return goog.getCssName('goog-jsonprettyprinter-propertyvalue-array');460case 'object':461return goog.getCssName('goog-jsonprettyprinter-propertyvalue-object');462default:463return goog.getCssName('goog-jsonprettyprinter-propertyvalue-unknown');464}465};466467468