OLD | NEW |
(Empty) | |
| 1 /* |
| 2 json2.js |
| 3 2008-02-14 |
| 4 |
| 5 Public Domain |
| 6 |
| 7 No warranty expressed or implied. Use at your own risk. |
| 8 |
| 9 See http://www.JSON.org/js.html |
| 10 |
| 11 This file creates a global JSON object containing two methods: |
| 12 |
| 13 JSON.stringify(value, whitelist) |
| 14 value any JavaScript value, usually an object or array. |
| 15 |
| 16 whitelist an optional array parameter that determines how object |
| 17 values are stringified. |
| 18 |
| 19 This method produces a JSON text from a JavaScript value. |
| 20 There are three possible ways to stringify an object, depending |
| 21 on the optional whitelist parameter. |
| 22 |
| 23 If an object has a toJSON method, then the toJSON() method will be |
| 24 called. The value returned from the toJSON method will be |
| 25 stringified. |
| 26 |
| 27 Otherwise, if the optional whitelist parameter is an array, then |
| 28 the elements of the array will be used to select members of the |
| 29 object for stringification. |
| 30 |
| 31 Otherwise, if there is no whitelist parameter, then all of the |
| 32 members of the object will be stringified. |
| 33 |
| 34 Values that do not have JSON representaions, such as undefined or |
| 35 functions, will not be serialized. Such values in objects will be |
| 36 dropped; in arrays will be replaced with null. |
| 37 JSON.stringify(undefined) returns undefined. Dates will be |
| 38 stringified as quoted ISO dates. |
| 39 |
| 40 Example: |
| 41 |
| 42 var text = JSON.stringify(['e', {pluribus: 'unum'}]); |
| 43 // text is '["e",{"pluribus":"unum"}]' |
| 44 |
| 45 JSON.parse(text, filter) |
| 46 This method parses a JSON text to produce an object or |
| 47 array. It can throw a SyntaxError exception. |
| 48 |
| 49 The optional filter parameter is a function that can filter and |
| 50 transform the results. It receives each of the keys and values, and |
| 51 its return value is used instead of the original value. If it |
| 52 returns what it received, then structure is not modified. If it |
| 53 returns undefined then the member is deleted. |
| 54 |
| 55 Example: |
| 56 |
| 57 // Parse the text. If a key contains the string 'date' then |
| 58 // convert the value to a date. |
| 59 |
| 60 myData = JSON.parse(text, function (key, value) { |
| 61 return key.indexOf('date') >= 0 ? new Date(value) : value; |
| 62 }); |
| 63 |
| 64 This is a reference implementation. You are free to copy, modify, or |
| 65 redistribute. |
| 66 |
| 67 Use your own copy. It is extremely unwise to load third party |
| 68 code into your pages. |
| 69 */ |
| 70 |
| 71 /*jslint evil: true */ |
| 72 |
| 73 /*global JSON */ |
| 74 |
| 75 /*members "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, |
| 76 charCodeAt, floor, getUTCDate, getUTCFullYear, getUTCHours, |
| 77 getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, length, |
| 78 parse, propertyIsEnumerable, prototype, push, replace, stringify, test, |
| 79 toJSON, toString |
| 80 */ |
| 81 |
| 82 if (!this.JSON) { |
| 83 |
| 84 JSON = function () { |
| 85 |
| 86 function f(n) { // Format integers to have at least two digits. |
| 87 return n < 10 ? '0' + n : n; |
| 88 } |
| 89 |
| 90 Date.prototype.toJSON = function () { |
| 91 |
| 92 // Eventually, this method will be based on the date.toISOString method. |
| 93 |
| 94 return this.getUTCFullYear() + '-' + |
| 95 f(this.getUTCMonth() + 1) + '-' + |
| 96 f(this.getUTCDate()) + 'T' + |
| 97 f(this.getUTCHours()) + ':' + |
| 98 f(this.getUTCMinutes()) + ':' + |
| 99 f(this.getUTCSeconds()) + 'Z'; |
| 100 }; |
| 101 |
| 102 |
| 103 var m = { // table of character substitutions |
| 104 '\b': '\\b', |
| 105 '\t': '\\t', |
| 106 '\n': '\\n', |
| 107 '\f': '\\f', |
| 108 '\r': '\\r', |
| 109 '"' : '\\"', |
| 110 '\\': '\\\\' |
| 111 }; |
| 112 |
| 113 function stringify(value, whitelist) { |
| 114 var a, // The array holding the partial texts. |
| 115 i, // The loop counter. |
| 116 k, // The member key. |
| 117 l, // Length. |
| 118 r = /["\\\x00-\x1f\x7f-\x9f]/g, |
| 119 v; // The member value. |
| 120 |
| 121 switch (typeof value) { |
| 122 case 'string': |
| 123 |
| 124 // If the string contains no control characters, no quote characters, and no |
| 125 // backslash characters, then we can safely slap some quotes around it. |
| 126 // Otherwise we must also replace the offending characters with safe sequences. |
| 127 |
| 128 return r.test(value) ? |
| 129 '"' + value.replace(r, function (a) { |
| 130 var c = m[a]; |
| 131 if (c) { |
| 132 return c; |
| 133 } |
| 134 c = a.charCodeAt(); |
| 135 return '\\u00' + Math.floor(c / 16).toString(16) + |
| 136 (c % 16).toString(16); |
| 137 }) + '"' : |
| 138 '"' + value + '"'; |
| 139 |
| 140 case 'number': |
| 141 |
| 142 // JSON numbers must be finite. Encode non-finite numbers as null. |
| 143 |
| 144 return isFinite(value) ? String(value) : 'null'; |
| 145 |
| 146 case 'boolean': |
| 147 case 'null': |
| 148 return String(value); |
| 149 |
| 150 case 'object': |
| 151 |
| 152 // Due to a specification blunder in ECMAScript, |
| 153 // typeof null is 'object', so watch out for that case. |
| 154 |
| 155 if (!value) { |
| 156 return 'null'; |
| 157 } |
| 158 |
| 159 // If the object has a toJSON method, call it, and stringify the result. |
| 160 |
| 161 if (typeof value.toJSON === 'function') { |
| 162 return stringify(value.toJSON()); |
| 163 } |
| 164 a = []; |
| 165 if (typeof value.length === 'number' && |
| 166 !(value.propertyIsEnumerable('length'))) { |
| 167 |
| 168 // The object is an array. Stringify every element. Use null as a placeholder |
| 169 // for non-JSON values. |
| 170 |
| 171 l = value.length; |
| 172 for (i = 0; i < l; i += 1) { |
| 173 a.push(stringify(value[i], whitelist) || 'null'); |
| 174 } |
| 175 |
| 176 // Join all of the elements together and wrap them in brackets. |
| 177 |
| 178 return '[' + a.join(',') + ']'; |
| 179 } |
| 180 if (whitelist) { |
| 181 |
| 182 // If a whitelist (array of keys) is provided, use it to select the components |
| 183 // of the object. |
| 184 |
| 185 l = whitelist.length; |
| 186 for (i = 0; i < l; i += 1) { |
| 187 k = whitelist[i]; |
| 188 if (typeof k === 'string') { |
| 189 v = stringify(value[k], whitelist); |
| 190 if (v) { |
| 191 a.push(stringify(k) + ':' + v); |
| 192 } |
| 193 } |
| 194 } |
| 195 } else { |
| 196 |
| 197 // Otherwise, iterate through all of the keys in the object. |
| 198 |
| 199 for (k in value) { |
| 200 if (typeof k === 'string') { |
| 201 v = stringify(value[k], whitelist); |
| 202 if (v) { |
| 203 a.push(stringify(k) + ':' + v); |
| 204 } |
| 205 } |
| 206 } |
| 207 } |
| 208 |
| 209 // Join all of the member texts together and wrap them in braces. |
| 210 |
| 211 return '{' + a.join(',') + '}'; |
| 212 } |
| 213 } |
| 214 |
| 215 return { |
| 216 stringify: stringify, |
| 217 parse: function (text, filter) { |
| 218 var j; |
| 219 |
| 220 function walk(k, v) { |
| 221 var i, n; |
| 222 if (v && typeof v === 'object') { |
| 223 for (i in v) { |
| 224 if (Object.prototype.hasOwnProperty.apply(v, [i])) { |
| 225 n = walk(i, v[i]); |
| 226 if (n !== undefined) { |
| 227 v[i] = n; |
| 228 } else { |
| 229 delete v[i]; |
| 230 } |
| 231 } |
| 232 } |
| 233 } |
| 234 return filter(k, v); |
| 235 } |
| 236 |
| 237 |
| 238 // Parsing happens in three stages. In the first stage, we run the text against |
| 239 // regular expressions that look for non-JSON patterns. We are especially |
| 240 // concerned with '()' and 'new' because they can cause invocation, and '=' |
| 241 // because it can cause mutation. But just to be safe, we want to reject all |
| 242 // unexpected forms. |
| 243 |
| 244 // We split the first stage into 4 regexp operations in order to work around |
| 245 // crippling inefficiencies in IE's and Safari's regexp engines. First we |
| 246 // replace all backslash pairs with '@' (a non-JSON character). Second, we |
| 247 // replace all simple value tokens with ']' characters. Third, we delete all |
| 248 // open brackets that follow a colon or comma or that begin the text. Finally, |
| 249 // we look to see that the remaining characters are only whitespace or ']' or |
| 250 // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. |
| 251 |
| 252 if (/^[\],:{}\s]*$/.test(text.replace(/\\./g, '@'). |
| 253 replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
. |
| 254 replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { |
| 255 |
| 256 // In the second stage we use the eval function to compile the text into a |
| 257 // JavaScript structure. The '{' operator is subject to a syntactic ambiguity |
| 258 // in JavaScript: it can begin a block or an object literal. We wrap the text |
| 259 // in parens to eliminate the ambiguity. |
| 260 |
| 261 j = eval('(' + text + ')'); |
| 262 |
| 263 // In the optional third stage, we recursively walk the new structure, passing |
| 264 // each name/value pair to a filter function for possible transformation. |
| 265 |
| 266 return typeof filter === 'function' ? walk('', j) : j; |
| 267 } |
| 268 |
| 269 // If the text is not JSON parseable, then a SyntaxError is thrown. |
| 270 |
| 271 throw new SyntaxError('parseJSON'); |
| 272 } |
| 273 }; |
| 274 }(); |
| 275 } |
OLD | NEW |