Skip to content

Commit 11c7bdf

Browse files
first commit
0 parents  commit 11c7bdf

File tree

6 files changed

+1951
-0
lines changed

6 files changed

+1951
-0
lines changed

README

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
JSON in JavaScript
2+
3+
4+
Douglas Crockford
5+
douglas@crockford.com
6+
7+
2010-11-18
8+
9+
10+
JSON is a light-weight, language independent, data interchange format.
11+
See http://www.JSON.org/
12+
13+
The files in this collection implement JSON encoders/decoders in JavaScript.
14+
15+
JSON became a built-in feature of JavaScript when the ECMAScript Programming
16+
Language Standard - Fifth Edition was adopted by the ECMA General Assembly
17+
in December 2009. Most of the files in this collection are for applications
18+
that are expected to run in obsolete web browsers. For most purposes, json2.js
19+
is the best choice.
20+
21+
22+
json2.js: This file creates a JSON property in the global object, if there
23+
isn't already one, setting its value to an object containing a stringify
24+
method and a parse method. The parse method uses the eval method to do the
25+
parsing, guarding it with several regular expressions to defend against
26+
accidental code execution hazards. On current browsers, this file does nothing,
27+
prefering the built-in JSON object.
28+
29+
json.js: This file does everything that json2.js does. It also adds a
30+
toJSONString method and a parseJSON method to Object.prototype. Use of this
31+
file is not recommended.
32+
33+
json_parse.js: This file contains an alternative JSON parse function that
34+
uses recursive descent instead of eval.
35+
36+
json_parse_state: This files contains an alternative JSON parse function that
37+
uses a state machine instead of eval.
38+
39+
cycle.js: This file contains two functions, JSON.decycle and JSON.retrocycle,
40+
which make it possible to encode cyclical structures and dags in JSON, and to
41+
then recover them. JSONPath is used to represent the links.
42+
http://GOESSNER.net/articles/JsonPath/

cycle.js

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
// cycle.js
2+
// 2010-11-18
3+
4+
/*jslint forin: true, evil: true */
5+
6+
/*members $ref, apply, call, decycle, hasOwnProperty, length, prototype, push,
7+
retrocycle, stringify, test, toString
8+
*/
9+
10+
if (typeof JSON.decycle !== 'function') {
11+
JSON.decycle = function decycle(object) {
12+
13+
// Make a deep copy of an object or array, assuring that there is at most
14+
// one instance of each object or array in the resulting structure. The
15+
// duplicate references (which might be forming cycles) are replaced with
16+
// an object of the form
17+
// {$ref: PATH}
18+
// where the PATH is a JSONPath string that locates the first occurance.
19+
// So,
20+
// var a = [];
21+
// a[0] = a;
22+
// return JSON.stringify(JSON.decycle(a));
23+
// produces the string '[{"$ref":"$"}]'.
24+
25+
// JSONPath is used to locate the unique object. $ indicates the top level of
26+
// the object or array. [NUMBER] or [STRING] indicates a child member or
27+
// property.
28+
29+
var objects = [], // Keep a reference to each unique object or array
30+
paths = []; // Keep the path to each unique object or array
31+
32+
return (function derez(value, path) {
33+
34+
// The derez recurses through the object, producing the deep copy.
35+
36+
var i, // The loop counter
37+
name, // Property name
38+
nu; // The new object or array
39+
40+
switch (typeof value) {
41+
case 'object':
42+
43+
// typeof null === 'object', so get out if this value is not really an object.
44+
45+
if (!value) {
46+
return null;
47+
}
48+
49+
// If the value is an object or array, look to see if we have already
50+
// encountered it. If so, return a $ref/path object. This is a hard way,
51+
// linear search that will get slower as the number of unique objects grows.
52+
53+
for (i = 0; i < objects.length; i += 1) {
54+
if (objects[i] === value) {
55+
return {$ref: paths[i]};
56+
}
57+
}
58+
59+
// Otherwise, accumulate the unique value and its path.
60+
61+
objects.push(value);
62+
paths.push(path);
63+
64+
// If it is an array, replicate the array.
65+
66+
if (Object.prototype.toString.apply(value) === '[object Array]') {
67+
nu = [];
68+
for (i = 0; i < value.length; i += 1) {
69+
nu[i] = derez(value[i], path + '[' + i + ']');
70+
}
71+
} else {
72+
73+
// If it is an object, replicate the object.
74+
75+
nu = {};
76+
for (name in value) {
77+
if (Object.hasOwnProperty.call(value, name)) {
78+
nu[name] = derez(value[name],
79+
path + '[' + JSON.stringify(name) + ']');
80+
}
81+
}
82+
}
83+
return nu;
84+
case 'number':
85+
case 'string':
86+
case 'boolean':
87+
return value;
88+
}
89+
}(object, '$'));
90+
};
91+
}
92+
93+
94+
if (typeof JSON.retrocycle !== 'function') {
95+
JSON.retrocycle = function retrocycle($) {
96+
97+
// Restore an object that was reduced by decycle. Members whose values are
98+
// objects of the form
99+
// {$ref: PATH}
100+
// are replaced with references to the value found by the PATH. This will
101+
// restore cycles. The object will be mutated.
102+
103+
// The eval function is used to locate the values described by a PATH. The
104+
// root object is kept in a $ variable. A regular expression is used to
105+
// assure that the PATH is extremely well formed. The regexp contains nested
106+
// * quantifiers. That has been known to have extremely bad performance
107+
// problems on some browsers for very long strings. A PATH is expected to be
108+
// reasonably short. A PATH is allowed to belong to a very restricted subset of
109+
// Goessner's JSONPath.
110+
111+
// So,
112+
// var s = '[{"$ref":"$"}]';
113+
// return JSON.retrocycle(JSON.parse(s));
114+
// produces an array containing a single element which is the array itself.
115+
116+
var px =
117+
/^\$(?:\[(?:\d?|\"(?:[^\\\"\u0000-\u001f]|\\([\\\"\/bfnrt]|u[0-9a-zA-Z]{4}))*\")\])*$/;
118+
119+
(function rez(value) {
120+
121+
// The rez function walks recursively through the object looking for $ref
122+
// properties. When it finds one that has a value that is a path, then it
123+
// replaces the $ref object with a reference to the value that is found by
124+
// the path.
125+
126+
var i, item, name, path;
127+
128+
if (value && typeof value === 'object') {
129+
if (Object.prototype.toString.apply(value) === '[object Array]') {
130+
for (i = 0; i < value.length; i += 1) {
131+
item = value[i];
132+
if (item && typeof item === 'object') {
133+
path = item.$ref;
134+
if (typeof path === 'string' && px.test(path)) {
135+
value[i] = eval(path);
136+
} else {
137+
rez(item);
138+
}
139+
}
140+
}
141+
} else {
142+
for (name in value) {
143+
item = value[name];
144+
if (item && typeof item === 'object') {
145+
path = item.$ref;
146+
if (typeof path === 'string' && px.test(path)) {
147+
value[name] = eval(path);
148+
} else {
149+
rez(item);
150+
}
151+
}
152+
}
153+
}
154+
}
155+
}($));
156+
return $;
157+
};
158+
}

0 commit comments

Comments
 (0)