50 Commits

Author SHA1 Message Date
Sean Leary
37582a44ad Update README 2016-08-10 09:13:22 -05:00
Sean Leary
154cfda9aa Merge pull request #261 from stleary/revert-249-master
Revert "reduces the use of unnecessary exceptions"
2016-08-10 09:03:57 -05:00
Sean Leary
45a7decba4 Revert "reduces the use of unnecessary exceptions" 2016-08-09 14:22:06 -05:00
Sean Leary
8e079599c4 Update README 2016-08-07 15:19:44 -05:00
Sean Leary
3080b8beeb Merge pull request #253 from johnjaylward/OptionalTypeConversion
Optional type conversion for XML reading
2016-07-31 21:09:07 -05:00
Sean Leary
2c228ecf1a Merge pull request #249 from Simulant87/master
reduces the use of unnecessary exceptions
2016-07-26 23:04:49 -05:00
Nils Faupel
3890bfae52 reduce the use of unnecessary exceptions 2016-07-19 19:59:30 +02:00
Nils Faupel
abf2963bbe Revert "reduces the use of unnecessary exceptions"
This reverts commit 7627d40d10.
2016-07-19 19:00:42 +02:00
John J. Aylward
09d37e59b8 Cleans up the JSONML changes and adds similar changes to the XML class 2016-07-18 14:42:21 -04:00
John J. Aylward
93704371bb Updates to the Javadoc for exceptions 2016-07-18 14:12:06 -04:00
Jakob Stemberger
42e0944708 Brings in changes from PR #70 to be updated to HEAD 2016-07-18 13:45:31 -04:00
Simulant
7627d40d10 reduces the use of unnecessary exceptions 2016-07-08 22:17:05 +02:00
Sean Leary
04181fb6e2 Merge pull request #246 from johnjaylward/LicenseFile
Add License file
2016-07-02 13:20:54 -05:00
Sean Leary
239e0b7070 Merge pull request #242 from johnjaylward/issue240
Fixes Issue #240
2016-07-02 13:20:21 -05:00
johnjaylward
a8a71898a3 Create LICENSE 2016-06-22 14:49:52 -04:00
johnjaylward
86e8f7b313 Update README
fixes typo
2016-06-17 16:39:11 -04:00
John J. Aylward
42791ab12d Updates README to note that the parser does allow some invalid JSON 2016-06-16 13:01:22 -04:00
johnjaylward
b3abaa5b4c Merge pull request #1 from stleary/master
update from origin
2016-06-16 11:43:05 -04:00
Sean Leary
eb569b58fc Merge pull request #236 from madsager/master
Make nextString throw a JSONException instead of a NumberFormatExcept…
2016-06-07 21:29:02 -05:00
Mads Ager
16a86d73df Pass in the throwable that caused the error. 2016-06-02 16:11:15 +02:00
Mads Ager
dfa651e777 Make nextString throw a JSONException instead of a NumberFormatException for malformed input. 2016-06-02 15:56:48 +02:00
Sean Leary
612dafc750 Update JSONObject.java 2016-05-20 21:10:17 -05:00
Sean Leary
808320801a Update JSONArray.java
Update version timestamp
2016-05-20 21:09:53 -05:00
Sean Leary
b2bde1f468 Merge pull request #234 from erosb/master
fixing stleary/JSON-Java#233
2016-05-20 21:03:06 -05:00
Bence Erős
56be31e7a8 fixing stleary/JSON-Java#233 2016-05-16 14:53:34 +02:00
stleary
9a81b40334 added some JavaDocs 2016-05-14 11:09:51 -05:00
stleary
4a458a9f1c add timestamps to recent commits, javadocs for JSONObject, JSONArray queryFrom() methods 2016-05-14 09:22:18 -05:00
Sean Leary
8a72509e6e Merge pull request #222 from erosb/master
JSON Pointer implementation
2016-05-13 22:46:52 -05:00
Bence Erős
c044eb14dd added copying to JSONPointer constructor 2016-05-05 15:59:43 +02:00
Bence Erős
5ae6a66e38 added javadoc & null check in Builder#append(String) 2016-05-03 23:41:51 +02:00
Bence Erős
d833c2d8de added builder class for JSONPointer, and implemented toString() and toURIFragment() 2016-05-03 23:18:05 +02:00
Sean Leary
f21ffbe189 Update CDL.java
Date of last change.
2016-05-02 22:12:29 -05:00
Sean Leary
cad23423ab Update JSONObject.java
Forgot to update date of last change
2016-05-02 22:11:20 -05:00
Sean Leary
ebf08f5651 Merge pull request #226 from stleary/restore-1.6-compatibility
fix to compile with 1.6.0_45
2016-05-01 22:59:29 -05:00
Sean Leary
f239dc75ad Merge pull request #219 from captainIowa/master
Added CSV change to CDL.java
2016-05-01 22:55:13 -05:00
stleary
1ca8933a8f fix to compile with 1.6.0_45 2016-04-28 22:12:16 -05:00
Bence Erős
cbb1546c53 README improvements for stleary/JSON-Java#218 2016-04-28 16:45:17 +02:00
Bence Erős
c1a789a70c adding missing license headers 2016-04-27 00:11:47 +02:00
Bence Erős
bff352791c removed @author tag from JSONPointerException 2016-04-27 00:10:45 +02:00
Bence Erős
5223aadd67 added some javadoc to JSONPointer 2016-04-27 00:10:06 +02:00
Bence Erős
45bd72c15d added JSONObject#query() and JSONPointer#query() methods 2016-04-26 23:48:14 +02:00
Bence Erős
792c6f6a9c improved failure handling 2016-04-26 23:32:15 +02:00
Bence Erős
5bee7e3b45 escape handling improvements & URL fragment notation handling 2016-04-26 23:00:16 +02:00
Bence Erős
612e41950c initial implementation of JSONPointer 2016-04-17 23:21:38 +02:00
Brian Russell
86cbfbc864 Added CSV change to CDL.java 2016-04-12 14:13:15 -04:00
Sean Leary
25a87975be Update date of merge. 2016-03-05 15:20:20 -06:00
Sean Leary
2f3af56535 Update date of merge. 2016-03-05 15:19:45 -06:00
Sean Leary
26477f4e76 Merge pull request #203 from joeferner/to-java
Adds JSONArray toList method and JSONObject toMap method
2016-03-05 15:18:38 -06:00
Joe Ferner
f024b52108 Adds JSONArray toList method and JSONObject toMap method 2016-02-27 11:20:25 -05:00
Sean Leary
2657915293 Update README
Include some text about 1.6 compatibility and add the latest release information.
2016-02-13 22:26:45 -06:00
10 changed files with 690 additions and 55 deletions

View File

@@ -41,7 +41,7 @@ SOFTWARE.
* The names for the elements in the JSONObjects can be taken from the names
* in the first row.
* @author JSON.org
* @version 2015-12-09
* @version 2016-05-01
*/
public class CDL {
@@ -69,7 +69,12 @@ public class CDL {
for (;;) {
c = x.next();
if (c == q) {
break;
//Handle escaped double-quote
if(x.next() != '\"')
{
x.back();
break;
}
}
if (c == 0 || c == '\n' || c == '\r') {
throw x.syntaxError("Missing close quote '" + q + "'.");

View File

@@ -28,10 +28,12 @@ import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Array;
import java.math.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
@@ -76,7 +78,7 @@ import java.util.Map;
* </ul>
*
* @author JSON.org
* @version 2016-02-08
* @version 2016-05-20
*/
public class JSONArray implements Iterable<Object> {
@@ -957,6 +959,46 @@ public class JSONArray implements Iterable<Object> {
}
return this;
}
/**
* Creates a JSONPointer using an intialization string and tries to
* match it to an item within this JSONArray. For example, given a
* JSONArray initialized with this document:
* <pre>
* [
* {"b":"c"}
* ]
* </pre>
* and this JSONPointer string:
* <pre>
* "/0/b"
* </pre>
* Then this method will return the String "c"
* A JSONPointerException may be thrown from code called by this method.
*
* @param jsonPointer string that can be used to create a JSONPointer
* @return the item matched by the JSONPointer, otherwise null
*/
public Object query(String jsonPointer) {
return new JSONPointer(jsonPointer).queryFrom(this);
}
/**
* Queries and returns a value from this object using {@code jsonPointer}, or
* returns null if the query fails due to a missing key.
*
* @param jsonPointer the string representation of the JSON pointer
* @return the queried value or {@code null}
* @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax
*/
public Object optQuery(String jsonPointer) {
JSONPointer pointer = new JSONPointer(jsonPointer);
try {
return pointer.queryFrom(this);
} catch (JSONPointerException e) {
return null;
}
}
/**
* Remove an index and close the hole.
@@ -1130,4 +1172,29 @@ public class JSONArray implements Iterable<Object> {
throw new JSONException(e);
}
}
/**
* Returns a java.util.List containing all of the elements in this array.
* If an element in the array is a JSONArray or JSONObject it will also
* be converted.
* <p>
* Warning: This method assumes that the data structure is acyclical.
*
* @return a java.util.List containing the elements of this array
*/
public List<Object> toList() {
List<Object> results = new ArrayList<Object>(this.myArrayList.size());
for (Object element : this.myArrayList) {
if (element == null || JSONObject.NULL.equals(element)) {
results.add(null);
} else if (element instanceof JSONArray) {
results.add(((JSONArray) element).toList());
} else if (element instanceof JSONObject) {
results.add(((JSONObject) element).toMap());
} else {
results.add(element);
}
}
return results;
}
}

View File

@@ -36,20 +36,21 @@ import java.util.Iterator;
* @version 2016-01-30
*/
public class JSONML {
/**
* Parse XML values and store them in a JSONArray.
* @param x The XMLTokener containing the source string.
* @param arrayForm true if array form, false if object form.
* @param ja The JSONArray that is containing the current tag or null
* if we are at the outermost level.
* @param keepStrings Don't type-convert text nodes and attibute values
* @return A JSONArray if the value is the outermost tag, otherwise null.
* @throws JSONException
*/
private static Object parse(
XMLTokener x,
boolean arrayForm,
JSONArray ja
JSONArray ja,
boolean keepStrings
) throws JSONException {
String attribute;
char c;
@@ -174,7 +175,7 @@ public class JSONML {
if (!(token instanceof String)) {
throw x.syntaxError("Missing value");
}
newjo.accumulate(attribute, JSONObject.stringToValue((String)token));
newjo.accumulate(attribute, keepStrings ? token :JSONObject.stringToValue((String)token));
token = null;
} else {
newjo.accumulate(attribute, "");
@@ -193,9 +194,8 @@ public class JSONML {
if (ja == null) {
if (arrayForm) {
return newja;
} else {
return newjo;
}
return newjo;
}
// Content, between <...> and </...>
@@ -204,7 +204,7 @@ public class JSONML {
if (token != XML.GT) {
throw x.syntaxError("Misshaped tag");
}
closeTag = (String)parse(x, arrayForm, newja);
closeTag = (String)parse(x, arrayForm, newja, keepStrings);
if (closeTag != null) {
if (!closeTag.equals(tagName)) {
throw x.syntaxError("Mismatched '" + tagName +
@@ -217,9 +217,8 @@ public class JSONML {
if (ja == null) {
if (arrayForm) {
return newja;
} else {
return newjo;
}
return newjo;
}
}
}
@@ -227,7 +226,7 @@ public class JSONML {
} else {
if (ja != null) {
ja.put(token instanceof String
? JSONObject.stringToValue((String)token)
? keepStrings ? token :JSONObject.stringToValue((String)token)
: token);
}
}
@@ -245,10 +244,54 @@ public class JSONML {
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param string The source string.
* @return A JSONArray containing the structured data from the XML string.
* @throws JSONException
* @throws JSONException Thrown on error converting to a JSONArray
*/
public static JSONArray toJSONArray(String string) throws JSONException {
return toJSONArray(new XMLTokener(string));
return (JSONArray)parse(new XMLTokener(string), true, null, false);
}
/**
* Convert a well-formed (but not necessarily valid) XML string into a
* JSONArray using the JsonML transform. Each XML tag is represented as
* a JSONArray in which the first element is the tag name. If the tag has
* attributes, then the second element will be JSONObject containing the
* name/value pairs. If the tag contains children, then strings and
* JSONArrays will represent the child tags.
* As opposed to toJSONArray this method does not attempt to convert
* any text node or attribute value to any type
* but just leaves it as a string.
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param string The source string.
* @param keepStrings If true, then values will not be coerced into boolean
* or numeric values and will instead be left as strings
* @return A JSONArray containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONArray
*/
public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException {
return (JSONArray)parse(new XMLTokener(string), true, null, keepStrings);
}
/**
* Convert a well-formed (but not necessarily valid) XML string into a
* JSONArray using the JsonML transform. Each XML tag is represented as
* a JSONArray in which the first element is the tag name. If the tag has
* attributes, then the second element will be JSONObject containing the
* name/value pairs. If the tag contains children, then strings and
* JSONArrays will represent the child content and tags.
* As opposed to toJSONArray this method does not attempt to convert
* any text node or attribute value to any type
* but just leaves it as a string.
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param x An XMLTokener.
* @param keepStrings If true, then values will not be coerced into boolean
* or numeric values and will instead be left as strings
* @return A JSONArray containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONArray
*/
public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException {
return (JSONArray)parse(x, true, null, keepStrings);
}
@@ -262,28 +305,10 @@ public class JSONML {
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param x An XMLTokener.
* @return A JSONArray containing the structured data from the XML string.
* @throws JSONException
* @throws JSONException Thrown on error converting to a JSONArray
*/
public static JSONArray toJSONArray(XMLTokener x) throws JSONException {
return (JSONArray)parse(x, true, null);
}
/**
* Convert a well-formed (but not necessarily valid) XML string into a
* JSONObject using the JsonML transform. Each XML tag is represented as
* a JSONObject with a "tagName" property. If the tag has attributes, then
* the attributes will be in the JSONObject as properties. If the tag
* contains children, the object will have a "childNodes" property which
* will be an array of strings and JsonML JSONObjects.
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param x An XMLTokener of the XML source text.
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException
*/
public static JSONObject toJSONObject(XMLTokener x) throws JSONException {
return (JSONObject)parse(x, false, null);
return (JSONArray)parse(x, true, null, false);
}
@@ -298,10 +323,68 @@ public class JSONML {
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param string The XML source text.
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException
* @throws JSONException Thrown on error converting to a JSONObject
*/
public static JSONObject toJSONObject(String string) throws JSONException {
return toJSONObject(new XMLTokener(string));
return (JSONObject)parse(new XMLTokener(string), false, null, false);
}
/**
* Convert a well-formed (but not necessarily valid) XML string into a
* JSONObject using the JsonML transform. Each XML tag is represented as
* a JSONObject with a "tagName" property. If the tag has attributes, then
* the attributes will be in the JSONObject as properties. If the tag
* contains children, the object will have a "childNodes" property which
* will be an array of strings and JsonML JSONObjects.
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param string The XML source text.
* @param keepStrings If true, then values will not be coerced into boolean
* or numeric values and will instead be left as strings
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONObject
*/
public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException {
return (JSONObject)parse(new XMLTokener(string), false, null, keepStrings);
}
/**
* Convert a well-formed (but not necessarily valid) XML string into a
* JSONObject using the JsonML transform. Each XML tag is represented as
* a JSONObject with a "tagName" property. If the tag has attributes, then
* the attributes will be in the JSONObject as properties. If the tag
* contains children, the object will have a "childNodes" property which
* will be an array of strings and JsonML JSONObjects.
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param x An XMLTokener of the XML source text.
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONObject
*/
public static JSONObject toJSONObject(XMLTokener x) throws JSONException {
return (JSONObject)parse(x, false, null, false);
}
/**
* Convert a well-formed (but not necessarily valid) XML string into a
* JSONObject using the JsonML transform. Each XML tag is represented as
* a JSONObject with a "tagName" property. If the tag has attributes, then
* the attributes will be in the JSONObject as properties. If the tag
* contains children, the object will have a "childNodes" property which
* will be an array of strings and JsonML JSONObjects.
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param x An XMLTokener of the XML source text.
* @param keepStrings If true, then values will not be coerced into boolean
* or numeric values and will instead be left as strings
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONObject
*/
public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException {
return (JSONObject)parse(x, false, null, keepStrings);
}
@@ -309,7 +392,7 @@ public class JSONML {
* Reverse the JSONML transformation, making an XML text from a JSONArray.
* @param ja A JSONArray.
* @return An XML string.
* @throws JSONException
* @throws JSONException Thrown on error converting to a string
*/
public static String toString(JSONArray ja) throws JSONException {
int i;
@@ -393,7 +476,7 @@ public class JSONML {
* The other properties are attributes with string values.
* @param jo A JSONObject.
* @return An XML string.
* @throws JSONException
* @throws JSONException Thrown on error converting to a string
*/
public static String toString(JSONObject jo) throws JSONException {
StringBuilder sb = new StringBuilder();

View File

@@ -93,7 +93,7 @@ import java.util.Set;
* </ul>
*
* @author JSON.org
* @version 2016-02-08
* @version 2016-05-20
*/
public class JSONObject {
/**
@@ -1338,6 +1338,46 @@ public class JSONObject {
return this;
}
/**
* Creates a JSONPointer using an intialization string and tries to
* match it to an item within this JSONObject. For example, given a
* JSONObject initialized with this document:
* <pre>
* {
* "a":{"b":"c"}
* }
* </pre>
* and this JSONPointer string:
* <pre>
* "/a/b"
* </pre>
* Then this method will return the String "c".
* A JSONPointerException may be thrown from code called by this method.
*
* @param jsonPointer string that can be used to create a JSONPointer
* @return the item matched by the JSONPointer, otherwise null
*/
public Object query(String jsonPointer) {
return new JSONPointer(jsonPointer).queryFrom(this);
}
/**
* Queries and returns a value from this object using {@code jsonPointer}, or
* returns null if the query fails due to a missing key.
*
* @param jsonPointer the string representation of the JSON pointer
* @return the queried value or {@code null}
* @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax
*/
public Object optQuery(String jsonPointer) {
JSONPointer pointer = new JSONPointer(jsonPointer);
try {
return pointer.queryFrom(this);
} catch (JSONPointerException e) {
return null;
}
}
/**
* Produce a string in double quotes with backslash sequences in all the
* right places. A backslash will be inserted within </, producing <\/,
@@ -1838,4 +1878,31 @@ public class JSONObject {
throw new JSONException(exception);
}
}
/**
* Returns a java.util.Map containing all of the entrys in this object.
* If an entry in the object is a JSONArray or JSONObject it will also
* be converted.
* <p>
* Warning: This method assumes that the data structure is acyclical.
*
* @return a java.util.Map containing the entrys of this object
*/
public Map<String, Object> toMap() {
Map<String, Object> results = new HashMap<String, Object>();
for (Entry<String, Object> entry : this.map.entrySet()) {
Object value;
if (entry.getValue() == null || NULL.equals(entry.getValue())) {
value = null;
} else if (entry.getValue() instanceof JSONObject) {
value = ((JSONObject) entry.getValue()).toMap();
} else if (entry.getValue() instanceof JSONArray) {
value = ((JSONArray) entry.getValue()).toList();
} else {
value = entry.getValue();
}
results.put(entry.getKey(), value);
}
return results;
}
}

267
JSONPointer.java Normal file
View File

@@ -0,0 +1,267 @@
package org.json;
import static java.lang.String.format;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.*;
/*
Copyright (c) 2002 JSON.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The Software shall be used for Good, not Evil.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* A JSON Pointer is a simple query language defined for JSON documents by
* <a href="https://tools.ietf.org/html/rfc6901">RFC 6901</a>.
*
* In a nutshell, JSONPointer allows the user to navigate into a JSON document
* using strings, and retrieve targeted objects, like a simple form of XPATH.
* Path segments are separated by the '/' char, which signifies the root of
* the document when it appears as the first char of the string. Array
* elements are navigated using ordinals, counting from 0. JSONPointer strings
* may be extended to any arbitrary number of segments. If the navigation
* is successful, the matched item is returned. A matched item may be a
* JSONObject, a JSONArray, or a JSON value. If the JSONPointer string building
* fails, an appropriate exception is thrown. If the navigation fails to find
* a match, a JSONPointerException is thrown.
*
* @author JSON.org
* @version 2016-05-14
*/
public class JSONPointer {
// used for URL encoding and decoding
private static final String ENCODING = "utf-8";
/**
* This class allows the user to build a JSONPointer in steps, using
* exactly one segment in each step.
*/
public static class Builder {
// Segments for the eventual JSONPointer string
private final List<String> refTokens = new ArrayList<String>();
/**
* Creates a {@code JSONPointer} instance using the tokens previously set using the
* {@link #append(String)} method calls.
*/
public JSONPointer build() {
return new JSONPointer(refTokens);
}
/**
* Adds an arbitary token to the list of reference tokens. It can be any non-null value.
*
* Unlike in the case of JSON string or URI fragment representation of JSON pointers, the
* argument of this method MUST NOT be escaped. If you want to query the property called
* {@code "a~b"} then you should simply pass the {@code "a~b"} string as-is, there is no
* need to escape it as {@code "a~0b"}.
*
* @param token the new token to be appended to the list
* @return {@code this}
* @throws NullPointerException if {@code token} is null
*/
public Builder append(String token) {
if (token == null) {
throw new NullPointerException("token cannot be null");
}
refTokens.add(token);
return this;
}
/**
* Adds an integer to the reference token list. Although not necessarily, mostly this token will
* denote an array index.
*
* @param arrayIndex the array index to be added to the token list
* @return {@code this}
*/
public Builder append(int arrayIndex) {
refTokens.add(String.valueOf(arrayIndex));
return this;
}
}
/**
* Static factory method for {@link Builder}. Example usage:
*
* <pre><code>
* JSONPointer pointer = JSONPointer.builder()
* .append("obj")
* .append("other~key").append("another/key")
* .append("\"")
* .append(0)
* .build();
* </code></pre>
*
* @return a builder instance which can be used to construct a {@code JSONPointer} instance by chained
* {@link Builder#append(String)} calls.
*/
public static Builder builder() {
return new Builder();
}
// Segments for the JSONPointer string
private final List<String> refTokens;
/**
* Pre-parses and initializes a new {@code JSONPointer} instance. If you want to
* evaluate the same JSON Pointer on different JSON documents then it is recommended
* to keep the {@code JSONPointer} instances due to performance considerations.
*
* @param pointer the JSON String or URI Fragment representation of the JSON pointer.
* @throws IllegalArgumentException if {@code pointer} is not a valid JSON pointer
*/
public JSONPointer(String pointer) {
if (pointer == null) {
throw new NullPointerException("pointer cannot be null");
}
if (pointer.isEmpty()) {
refTokens = Collections.emptyList();
return;
}
if (pointer.startsWith("#/")) {
pointer = pointer.substring(2);
try {
pointer = URLDecoder.decode(pointer, ENCODING);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
} else if (pointer.startsWith("/")) {
pointer = pointer.substring(1);
} else {
throw new IllegalArgumentException("a JSON pointer should start with '/' or '#/'");
}
refTokens = new ArrayList<String>();
for (String token : pointer.split("/")) {
refTokens.add(unescape(token));
}
}
public JSONPointer(List<String> refTokens) {
this.refTokens = new ArrayList<String>(refTokens);
}
private String unescape(String token) {
return token.replace("~1", "/").replace("~0", "~")
.replace("\\\"", "\"")
.replace("\\\\", "\\");
}
/**
* Evaluates this JSON Pointer on the given {@code document}. The {@code document}
* is usually a {@link JSONObject} or a {@link JSONArray} instance, but the empty
* JSON Pointer ({@code ""}) can be evaluated on any JSON values and in such case the
* returned value will be {@code document} itself.
*
* @param document the JSON document which should be the subject of querying.
* @return the result of the evaluation
* @throws JSONPointerException if an error occurs during evaluation
*/
public Object queryFrom(Object document) {
if (refTokens.isEmpty()) {
return document;
}
Object current = document;
for (String token : refTokens) {
if (current instanceof JSONObject) {
current = ((JSONObject) current).opt(unescape(token));
} else if (current instanceof JSONArray) {
current = readByIndexToken(current, token);
} else {
throw new JSONPointerException(format(
"value [%s] is not an array or object therefore its key %s cannot be resolved", current,
token));
}
}
return current;
}
/**
* Matches a JSONArray element by ordinal position
* @param current the JSONArray to be evaluated
* @param indexToken the array index in string form
* @return the matched object. If no matching item is found a
* JSONPointerException is thrown
*/
private Object readByIndexToken(Object current, String indexToken) {
try {
int index = Integer.parseInt(indexToken);
JSONArray currentArr = (JSONArray) current;
if (index >= currentArr.length()) {
throw new JSONPointerException(format("index %d is out of bounds - the array has %d elements", index,
currentArr.length()));
}
return currentArr.get(index);
} catch (NumberFormatException e) {
throw new JSONPointerException(format("%s is not an array index", indexToken), e);
}
}
/**
* Returns a string representing the JSONPointer path value using string
* representation
*/
@Override
public String toString() {
StringBuilder rval = new StringBuilder("");
for (String token: refTokens) {
rval.append('/').append(escape(token));
}
return rval.toString();
}
/**
* Escapes path segment values to an unambiguous form.
* The escape char to be inserted is '~'. The chars to be escaped
* are ~, which maps to ~0, and /, which maps to ~1. Backslashes
* and double quote chars are also escaped.
* @param token the JSONPointer segment value to be escaped
* @return the escaped value for the token
*/
private String escape(String token) {
return token.replace("~", "~0")
.replace("/", "~1")
.replace("\\", "\\\\")
.replace("\"", "\\\"");
}
/**
* Returns a string representing the JSONPointer path value using URI
* fragment identifier representation
*/
public String toURIFragment() {
try {
StringBuilder rval = new StringBuilder("#");
for (String token : refTokens) {
rval.append('/').append(URLEncoder.encode(token, ENCODING));
}
return rval.toString();
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}

45
JSONPointerException.java Normal file
View File

@@ -0,0 +1,45 @@
package org.json;
/*
Copyright (c) 2002 JSON.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The Software shall be used for Good, not Evil.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* The JSONPointerException is thrown by {@link JSONPointer} if an error occurs
* during evaluating a pointer.
*
* @author JSON.org
* @version 2016-05-13
*/
public class JSONPointerException extends JSONException {
private static final long serialVersionUID = 8872944667561856751L;
public JSONPointerException(String message) {
super(message);
}
public JSONPointerException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -71,7 +71,7 @@ public class JSONTokener {
* Construct a JSONTokener from an InputStream.
* @param inputStream The source.
*/
public JSONTokener(InputStream inputStream) throws JSONException {
public JSONTokener(InputStream inputStream) {
this(new InputStreamReader(inputStream));
}
@@ -90,6 +90,8 @@ public class JSONTokener {
* 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.
* @throws JSONException Thrown if trying to step back more than 1 step
* or if already at the start of the string
*/
public void back() throws JSONException {
if (this.usePrevious || this.index <= 0) {
@@ -121,6 +123,9 @@ public class JSONTokener {
return -1;
}
/**
* @return true if at the end of the file and we didn't step back
*/
public boolean end() {
return this.eof && !this.usePrevious;
}
@@ -130,6 +135,8 @@ public class JSONTokener {
* Determine if the source string still contains characters that next()
* can consume.
* @return true if not yet at the end of the source.
* @throws JSONException thrown if there is an error stepping forward
* or backward while checking for more data.
*/
public boolean more() throws JSONException {
this.next();
@@ -145,6 +152,7 @@ public class JSONTokener {
* Get the next character in the source string.
*
* @return The next character, or 0 if past the end of the source string.
* @throws JSONException Thrown if there is an error reading the source string.
*/
public char next() throws JSONException {
int c;
@@ -225,7 +233,7 @@ public class JSONTokener {
/**
* Get the next char in the string, skipping whitespace.
* @throws JSONException
* @throws JSONException Thrown if there is an error reading the source string.
* @return A character, or 0 if there are no more characters.
*/
public char nextClean() throws JSONException {
@@ -278,7 +286,11 @@ public class JSONTokener {
sb.append('\r');
break;
case 'u':
sb.append((char)Integer.parseInt(this.next(4), 16));
try {
sb.append((char)Integer.parseInt(this.next(4), 16));
} catch (NumberFormatException e) {
throw this.syntaxError("Illegal escape.", e);
}
break;
case '"':
case '\'':
@@ -305,6 +317,8 @@ public class JSONTokener {
* end of line, whichever comes first.
* @param delimiter A delimiter character.
* @return A string.
* @throws JSONException Thrown if there is an error while searching
* for the delimiter
*/
public String nextTo(char delimiter) throws JSONException {
StringBuilder sb = new StringBuilder();
@@ -326,6 +340,8 @@ public class JSONTokener {
* characters or the end of line, whichever comes first.
* @param delimiters A set of delimiter characters.
* @return A string, trimmed.
* @throws JSONException Thrown if there is an error while searching
* for the delimiter
*/
public String nextTo(String delimiters) throws JSONException {
char c;
@@ -397,6 +413,8 @@ public class JSONTokener {
* @param to A character to skip to.
* @return The requested character, or zero if the requested character
* is not found.
* @throws JSONException Thrown if there is an error while searching
* for the to character
*/
public char skipTo(char to) throws JSONException {
char c;
@@ -433,12 +451,23 @@ public class JSONTokener {
return new JSONException(message + this.toString());
}
/**
* Make a JSONException to signal a syntax error.
*
* @param message The error message.
* @param causedBy The throwable that caused the error.
* @return A JSONException object, suitable for throwing
*/
public JSONException syntaxError(String message, Throwable causedBy) {
return new JSONException(message + this.toString(), causedBy);
}
/**
* 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 + "]";

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
Copyright (c) 2002 JSON.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The Software shall be used for Good, not Evil.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

27
README
View File

@@ -15,7 +15,7 @@ The license includes this restriction: "The software shall be used for good,
not evil." If your conscience cannot live with that, then choose a different
package.
The package compiles on Java 1.8.
The package compiles on Java 1.6-1.8.
JSONObject.java: The JSONObject can parse text from a String or a JSONTokener
@@ -32,6 +32,10 @@ tokens. It can be constructed from a String, Reader, or InputStream.
JSONException.java: The JSONException is the standard exception type thrown
by this package.
JSONPointer.java: Implementation of
[JSON Pointer (RFC 6901)](https://tools.ietf.org/html/rfc6901). Supports
JSON Pointers both in the form of string representation and URI fragment
representation.
JSONString.java: The JSONString interface requires a toJSONString method,
allowing an object to provide its own serialization.
@@ -73,8 +77,29 @@ This package fully supports Integer, Long, and Double Java types. Partial suppor
for BigInteger and BigDecimal values in JSONObject and JSONArray objects is provided
in the form of get(), opt(), and put() API methods.
Although 1.6 compatibility is currently supported, it is not a project goal and may be
removed in some future release.
In compliance with RFC7159 page 10 section 9, the parser is more lax with what is valid
JSON than the Generator. For Example, the tab character (U+0009) is allowed when reading
JSON Text strings, but when output by the Generator, tab is properly converted to \t in
the string. Other instances may occur where reading invalid JSON text does not cause an
error to be generated. Malformed JSON Texts such as missing end " (quote) on strings or
invalid number formats (1.2e6.3) will cause errors as such documents can not be read
reliably.
Release history:
20160810 Revert code that was breaking opt*() methods.
20160807 This release contains a bug in the JSONObject.opt*() and JSONArray.opt*() methods,
it is not recommended for use.
Java 1.6 compatability fixed, JSONArray.toList() and JSONObject.toMap(),
RFC4180 compatibility, JSONPointer, some exception fixes, optional XML type conversion.
Contains the latest code as of 7 Aug, 2016
20160212 Java 1.6 compatibility, OSGi bundle. Contains the latest code as of 12 Feb, 2016.
20151123 JSONObject and JSONArray initialization with generics. Contains the
latest code as of 23 Nov, 2015.

View File

@@ -110,7 +110,7 @@ public class XML {
*
* @param string
* A string.
* @throws JSONException
* @throws JSONException Thrown if the string contains whitespace or is empty.
*/
public static void noSpace(String string) throws JSONException {
int i, length = string.length();
@@ -137,7 +137,7 @@ public class XML {
* @return true if the close tag is processed.
* @throws JSONException
*/
private static boolean parse(XMLTokener x, JSONObject context, String name)
private static boolean parse(XMLTokener x, JSONObject context, String name, boolean keepStrings)
throws JSONException {
char c;
int i;
@@ -238,7 +238,7 @@ public class XML {
throw x.syntaxError("Missing value");
}
jsonobject.accumulate(string,
JSONObject.stringToValue((String) token));
keepStrings ? token : JSONObject.stringToValue((String) token));
token = null;
} else {
jsonobject.accumulate(string, "");
@@ -270,12 +270,12 @@ public class XML {
string = (String) token;
if (string.length() > 0) {
jsonobject.accumulate("content",
JSONObject.stringToValue(string));
keepStrings ? token : JSONObject.stringToValue(string));
}
} else if (token == LT) {
// Nested element
if (parse(x, jsonobject, tagName)) {
if (parse(x, jsonobject, tagName,keepStrings)) {
if (jsonobject.length() == 0) {
context.accumulate(tagName, "");
} else if (jsonobject.length() == 1
@@ -301,9 +301,10 @@ public class XML {
* {@link JSONObject.stringToValue(String)} method. Use it instead.
*
* @deprecated Use {@link JSONObject#stringToValue(String)} instead.
* @param string
* @param string String to convert
* @return JSON value of this string or the string
*/
@Deprecated
public static Object stringToValue(String string) {
return JSONObject.stringToValue(string);
}
@@ -322,24 +323,49 @@ public class XML {
* @param string
* The source string.
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException
* @throws JSONException Thrown if there is an errors while parsing the string
*/
public static JSONObject toJSONObject(String string) throws JSONException {
return toJSONObject(string, false);
}
/**
* Convert a well-formed (but not necessarily valid) XML string into a
* JSONObject. Some information may be lost in this transformation because
* JSON is a data format and XML is a document format. XML uses elements,
* attributes, and content text, while JSON uses unordered collections of
* name/value pairs and arrays of values. JSON does not does not like to
* distinguish between elements and attributes. Sequences of similar
* elements are represented as JSONArrays. Content text may be placed in a
* "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code>
* are ignored.
*
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to
* numbers but will instead be the exact value as seen in the XML document.
*
* @param string
* The source string.
* @param keepStrings If true, then values will not be coerced into boolean
* or numeric values and will instead be left as strings
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown if there is an errors while parsing the string
*/
public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException {
JSONObject jo = new JSONObject();
XMLTokener x = new XMLTokener(string);
while (x.more() && x.skipPast("<")) {
parse(x, jo, null);
parse(x, jo, null, keepStrings);
}
return jo;
}
/**
* Convert a JSONObject into a well-formed, element-normal XML string.
*
* @param object
* A JSONObject.
* @return A string.
* @throws JSONException
* @throws JSONException Thrown if there is an error parsing the string
*/
public static String toString(Object object) throws JSONException {
return toString(object, null);
@@ -353,7 +379,7 @@ public class XML {
* @param tagName
* The optional name of the enclosing tag.
* @return A string.
* @throws JSONException
* @throws JSONException Thrown if there is an error parsing the string
*/
public static String toString(Object object, String tagName)
throws JSONException {