1
0
Fork 0
mirror of https://github.com/ethauvin/JSON-java.git synced 2025-06-17 07:50:52 -07:00

Merge pull request #170 from johnjaylward/HandleArraysConsistently

Handle arrays consistently
This commit is contained in:
Sean Leary 2016-01-01 13:44:57 -06:00
commit 757fd566ab

140
XML.java
View file

@ -27,11 +27,13 @@ SOFTWARE.
import java.util.Iterator;
/**
* This provides static methods to convert an XML text into a JSONObject,
* and to covert a JSONObject into an XML text.
* This provides static methods to convert an XML text into a JSONObject, and to
* covert a JSONObject into an XML text.
*
* @author JSON.org
* @version 2015-12-09
*/
@SuppressWarnings("boxing")
public class XML {
/** The Character '&'. */
@ -63,13 +65,16 @@ public class XML {
/**
* Replace special characters with XML escapes:
*
* <pre>
* &amp; <small>(ampersand)</small> is replaced by &amp;amp;
* &lt; <small>(less than)</small> is replaced by &amp;lt;
* &gt; <small>(greater than)</small> is replaced by &amp;gt;
* &quot; <small>(double quote)</small> is replaced by &amp;quot;
* </pre>
* @param string The string to be escaped.
*
* @param string
* The string to be escaped.
* @return The escaped string.
*/
public static String escape(String string) {
@ -100,9 +105,11 @@ public class XML {
}
/**
* Throw an exception if the string contains whitespace.
* Whitespace is not allowed in tagNames and attributes.
* @param string A string.
* Throw an exception if the string contains whitespace. Whitespace is not
* allowed in tagNames and attributes.
*
* @param string
* A string.
* @throws JSONException
*/
public static void noSpace(String string) throws JSONException {
@ -112,22 +119,26 @@ public class XML {
}
for (i = 0; i < length; i += 1) {
if (Character.isWhitespace(string.charAt(i))) {
throw new JSONException("'" + string +
"' contains a space character.");
throw new JSONException("'" + string
+ "' contains a space character.");
}
}
}
/**
* Scan the content following the named tag, attaching it to the context.
* @param x The XMLTokener containing the source string.
* @param context The JSONObject that will include the new material.
* @param name The tag name.
*
* @param x
* The XMLTokener containing the source string.
* @param context
* The JSONObject that will include the new material.
* @param name
* The tag name.
* @return true if the close tag is processed.
* @throws JSONException
*/
private static boolean parse(XMLTokener x, JSONObject context,
String name) throws JSONException {
private static boolean parse(XMLTokener x, JSONObject context, String name)
throws JSONException {
char c;
int i;
JSONObject jsonobject = null;
@ -185,7 +196,6 @@ public class XML {
} else if (token == QUEST) {
// <?
x.skipPast("?>");
return false;
} else if (token == SLASH) {
@ -219,7 +229,6 @@ public class XML {
}
// attribute = value
if (token instanceof String) {
string = (String) token;
token = x.nextToken();
@ -235,9 +244,9 @@ public class XML {
jsonobject.accumulate(string, "");
}
// Empty tag <.../>
} else if (token == SLASH) {
// Empty tag <.../>
if (x.nextToken() != GT) {
throw x.syntaxError("Misshaped tag");
}
@ -248,9 +257,8 @@ public class XML {
}
return false;
// Content, between <...> and </...>
} else if (token == GT) {
// Content, between <...> and </...>
for (;;) {
token = x.nextContent();
if (token == null) {
@ -265,14 +273,13 @@ public class XML {
XML.stringToValue(string));
}
// Nested element
} else if (token == LT) {
// Nested element
if (parse(x, jsonobject, tagName)) {
if (jsonobject.length() == 0) {
context.accumulate(tagName, "");
} else if (jsonobject.length() == 1 &&
jsonobject.opt("content") != null) {
} else if (jsonobject.length() == 1
&& jsonobject.opt("content") != null) {
context.accumulate(tagName,
jsonobject.opt("content"));
} else {
@ -289,14 +296,15 @@ public class XML {
}
}
/**
* Try to convert a string into a number, boolean, or null. If the string
* can't be converted, return the string. This is much less ambitious than
* JSONObject.stringToValue, especially because it does not attempt to
* convert plus forms, octal forms, hex forms, or E forms lacking decimal
* points.
* @param string A String.
*
* @param string
* A String.
* @return A simple JSON value.
*/
public static Object stringToValue(String string) {
@ -310,9 +318,8 @@ public class XML {
return JSONObject.NULL;
}
// If it might be a number, try converting it, first as a Long, and then as a
// Double. If that doesn't work, return the string.
// If it might be a number, try converting it, first as a Long, and then
// as a Double. If that doesn't work, return the string.
try {
char initial = string.charAt(0);
if (initial == '-' || (initial >= '0' && initial <= '9')) {
@ -333,18 +340,19 @@ public class XML {
return string;
}
/**
* 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.
* @param string The source string.
* 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.
*
* @param string
* The source string.
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException
*/
@ -357,10 +365,11 @@ public class XML {
return jo;
}
/**
* Convert a JSONObject into a well-formed, element-normal XML string.
* @param object A JSONObject.
*
* @param object
* A JSONObject.
* @return A string.
* @throws JSONException
*/
@ -368,29 +377,29 @@ public class XML {
return toString(object, null);
}
/**
* Convert a JSONObject into a well-formed, element-normal XML string.
* @param object A JSONObject.
* @param tagName The optional name of the enclosing tag.
*
* @param object
* A JSONObject.
* @param tagName
* The optional name of the enclosing tag.
* @return A string.
* @throws JSONException
*/
public static String toString(Object object, String tagName)
throws JSONException {
StringBuilder sb = new StringBuilder();
int i;
JSONArray ja;
JSONObject jo;
String key;
Iterator<String> keys;
int length;
String string;
Object value;
if (object instanceof JSONObject) {
// Emit <tagName>
if (tagName != null) {
sb.append('<');
sb.append(tagName);
@ -398,7 +407,6 @@ public class XML {
}
// Loop thru the keys.
jo = (JSONObject) object;
keys = jo.keys();
while (keys.hasNext()) {
@ -406,20 +414,22 @@ public class XML {
value = jo.opt(key);
if (value == null) {
value = "";
} else if (value.getClass().isArray()) {
value = new JSONArray(value);
}
string = value instanceof String ? (String) value : null;
// Emit content in body
if ("content".equals(key)) {
if (value instanceof JSONArray) {
ja = (JSONArray) value;
length = ja.length();
for (i = 0; i < length; i += 1) {
int i = 0;
for (Object val : ja) {
if (i > 0) {
sb.append('\n');
}
sb.append(escape(ja.get(i).toString()));
sb.append(escape(val.toString()));
i++;
}
} else {
sb.append(escape(value.toString()));
@ -429,19 +439,17 @@ public class XML {
} else if (value instanceof JSONArray) {
ja = (JSONArray) value;
length = ja.length();
for (i = 0; i < length; i += 1) {
value = ja.get(i);
if (value instanceof JSONArray) {
for (Object val : ja) {
if (val instanceof JSONArray) {
sb.append('<');
sb.append(key);
sb.append('>');
sb.append(toString(value));
sb.append(toString(val));
sb.append("</");
sb.append(key);
sb.append('>');
} else {
sb.append(toString(value, key));
sb.append(toString(val, key));
}
}
} else if ("".equals(value)) {
@ -458,17 +466,14 @@ public class XML {
if (tagName != null) {
// Emit the </tagname> close tag
sb.append("</");
sb.append(tagName);
sb.append('>');
}
return sb.toString();
// XML does not have good support for arrays. If an array appears in a place
// where XML is lacking, synthesize an <array> element.
}
if (object != null) {
if (object.getClass().isArray()) {
object = new JSONArray(object);
@ -476,17 +481,20 @@ public class XML {
if (object instanceof JSONArray) {
ja = (JSONArray) object;
length = ja.length();
for (i = 0; i < length; i += 1) {
sb.append(toString(ja.opt(i), tagName == null ? "array" : tagName));
for (Object val : ja) {
// XML does not have good support for arrays. If an array
// appears in a place where XML is lacking, synthesize an
// <array> element.
sb.append(toString(val, tagName == null ? "array" : tagName));
}
return sb.toString();
}
}
string = (object == null) ? "null" : escape(object.toString());
return (tagName == null) ? "\"" + string + "\"" :
(string.length() == 0) ? "<" + tagName + "/>" :
"<" + tagName + ">" + string + "</" + tagName + ">";
return (tagName == null) ? "\"" + string + "\""
: (string.length() == 0) ? "<" + tagName + "/>" : "<" + tagName
+ ">" + string + "</" + tagName + ">";
}
}