diff --git a/core/src/processing/data/JSONArray.java b/core/src/processing/data/JSONArray.java
index 8f9c17ce82..9c6a48a5b6 100644
--- a/core/src/processing/data/JSONArray.java
+++ b/core/src/processing/data/JSONArray.java
@@ -107,7 +107,7 @@ public JSONArray() {
* @param x A JSONTokener
* @throws JSONException If there is a syntax error.
*/
- private JSONArray(JSONTokener x) {
+ /*private*/protected JSONArray(JSONTokener x) {
this();
if (x.nextClean() != '[') {
throw new RuntimeException("A JSONArray text must start with '['");
diff --git a/core/src/processing/data/JSONObject.java b/core/src/processing/data/JSONObject.java
index 4f9980b085..5dbf4abcf4 100644
--- a/core/src/processing/data/JSONObject.java
+++ b/core/src/processing/data/JSONObject.java
@@ -1120,12 +1120,12 @@ public JSONObject setBoolean(String key, boolean value) {
}
- public JSONObject setJSONObject(String key, String value) {
+ public JSONObject setJSONObject(String key, JSONObject/*String*/ value) {
return put(key, value);
}
- public JSONObject setJSONArray(String key, String value) {
+ public JSONObject setJSONArray(String key, JSONArray/*String*/ value) {
return put(key, value);
}
@@ -1715,379 +1715,379 @@ protected Writer write(Writer writer, int indentFactor, int indent) {
// }
- static class JSONTokener {
- private long character;
- private boolean eof;
- private long index;
- private long line;
- private char previous;
- private Reader reader;
- private boolean usePrevious;
-
-
- /**
- * Construct a JSONTokener from a Reader.
- *
- * @param reader A reader.
- */
- public JSONTokener(Reader reader) {
- this.reader = reader.markSupported()
- ? reader
- : new BufferedReader(reader);
- this.eof = false;
- this.usePrevious = false;
- this.previous = 0;
- this.index = 0;
- this.character = 1;
- this.line = 1;
- }
-
-
- /**
- * Construct a JSONTokener from an InputStream.
- */
- public JSONTokener(InputStream inputStream) {
- this(new InputStreamReader(inputStream));
- }
-
-
- /**
- * Construct a JSONTokener from a string.
- *
- * @param s A source string.
- */
- public JSONTokener(String s) {
- this(new StringReader(s));
- }
-
-
- /**
- * Back up one character. This provides a sort of lookahead capability,
- * so that you can test for a digit or letter before attempting to parse
- * the next number or identifier.
- */
- public void back() {
- if (this.usePrevious || this.index <= 0) {
- throw new RuntimeException("Stepping back two steps is not supported");
- }
- this.index -= 1;
- this.character -= 1;
- this.usePrevious = true;
- this.eof = false;
- }
-
-
- public boolean end() {
- return this.eof && !this.usePrevious;
- }
-
-
- /**
- * Determine if the source string still contains characters that next()
- * can consume.
- * @return true if not yet at the end of the source.
- */
- public boolean more() {
- this.next();
- if (this.end()) {
- return false;
- }
- this.back();
- return true;
- }
-
-
- /**
- * Get the next character in the source string.
- *
- * @return The next character, or 0 if past the end of the source string.
- */
- public char next() {
- int c;
- if (this.usePrevious) {
- this.usePrevious = false;
- c = this.previous;
- } else {
- try {
- c = this.reader.read();
- } catch (IOException exception) {
- throw new RuntimeException(exception);
- }
-
- if (c <= 0) { // End of stream
- this.eof = true;
- c = 0;
- }
- }
- this.index += 1;
- if (this.previous == '\r') {
- this.line += 1;
- this.character = c == '\n' ? 0 : 1;
- } else if (c == '\n') {
- this.line += 1;
- this.character = 0;
- } else {
- this.character += 1;
- }
- this.previous = (char) c;
- return this.previous;
- }
-
-
- /**
- * Consume the next character, and check that it matches a specified
- * character.
- * @param c The character to match.
- * @return The character.
- * @throws JSONException if the character does not match.
- */
- public char next(char c) {
- char n = this.next();
- if (n != c) {
- throw new RuntimeException("Expected '" + c + "' and instead saw '" + n + "'");
- }
- return n;
- }
-
-
- /**
- * Get the next n characters.
- *
- * @param n The number of characters to take.
- * @return A string of n characters.
- * @throws JSONException
- * Substring bounds error if there are not
- * n characters remaining in the source string.
- */
- public String next(int n) {
- if (n == 0) {
- return "";
- }
-
- char[] chars = new char[n];
- int pos = 0;
-
- while (pos < n) {
- chars[pos] = this.next();
- if (this.end()) {
- throw new RuntimeException("Substring bounds error");
- }
- pos += 1;
- }
- return new String(chars);
- }
-
-
- /**
- * Get the next char in the string, skipping whitespace.
- * @throws JSONException
- * @return A character, or 0 if there are no more characters.
- */
- public char nextClean() {
- for (;;) {
- char c = this.next();
- if (c == 0 || c > ' ') {
- return c;
- }
- }
- }
-
-
- /**
- * Return the characters up to the next close quote character.
- * Backslash processing is done. The formal JSON format does not
- * allow strings in single quotes, but an implementation is allowed to
- * accept them.
- * @param quote The quoting character, either
- * " (double quote) or
- * ' (single quote).
- * @return A String.
- * @throws JSONException Unterminated string.
- */
- public String nextString(char quote) {
- char c;
- StringBuffer sb = new StringBuffer();
- for (;;) {
- c = this.next();
- switch (c) {
- case 0:
- case '\n':
- case '\r':
- throw new RuntimeException("Unterminated string");
- case '\\':
- c = this.next();
- switch (c) {
- case 'b':
- sb.append('\b');
- break;
- case 't':
- sb.append('\t');
- break;
- case 'n':
- sb.append('\n');
- break;
- case 'f':
- sb.append('\f');
- break;
- case 'r':
- sb.append('\r');
- break;
- case 'u':
- sb.append((char)Integer.parseInt(this.next(4), 16));
- break;
- case '"':
- case '\'':
- case '\\':
- case '/':
- sb.append(c);
- break;
- default:
- throw new RuntimeException("Illegal escape.");
- }
- break;
- default:
- if (c == quote) {
- return sb.toString();
- }
- sb.append(c);
- }
- }
- }
-
-
- /**
- * Get the text up but not including the specified character or the
- * end of line, whichever comes first.
- * @param delimiter A delimiter character.
- * @return A string.
- */
- public String nextTo(char delimiter) {
- StringBuffer sb = new StringBuffer();
- for (;;) {
- char c = this.next();
- if (c == delimiter || c == 0 || c == '\n' || c == '\r') {
- if (c != 0) {
- this.back();
- }
- return sb.toString().trim();
- }
- sb.append(c);
- }
- }
-
-
- /**
- * Get the text up but not including one of the specified delimiter
- * characters or the end of line, whichever comes first.
- * @param delimiters A set of delimiter characters.
- * @return A string, trimmed.
- */
- public String nextTo(String delimiters) {
- char c;
- StringBuffer sb = new StringBuffer();
- for (;;) {
- c = this.next();
- if (delimiters.indexOf(c) >= 0 || c == 0 ||
- c == '\n' || c == '\r') {
- if (c != 0) {
- this.back();
- }
- return sb.toString().trim();
- }
- sb.append(c);
- }
- }
-
-
- /**
- * Get the next value. The value can be a Boolean, Double, Integer,
- * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
- * @throws JSONException If syntax error.
- *
- * @return An object.
- */
- public Object nextValue() {
- char c = this.nextClean();
- String string;
-
- switch (c) {
- case '"':
- case '\'':
- return this.nextString(c);
- case '{':
- this.back();
- return new JSONObject(this);
- case '[':
- this.back();
- return new JSONArray(this);
- }
-
- /*
- * Handle unquoted text. This could be the values true, false, or
- * null, or it can be a number. An implementation (such as this one)
- * is allowed to also accept non-standard forms.
- *
- * Accumulate characters until we reach the end of the text or a
- * formatting character.
- */
-
- StringBuffer sb = new StringBuffer();
- while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
- sb.append(c);
- c = this.next();
- }
- this.back();
-
- string = sb.toString().trim();
- if ("".equals(string)) {
- throw new RuntimeException("Missing value");
- }
- return JSONObject.stringToValue(string);
- }
-
-
- /**
- * Skip characters until the next character is the requested character.
- * If the requested character is not found, no characters are skipped.
- * @param to A character to skip to.
- * @return The requested character, or zero if the requested character
- * is not found.
- */
- public char skipTo(char to) {
- char c;
- try {
- long startIndex = this.index;
- long startCharacter = this.character;
- long startLine = this.line;
- this.reader.mark(1000000);
- do {
- c = this.next();
- if (c == 0) {
- this.reader.reset();
- this.index = startIndex;
- this.character = startCharacter;
- this.line = startLine;
- return c;
- }
- } while (c != to);
- } catch (IOException exc) {
- throw new RuntimeException(exc);
- }
-
- this.back();
- return c;
- }
-
-
- /**
- * Make a printable string of this JSONTokener.
- *
- * @return " at {index} [character {character} line {line}]"
- */
- @Override
- public String toString() {
- return " at " + this.index + " [character " + this.character + " line " +
- this.line + "]";
- }
- }
+// static class JSONTokener {
+// private long character;
+// private boolean eof;
+// private long index;
+// private long line;
+// private char previous;
+// private Reader reader;
+// private boolean usePrevious;
+//
+//
+// /**
+// * Construct a JSONTokener from a Reader.
+// *
+// * @param reader A reader.
+// */
+// public JSONTokener(Reader reader) {
+// this.reader = reader.markSupported()
+// ? reader
+// : new BufferedReader(reader);
+// this.eof = false;
+// this.usePrevious = false;
+// this.previous = 0;
+// this.index = 0;
+// this.character = 1;
+// this.line = 1;
+// }
+//
+//
+// /**
+// * Construct a JSONTokener from an InputStream.
+// */
+// public JSONTokener(InputStream inputStream) {
+// this(new InputStreamReader(inputStream));
+// }
+//
+//
+// /**
+// * Construct a JSONTokener from a string.
+// *
+// * @param s A source string.
+// */
+// public JSONTokener(String s) {
+// this(new StringReader(s));
+// }
+//
+//
+// /**
+// * Back up one character. This provides a sort of lookahead capability,
+// * so that you can test for a digit or letter before attempting to parse
+// * the next number or identifier.
+// */
+// public void back() {
+// if (this.usePrevious || this.index <= 0) {
+// throw new RuntimeException("Stepping back two steps is not supported");
+// }
+// this.index -= 1;
+// this.character -= 1;
+// this.usePrevious = true;
+// this.eof = false;
+// }
+//
+//
+// public boolean end() {
+// return this.eof && !this.usePrevious;
+// }
+//
+//
+// /**
+// * Determine if the source string still contains characters that next()
+// * can consume.
+// * @return true if not yet at the end of the source.
+// */
+// public boolean more() {
+// this.next();
+// if (this.end()) {
+// return false;
+// }
+// this.back();
+// return true;
+// }
+//
+//
+// /**
+// * Get the next character in the source string.
+// *
+// * @return The next character, or 0 if past the end of the source string.
+// */
+// public char next() {
+// int c;
+// if (this.usePrevious) {
+// this.usePrevious = false;
+// c = this.previous;
+// } else {
+// try {
+// c = this.reader.read();
+// } catch (IOException exception) {
+// throw new RuntimeException(exception);
+// }
+//
+// if (c <= 0) { // End of stream
+// this.eof = true;
+// c = 0;
+// }
+// }
+// this.index += 1;
+// if (this.previous == '\r') {
+// this.line += 1;
+// this.character = c == '\n' ? 0 : 1;
+// } else if (c == '\n') {
+// this.line += 1;
+// this.character = 0;
+// } else {
+// this.character += 1;
+// }
+// this.previous = (char) c;
+// return this.previous;
+// }
+//
+//
+// /**
+// * Consume the next character, and check that it matches a specified
+// * character.
+// * @param c The character to match.
+// * @return The character.
+// * @throws JSONException if the character does not match.
+// */
+// public char next(char c) {
+// char n = this.next();
+// if (n != c) {
+// throw new RuntimeException("Expected '" + c + "' and instead saw '" + n + "'");
+// }
+// return n;
+// }
+//
+//
+// /**
+// * Get the next n characters.
+// *
+// * @param n The number of characters to take.
+// * @return A string of n characters.
+// * @throws JSONException
+// * Substring bounds error if there are not
+// * n characters remaining in the source string.
+// */
+// public String next(int n) {
+// if (n == 0) {
+// return "";
+// }
+//
+// char[] chars = new char[n];
+// int pos = 0;
+//
+// while (pos < n) {
+// chars[pos] = this.next();
+// if (this.end()) {
+// throw new RuntimeException("Substring bounds error");
+// }
+// pos += 1;
+// }
+// return new String(chars);
+// }
+//
+//
+// /**
+// * Get the next char in the string, skipping whitespace.
+// * @throws JSONException
+// * @return A character, or 0 if there are no more characters.
+// */
+// public char nextClean() {
+// for (;;) {
+// char c = this.next();
+// if (c == 0 || c > ' ') {
+// return c;
+// }
+// }
+// }
+//
+//
+// /**
+// * Return the characters up to the next close quote character.
+// * Backslash processing is done. The formal JSON format does not
+// * allow strings in single quotes, but an implementation is allowed to
+// * accept them.
+// * @param quote The quoting character, either
+// * " (double quote) or
+// * ' (single quote).
+// * @return A String.
+// * @throws JSONException Unterminated string.
+// */
+// public String nextString(char quote) {
+// char c;
+// StringBuffer sb = new StringBuffer();
+// for (;;) {
+// c = this.next();
+// switch (c) {
+// case 0:
+// case '\n':
+// case '\r':
+// throw new RuntimeException("Unterminated string");
+// case '\\':
+// c = this.next();
+// switch (c) {
+// case 'b':
+// sb.append('\b');
+// break;
+// case 't':
+// sb.append('\t');
+// break;
+// case 'n':
+// sb.append('\n');
+// break;
+// case 'f':
+// sb.append('\f');
+// break;
+// case 'r':
+// sb.append('\r');
+// break;
+// case 'u':
+// sb.append((char)Integer.parseInt(this.next(4), 16));
+// break;
+// case '"':
+// case '\'':
+// case '\\':
+// case '/':
+// sb.append(c);
+// break;
+// default:
+// throw new RuntimeException("Illegal escape.");
+// }
+// break;
+// default:
+// if (c == quote) {
+// return sb.toString();
+// }
+// sb.append(c);
+// }
+// }
+// }
+//
+//
+// /**
+// * Get the text up but not including the specified character or the
+// * end of line, whichever comes first.
+// * @param delimiter A delimiter character.
+// * @return A string.
+// */
+// public String nextTo(char delimiter) {
+// StringBuffer sb = new StringBuffer();
+// for (;;) {
+// char c = this.next();
+// if (c == delimiter || c == 0 || c == '\n' || c == '\r') {
+// if (c != 0) {
+// this.back();
+// }
+// return sb.toString().trim();
+// }
+// sb.append(c);
+// }
+// }
+//
+//
+// /**
+// * Get the text up but not including one of the specified delimiter
+// * characters or the end of line, whichever comes first.
+// * @param delimiters A set of delimiter characters.
+// * @return A string, trimmed.
+// */
+// public String nextTo(String delimiters) {
+// char c;
+// StringBuffer sb = new StringBuffer();
+// for (;;) {
+// c = this.next();
+// if (delimiters.indexOf(c) >= 0 || c == 0 ||
+// c == '\n' || c == '\r') {
+// if (c != 0) {
+// this.back();
+// }
+// return sb.toString().trim();
+// }
+// sb.append(c);
+// }
+// }
+//
+//
+// /**
+// * Get the next value. The value can be a Boolean, Double, Integer,
+// * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
+// * @throws JSONException If syntax error.
+// *
+// * @return An object.
+// */
+// public Object nextValue() {
+// char c = this.nextClean();
+// String string;
+//
+// switch (c) {
+// case '"':
+// case '\'':
+// return this.nextString(c);
+// case '{':
+// this.back();
+// return new JSONObject(this);
+// case '[':
+// this.back();
+// return new JSONArray(this);
+// }
+//
+// /*
+// * Handle unquoted text. This could be the values true, false, or
+// * null, or it can be a number. An implementation (such as this one)
+// * is allowed to also accept non-standard forms.
+// *
+// * Accumulate characters until we reach the end of the text or a
+// * formatting character.
+// */
+//
+// StringBuffer sb = new StringBuffer();
+// while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
+// sb.append(c);
+// c = this.next();
+// }
+// this.back();
+//
+// string = sb.toString().trim();
+// if ("".equals(string)) {
+// throw new RuntimeException("Missing value");
+// }
+// return JSONObject.stringToValue(string);
+// }
+//
+//
+// /**
+// * Skip characters until the next character is the requested character.
+// * If the requested character is not found, no characters are skipped.
+// * @param to A character to skip to.
+// * @return The requested character, or zero if the requested character
+// * is not found.
+// */
+// public char skipTo(char to) {
+// char c;
+// try {
+// long startIndex = this.index;
+// long startCharacter = this.character;
+// long startLine = this.line;
+// this.reader.mark(1000000);
+// do {
+// c = this.next();
+// if (c == 0) {
+// this.reader.reset();
+// this.index = startIndex;
+// this.character = startCharacter;
+// this.line = startLine;
+// return c;
+// }
+// } while (c != to);
+// } catch (IOException exc) {
+// throw new RuntimeException(exc);
+// }
+//
+// this.back();
+// return c;
+// }
+//
+//
+// /**
+// * Make a printable string of this JSONTokener.
+// *
+// * @return " at {index} [character {character} line {line}]"
+// */
+// @Override
+// public String toString() {
+// return " at " + this.index + " [character " + this.character + " line " +
+// this.line + "]";
+// }
+// }
}
diff --git a/java/examples/Topics/Advanced Data/LoadSaveJSON/LoadSaveJSON.pde b/java/examples/Topics/Advanced Data/LoadSaveJSON/LoadSaveJSON.pde
index 06f6e20d2c..e34843ff29 100644
--- a/java/examples/Topics/Advanced Data/LoadSaveJSON/LoadSaveJSON.pde
+++ b/java/examples/Topics/Advanced Data/LoadSaveJSON/LoadSaveJSON.pde
@@ -1,5 +1,5 @@
/**
- * Loading XML Data
+ * Loading JSON Data
* by Daniel Shiffman.
*
* This example demonstrates how to use loadJSON()
@@ -31,7 +31,7 @@
}
}
*/
-
+
// An Array of Bubble objects
Bubble[] bubbles;
// A Table object
@@ -45,88 +45,89 @@ void setup() {
void draw() {
background(255);
// Display all bubbles
-// for (Bubble b : bubbles) {
-// b.display();
-// b.rollover(mouseX, mouseY);
-// }
-//
-// textAlign(LEFT);
-// fill(0);
-// text("Click to add bubbles.", 10, height-10);
+ for (Bubble b : bubbles) {
+ b.display();
+ b.rollover(mouseX, mouseY);
+ }
+
+ textAlign(LEFT);
+ fill(0);
+ text("Click to add bubbles.", 10, height-10);
}
void loadData() {
// Load JSON file
- String jsonString = join(loadStrings("data.json"),"\n");
+ String jsonString = join(loadStrings("data.json"), "\n");
//println(jsonString);
-
- json = JSONArray.parse(jsonString);
- println(json);
-
- // Get all the child nodes named "bubble"
-// XML[] children = xml.getChildren("bubble");
-//
-// // The size of the array of Bubble objects is determined by the total XML elements named "bubble"
-// bubbles = new Bubble[children.length];
-//
-// for (int i = 0; i < bubbles.length; i++) {
-//
-// // The position element has two attributes: x and y
-// XML positionElement = children[i].getChild("position");
-// // Note how with attributes we can get an integer or float directly
-// float x = positionElement.getInt("x");
-// float y = positionElement.getInt("y");
-//
-// // The diameter is the content of the child named "diamater"
-// XML diameterElement = children[i].getChild("diameter");
-// // Note how with the content of an XML node, we retrieve as a String and then convert
-// float diameter = float(diameterElement.getContent());
-//
-// // The label is the content of the child named "label"
-// XML labelElement = children[i].getChild("label");
-// String label = labelElement.getContent();
-//
-// // Make a Bubble object out of the data read
-// bubbles[i] = new Bubble(x, y, diameter, label);
-// }
-}
+ // Load the entire document in a JSONObject
+ JSONObject root = JSONObject.parse(jsonString);
-// Still need to work on adding and deleting
+ // Fetch the internal JSONObject called "bubbles" (all the bubbles are stored inside this object)
+ JSONObject json_bubbles = root.getJSONObject("bubbles");
-void mousePressed() {
-
- // Create a new XML bubble element
-// XML bubble = xml.addChild("bubble");
-//
-// // Set the poisition element
-// XML position = bubble.addChild("position");
-// // Here we can set attributes as integers directly
-// position.setInt("x",mouseX);
-// position.setInt("y",mouseY);
-//
-// // Set the diameter element
-// XML diameter = bubble.addChild("diameter");
-// // Here for a node's content, we have to convert to a String
-// diameter.setContent("" + random(40,80));
-//
-// // Set a label
-// XML label = bubble.addChild("label");
-// label.setContent("New label");
-//
-//
-// // Here we are removing the oldest bubble if there are more than 10
-// XML[] children = xml.getChildren("bubble");
-// // If the XML file has more than 10 bubble elements
-// if (children.length > 10) {
-// // Delete the first one
-// xml.removeChild(children[0]);
-// }
-//
-// // Save a new XML file
-// saveXML(xml,"data/data.xml");
-//
-// // reload the new data
-// loadData();
+ // Load the JSONArray of bubbles
+ json = json_bubbles.getJSONArray("bubble");
+
+ // The size of the array of Bubble objects is determined by the total XML elements named "bubble"
+ bubbles = new Bubble[json.size()];
+
+ for (int i = 0; i < bubbles.length; i++) {
+
+ // Get the JSONObject representing the bubble
+ JSONObject bubble = json.getObject(i);
+
+ // The position element has two attributes: x and y
+ float x = bubble.getJSONObject("position").getInt("x");
+ float y = bubble.getJSONObject("position").getInt("y");
+
+ // The diameter is the content of the child named "diamater"
+ float diameter = bubble.getFloat("diameter");
+
+ // The label is the content of the child named "label"
+ String label = bubble.getString("label");
+
+ // Make a Bubble object out of the data read
+ bubbles[i] = new Bubble(x, y, diameter, label);
+ }
}
+void mousePressed() {
+
+ // Create a new JSON bubble element
+ JSONObject newBubble = new JSONObject();
+
+ // Set the poisition element
+ JSONObject position = new JSONObject();
+ position.setInt("x", mouseX);
+ position.setInt("y", mouseY);
+ newBubble.setJSONObject("position", position);
+
+ // Set the diameter element
+ newBubble.setFloat("diameter", random(40, 80));
+
+ // Set a label
+ newBubble.setString("label", "New label");
+
+ // Append the new bubble to the JSONArray json
+ json.append( newBubble );
+
+ // Here we are removing the oldest bubble if there are more than 10
+ // If the XML file has more than 10 bubble elements
+ if (json.size() > 10) {
+ // Delete the first one
+ json.removeIndex(0);
+ }
+
+ JSONObject jsonBubbles = new JSONObject();
+ jsonBubbles.setJSONArray( "bubble", json );
+
+ JSONObject root = new JSONObject();
+ root.setJSONObject( "bubbles", jsonBubbles );
+
+ // Save a new XML file
+ saveStrings("data/data.json", split(root.toString(), "\n"));
+
+ // reload the new data
+ loadData();
+}