Advertisement
Guest User

json_parse_raw

a guest
Mar 26th, 2012
594
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.     json_parse_raw.js
  3.     2012-03-26
  4.  
  5.     based on json_parse.js
  6.     2011-03-06
  7.  
  8.     Public Domain.
  9.  
  10.     NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
  11.  
  12.     This file creates a json_parse_raw function.
  13.  
  14.         json_parse_raw(text, reviver)
  15.  
  16.             This method parses the first JSON text in a string to
  17.             produce an object or array and the position of the first
  18.             character past the JSON text. If given an empty string or
  19.             an incomplete JSON text, it will return [undefined, 0]. If
  20.             given invalid JSON, it will throw a SyntaxError exception.
  21.  
  22.             The optional reviver parameter is a function that can filter and
  23.             transform the results. It receives each of the keys and values,
  24.             and its return value is used instead of the original value.
  25.             If it returns what it received, then the structure is not modified.
  26.             If it returns undefined then the member is deleted.
  27.  
  28.             Example:
  29.  
  30.             // Parse the text. Values that look like ISO date strings will
  31.             // be converted to Date objects.
  32.  
  33.             myData = json_parse_raw(text, function (key, value) {
  34.                 var a;
  35.                 if (typeof value === 'string') {
  36.                     a =
  37. /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
  38.                     if (a) {
  39.                         return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
  40.                             +a[5], +a[6]));
  41.                     }
  42.                 }
  43.                 return value;
  44.             });
  45.  
  46.     This is a reference implementation. You are free to copy, modify, or
  47.     redistribute.
  48.  
  49.     This code should be minified before deployment.
  50.     See http://javascript.crockford.com/jsmin.html
  51.  
  52.     USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
  53.     NOT CONTROL.
  54. */
  55.  
  56. /*members "", "\"", "\/", "\\", at, b, call, charAt, f, fromCharCode,
  57.     hasOwnProperty, message, n, name, prototype, push, r, t, text
  58. */
  59.  
  60. var json_parse_raw = (function () {
  61.     "use strict";
  62.  
  63. // This is a function that can parse a JSON text, producing a JavaScript
  64. // data structure. It is a simple, recursive descent parser. It does not use
  65. // eval or regular expressions, so it can be used as a model for implementing
  66. // a JSON parser in other languages.
  67.  
  68. // We are defining the function inside of another function to avoid creating
  69. // global variables.
  70.  
  71.     var at,     // The index of the current character
  72.         ch,     // The current character
  73.         escapee = {
  74.             '"':  '"',
  75.             '\\': '\\',
  76.             '/':  '/',
  77.             b:    '\b',
  78.             f:    '\f',
  79.             n:    '\n',
  80.             r:    '\r',
  81.             t:    '\t'
  82.         },
  83.         text,
  84.  
  85.         error = function (m) {
  86.  
  87. // Call error when something is wrong.
  88.  
  89.             throw {
  90.                 name:    'SyntaxError',
  91.                 message: m,
  92.                 at:      at,
  93.                 text:    text
  94.             };
  95.         },
  96.  
  97.         incomplete = function(m) {
  98.             throw {
  99.                 name:    'IncompleteJson',
  100.                 message: m,
  101.                 at:      at,
  102.                 text:    text
  103.             };
  104.     },
  105.  
  106.         next = function (c) {
  107.  
  108. // If a c parameter is provided, verify that it matches the current character.
  109.  
  110.             if (c && c !== ch) {
  111.                 m = ("Expected '" + c + "' instead of '" + ch + "'");
  112.                 if (!ch) incomplete(m);
  113.                 else error(m);
  114.             }
  115.  
  116. // Get the next character. When there are no more characters,
  117. // return the empty string.
  118.  
  119.             ch = text.charAt(at);
  120.             at += 1;
  121.             return ch;
  122.         },
  123.  
  124.         number = function () {
  125.  
  126. // Parse a number value.
  127.  
  128.             var number,
  129.                 string = '';
  130.  
  131.             if (ch === '-') {
  132.                 string = '-';
  133.                 next('-');
  134.             }
  135.             while (ch >= '0' && ch <= '9') {
  136.                 string += ch;
  137.                 next();
  138.             }
  139.             if (ch === '.') {
  140.                 string += '.';
  141.                 while (next() && ch >= '0' && ch <= '9') {
  142.                     string += ch;
  143.                 }
  144.             }
  145.             if (ch === 'e' || ch === 'E') {
  146.                 string += ch;
  147.                 next();
  148.                 if (ch === '-' || ch === '+') {
  149.                     string += ch;
  150.                     next();
  151.                 }
  152.                 while (ch >= '0' && ch <= '9') {
  153.                     string += ch;
  154.                     next();
  155.                 }
  156.             }
  157.             number = +string;
  158.             if (!isFinite(number)) {
  159.                 error("Bad number");
  160.             } else {
  161.                 return number;
  162.             }
  163.         },
  164.  
  165.         string = function () {
  166.  
  167. // Parse a string value.
  168.  
  169.             var hex,
  170.                 i,
  171.                 string = '',
  172.                 uffff;
  173.  
  174. // When parsing for string values, we must look for " and \ characters.
  175.  
  176.             if (ch === '"') {
  177.                 while (next()) {
  178.                     if (ch === '"') {
  179.                         next();
  180.                         return string;
  181.                     } else if (ch === '\\') {
  182.                         next();
  183.                         if (ch === 'u') {
  184.                             uffff = 0;
  185.                             for (i = 0; i < 4; i += 1) {
  186.                                 hex = parseInt(next(), 16);
  187.                                 if (!isFinite(hex)) {
  188.                                     break;
  189.                                 }
  190.                                 uffff = uffff * 16 + hex;
  191.                             }
  192.                             string += String.fromCharCode(uffff);
  193.                         } else if (typeof escapee[ch] === 'string') {
  194.                             string += escapee[ch];
  195.                         } else {
  196.                             break;
  197.                         }
  198.                     } else {
  199.                         string += ch;
  200.                     }
  201.                 }
  202.             }
  203.             if (ch === '') incomplete("Bad string");
  204.             else error("Bad string");
  205.         },
  206.  
  207.         white = function () {
  208.  
  209. // Skip whitespace.
  210.  
  211.             while (ch && ch <= ' ') {
  212.                 next();
  213.             }
  214.         },
  215.  
  216.         word = function () {
  217.  
  218. // true, false, or null.
  219.  
  220.             switch (ch) {
  221.             case 't':
  222.                 next('t');
  223.                 next('r');
  224.                 next('u');
  225.                 next('e');
  226.                 return true;
  227.             case 'f':
  228.                 next('f');
  229.                 next('a');
  230.                 next('l');
  231.                 next('s');
  232.                 next('e');
  233.                 return false;
  234.             case 'n':
  235.                 next('n');
  236.                 next('u');
  237.                 next('l');
  238.                 next('l');
  239.                 return null;
  240.             }
  241.             error("Unexpected '" + ch + "'");
  242.         },
  243.  
  244.         value,  // Place holder for the value function.
  245.  
  246.         array = function () {
  247.  
  248. // Parse an array value.
  249.  
  250.             var array = [];
  251.  
  252.             if (ch === '[') {
  253.                 next('[');
  254.                 white();
  255.                 if (ch === ']') {
  256.                     next(']');
  257.                     return array;   // empty array
  258.                 }
  259.                 while (ch) {
  260.                     array.push(value());
  261.                     white();
  262.                     if (ch === ']') {
  263.                         next(']');
  264.                         return array;
  265.                     }
  266.                     next(',');
  267.                     white();
  268.                 }
  269.             }
  270.             if (ch === '') incomplete("Bad array");
  271.             else error("Bad array");
  272.         },
  273.  
  274.         object = function () {
  275.  
  276. // Parse an object value.
  277.  
  278.             var key,
  279.                 object = {};
  280.  
  281.             if (ch === '{') {
  282.                 next('{');
  283.                 white();
  284.                 if (ch === '}') {
  285.                     next('}');
  286.                     return object;   // empty object
  287.                 }
  288.                 while (ch) {
  289.                     key = string();
  290.                     white();
  291.                     next(':');
  292.                     if (Object.hasOwnProperty.call(object, key)) {
  293.                         error('Duplicate key "' + key + '"');
  294.                     }
  295.                     object[key] = value();
  296.                     white();
  297.                     if (ch === '}') {
  298.                         next('}');
  299.                         return object;
  300.                     }
  301.                     next(',');
  302.                     white();
  303.                 }
  304.             }
  305.             if (ch === '') incomplete("Bad object");
  306.             else error("Bad object");
  307.         };
  308.  
  309.     value = function () {
  310.  
  311. // Parse a JSON value. It could be an object, an array, a string, a number,
  312. // or a word.
  313.  
  314.         white();
  315.         switch (ch) {
  316.         case '{':
  317.             return object();
  318.         case '[':
  319.             return array();
  320.         case '"':
  321.             return string();
  322.         case '-':
  323.             return number();
  324.         default:
  325.             return ch >= '0' && ch <= '9' ? number() : word();
  326.         }
  327.     };
  328.  
  329. // Return the json_parse function. It will have access to all of the above
  330. // functions and variables.
  331.  
  332.     var try_parse = function (source, reviver) {
  333.         var result;
  334.  
  335.         text = source;
  336.         at = 0;
  337.         ch = ' ';
  338.         result = value();
  339.         white();
  340.         //if (ch) {
  341.         //    error("Syntax error");
  342.         //}
  343.  
  344. // If there is a reviver function, we recursively walk the new structure,
  345. // passing each name/value pair to the reviver function for possible
  346. // transformation, starting with a temporary root object that holds the result
  347. // in an empty key. If there is not a reviver function, we simply return the
  348. // result.
  349.  
  350.         return typeof reviver === 'function' ? (function walk(holder, key) {
  351.             var k, v, value = holder[key];
  352.             if (value && typeof value === 'object') {
  353.                 for (k in value) {
  354.                     if (Object.prototype.hasOwnProperty.call(value, k)) {
  355.                         v = walk(value, k);
  356.                         if (v !== undefined) {
  357.                             value[k] = v;
  358.                         } else {
  359.                             delete value[k];
  360.                         }
  361.                     }
  362.                 }
  363.             }
  364.             return [reviver.call(holder, key, value), at-1];
  365.         }({'': result}, '')) : [result, at-1];
  366.     };
  367.  
  368.     return function(source, reviver) {
  369.         if (source === '') return [undefined, 0];
  370.         try {
  371.             return try_parse(source, reviver);
  372.         } catch (e) {
  373.             if (e.name === "IncompleteJson") return [undefined, 0];
  374.             else throw e;
  375.     }
  376.     };
  377. }());
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement