git-svn-id: http://svn.openlayers.org/tags/openlayers/release-2.5-rc1@4347 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
377 lines
12 KiB
JavaScript
377 lines
12 KiB
JavaScript
/* Copyright (c) 2006-2007 MetaCarta, Inc., published under the BSD license.
|
|
* See http://svn.openlayers.org/trunk/openlayers/release-license.txt
|
|
* for the full text of the license. */
|
|
|
|
/**
|
|
* Note:
|
|
* This work draws heavily from the public domain JSON serializer/deserializer
|
|
* at http://www.json.org/json.js. Rewritten so that it doesn't modify
|
|
* basic data prototypes.
|
|
*/
|
|
|
|
/**
|
|
* @requires OpenLayers/Format.js
|
|
*
|
|
* Class: OpenLayers.Format.JSON
|
|
* A parser to read/write JSON safely. Create a new instance with the
|
|
* <OpenLayers.Format.JSON> constructor.
|
|
*
|
|
* Inherits from:
|
|
* - <OpenLayers.Format>
|
|
*/
|
|
OpenLayers.Format.JSON = OpenLayers.Class(OpenLayers.Format, {
|
|
|
|
/**
|
|
* APIProperty: indent
|
|
* {String} For "pretty" printing, the indent string will be used once for
|
|
* each indentation level.
|
|
*/
|
|
indent: " ",
|
|
|
|
/**
|
|
* APIProperty: space
|
|
* {String} For "pretty" printing, the space string will be used after
|
|
* the ":" separating a name/value pair.
|
|
*/
|
|
space: " ",
|
|
|
|
/**
|
|
* APIProperty: newline
|
|
* {String} For "pretty" printing, the newline string will be used at the
|
|
* end of each name/value pair or array item.
|
|
*/
|
|
newline: "\n",
|
|
|
|
/**
|
|
* Property: level
|
|
* {Integer} For "pretty" printing, this is incremented/decremented during
|
|
* serialization.
|
|
*/
|
|
level: 0,
|
|
|
|
/**
|
|
* Property: pretty
|
|
* {Boolean} Serialize with extra whitespace for structure. This is set
|
|
* by the <write> method.
|
|
*/
|
|
pretty: false,
|
|
|
|
/**
|
|
* Constructor: OpenLayers.Format.JSON
|
|
* Create a new parser for JSON.
|
|
*
|
|
* Parameters:
|
|
* options - {Object} An optional object whose properties will be set on
|
|
* this instance.
|
|
*/
|
|
initialize: function(options) {
|
|
OpenLayers.Format.prototype.initialize.apply(this, [options]);
|
|
},
|
|
|
|
/**
|
|
* APIMethod: read
|
|
* Deserialize a json string.
|
|
*
|
|
* Parameters:
|
|
* json - {String} A JSON string
|
|
* filter - {Function} A function which will be called for every key and
|
|
* value at every level of the final result. Each value will be
|
|
* replaced by the result of the filter function. This can be used to
|
|
* reform generic objects into instances of classes, or to transform
|
|
* date strings into Date objects.
|
|
*
|
|
* Returns:
|
|
* {Object} An object, array, string, or number .
|
|
*/
|
|
read: function(json, filter) {
|
|
/**
|
|
* Parsing happens in three stages. In the first stage, we run the text
|
|
* against a regular expression which looks for non-JSON
|
|
* characters. We are especially concerned with '()' and 'new'
|
|
* because they can cause invocation, and '=' because it can cause
|
|
* mutation. But just to be safe, we will reject all unexpected
|
|
* characters.
|
|
*/
|
|
try {
|
|
if(/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.
|
|
test(json)) {
|
|
|
|
/**
|
|
* In the second stage we use the eval function to compile the
|
|
* text into a JavaScript structure. The '{' operator is
|
|
* subject to a syntactic ambiguity in JavaScript - it can
|
|
* begin a block or an object literal. We wrap the text in
|
|
* parens to eliminate the ambiguity.
|
|
*/
|
|
var object = eval('(' + json + ')');
|
|
|
|
/**
|
|
* In the optional third stage, we recursively walk the new
|
|
* structure, passing each name/value pair to a filter
|
|
* function for possible transformation.
|
|
*/
|
|
if(typeof filter === 'function') {
|
|
function walk(k, v) {
|
|
if(v && typeof v === 'object') {
|
|
for(var i in v) {
|
|
if(v.hasOwnProperty(i)) {
|
|
v[i] = walk(i, v[i]);
|
|
}
|
|
}
|
|
}
|
|
return filter(k, v);
|
|
}
|
|
object = walk('', object);
|
|
}
|
|
return object;
|
|
}
|
|
} catch(e) {
|
|
// Fall through if the regexp test fails.
|
|
}
|
|
return null;
|
|
},
|
|
|
|
/**
|
|
* APIMethod: write
|
|
* Serialize an object into a JSON string.
|
|
*
|
|
* Parameters:
|
|
* value - {String} The object, array, string, number, boolean or date
|
|
* to be serialized.
|
|
* pretty - {Boolean} Structure the output with newlines and indentation.
|
|
* Default is false.
|
|
*
|
|
* Returns:
|
|
* {String} The JSON string representation of the input value.
|
|
*/
|
|
write: function(value, pretty) {
|
|
this.pretty = !!pretty;
|
|
var json = null;
|
|
var type = typeof value;
|
|
if(this.serialize[type]) {
|
|
json = this.serialize[type].apply(this, [value]);
|
|
}
|
|
return json;
|
|
},
|
|
|
|
/**
|
|
* Method: writeIndent
|
|
* Output an indentation string depending on the indentation level.
|
|
*
|
|
* Returns:
|
|
* {String} An appropriate indentation string.
|
|
*/
|
|
writeIndent: function() {
|
|
var pieces = [];
|
|
if(this.pretty) {
|
|
for(var i=0; i<this.level; ++i) {
|
|
pieces.push(this.indent);
|
|
}
|
|
}
|
|
return pieces.join('');
|
|
},
|
|
|
|
/**
|
|
* Method: writeNewline
|
|
* Output a string representing a newline if in pretty printing mode.
|
|
*
|
|
* Returns:
|
|
* {String} A string representing a new line.
|
|
*/
|
|
writeNewline: function() {
|
|
return (this.pretty) ? this.newline : '';
|
|
},
|
|
|
|
/**
|
|
* Method: writeSpace
|
|
* Output a string representing a space if in pretty printing mode.
|
|
*
|
|
* Returns:
|
|
* {String} A space.
|
|
*/
|
|
writeSpace: function() {
|
|
return (this.pretty) ? this.space : '';
|
|
},
|
|
|
|
/**
|
|
* Property: serialize
|
|
* Object with properties corresponding to the serializable data types.
|
|
* Property values are functions that do the actual serializing.
|
|
*/
|
|
serialize: {
|
|
/**
|
|
* Method: serialize.object
|
|
* Transform an object into a JSON string.
|
|
*
|
|
* Parameters:
|
|
* object - {Object} The object to be serialized.
|
|
*
|
|
* Returns:
|
|
* {String} A JSON string representing the object.
|
|
*/
|
|
'object': function(object) {
|
|
// three special objects that we want to treat differently
|
|
if(object == null) {
|
|
return "null";
|
|
}
|
|
if(object.constructor == Date) {
|
|
return this.serialize.date.apply(this, [object]);
|
|
}
|
|
if(object.constructor == Array) {
|
|
return this.serialize.array.apply(this, [object]);
|
|
}
|
|
var pieces = ['{'];
|
|
this.level += 1;
|
|
var key, keyJSON, valueJSON;
|
|
|
|
var addComma = false;
|
|
for(key in object) {
|
|
if(object.hasOwnProperty(key)) {
|
|
// recursive calls need to allow for sub-classing
|
|
keyJSON = OpenLayers.Format.JSON.prototype.write.apply(this,
|
|
[key, this.pretty]);
|
|
valueJSON = OpenLayers.Format.JSON.prototype.write.apply(this,
|
|
[object[key], this.pretty]);
|
|
if(keyJSON != null && valueJSON != null) {
|
|
if(addComma) {
|
|
pieces.push(',');
|
|
}
|
|
pieces.push(this.writeNewline(), this.writeIndent(),
|
|
keyJSON, ':', this.writeSpace(), valueJSON);
|
|
addComma = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
this.level -= 1;
|
|
pieces.push(this.writeNewline(), this.writeIndent(), '}');
|
|
return pieces.join('');
|
|
},
|
|
|
|
/**
|
|
* Method: serialize.array
|
|
* Transform an array into a JSON string.
|
|
*
|
|
* Parameters:
|
|
* array - {Array} The array to be serialized
|
|
*
|
|
* Returns:
|
|
* {String} A JSON string representing the array.
|
|
*/
|
|
'array': function(array) {
|
|
var json;
|
|
var pieces = ['['];
|
|
this.level += 1;
|
|
|
|
for(var i=0; i<array.length; ++i) {
|
|
// recursive calls need to allow for sub-classing
|
|
json = OpenLayers.Format.JSON.prototype.write.apply(this,
|
|
[array[i], this.pretty]);
|
|
if(json != null) {
|
|
if(i > 0) {
|
|
pieces.push(',');
|
|
}
|
|
pieces.push(this.writeNewline(), this.writeIndent(), json);
|
|
}
|
|
}
|
|
|
|
this.level -= 1;
|
|
pieces.push(this.writeNewline(), this.writeIndent(), ']');
|
|
return pieces.join('');
|
|
},
|
|
|
|
/**
|
|
* Method: serialize.string
|
|
* Transform a string into a JSON string.
|
|
*
|
|
* Parameters
|
|
* string - {String} The string to be serialized
|
|
*
|
|
* Returns:
|
|
* {String} A JSON string representing the string.
|
|
*/
|
|
'string': function(string) {
|
|
// If the string contains no control characters, no quote characters, and no
|
|
// backslash characters, then we can simply slap some quotes around it.
|
|
// Otherwise we must also replace the offending characters with safe
|
|
// sequences.
|
|
var m = {
|
|
'\b': '\\b',
|
|
'\t': '\\t',
|
|
'\n': '\\n',
|
|
'\f': '\\f',
|
|
'\r': '\\r',
|
|
'"' : '\\"',
|
|
'\\': '\\\\'
|
|
};
|
|
if(/["\\\x00-\x1f]/.test(string)) {
|
|
return '"' + string.replace(/([\x00-\x1f\\"])/g, function(a, b) {
|
|
var c = m[b];
|
|
if(c) {
|
|
return c;
|
|
}
|
|
c = b.charCodeAt();
|
|
return '\\u00' +
|
|
Math.floor(c / 16).toString(16) +
|
|
(c % 16).toString(16);
|
|
}) + '"';
|
|
}
|
|
return '"' + string + '"';
|
|
},
|
|
|
|
/**
|
|
* Method: serialize.number
|
|
* Transform a number into a JSON string.
|
|
*
|
|
* Parameters:
|
|
* number - {Number} The number to be serialized.
|
|
*
|
|
* Returns:
|
|
* {String} A JSON string representing the number.
|
|
*/
|
|
'number': function(number) {
|
|
return isFinite(number) ? String(number) : "null";
|
|
},
|
|
|
|
/**
|
|
* Method: serialize.boolean
|
|
* Transform a boolean into a JSON string.
|
|
*
|
|
* Parameters:
|
|
* bool - {Boolean} The boolean to be serialized.
|
|
*
|
|
* Returns:
|
|
* {String} A JSON string representing the boolean.
|
|
*/
|
|
'boolean': function(bool) {
|
|
return String(bool);
|
|
},
|
|
|
|
/**
|
|
* Method: serialize.object
|
|
* Transform a date into a JSON string.
|
|
*
|
|
* Parameters:
|
|
* date - {Date} The date to be serialized.
|
|
*
|
|
* Returns:
|
|
* {String} A JSON string representing the date.
|
|
*/
|
|
'date': function(date) {
|
|
function format(number) {
|
|
// Format integers to have at least two digits.
|
|
return (number < 10) ? '0' + number : number;
|
|
}
|
|
return '"' + date.getFullYear() + '-' +
|
|
format(date.getMonth() + 1) + '-' +
|
|
format(date.getDate()) + 'T' +
|
|
format(date.getHours()) + ':' +
|
|
format(date.getMinutes()) + ':' +
|
|
format(date.getSeconds()) + '"';
|
|
}
|
|
},
|
|
|
|
CLASS_NAME: "OpenLayers.Format.JSON"
|
|
|
|
});
|