diff --git a/XML.java b/XML.java
index 55362b274..73090fc98 100644
--- a/XML.java
+++ b/XML.java
@@ -37,6 +37,7 @@ of this software and associated documentation files (the "Software"), to deal
*/
@SuppressWarnings("boxing")
public class XML {
+
/** The Character '&'. */
public static final Character AMP = '&';
@@ -241,7 +242,7 @@ public static void noSpace(String string) throws JSONException {
* @return true if the close tag is processed.
* @throws JSONException
*/
- private static boolean parse(XMLTokener x, JSONObject context, String name, boolean keepStrings)
+ private static boolean parse(XMLTokener x, JSONObject context, String name, XMLParserConfiguration config)
throws JSONException {
char c;
int i;
@@ -278,7 +279,7 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, bool
if (x.next() == '[') {
string = x.nextCDATA();
if (string.length() > 0) {
- context.accumulate("content", string);
+ context.accumulate(config.cDataTagName, string);
}
return false;
}
@@ -341,7 +342,7 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, bool
throw x.syntaxError("Missing value");
}
jsonobject.accumulate(string,
- keepStrings ? ((String)token) : stringToValue((String) token));
+ config.keepStrings ? ((String)token) : stringToValue((String) token));
token = null;
} else {
jsonobject.accumulate(string, "");
@@ -372,19 +373,19 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, bool
} else if (token instanceof String) {
string = (String) token;
if (string.length() > 0) {
- jsonobject.accumulate("content",
- keepStrings ? string : stringToValue(string));
+ jsonobject.accumulate(config.cDataTagName,
+ config.keepStrings ? string : stringToValue(string));
}
} else if (token == LT) {
// Nested element
- if (parse(x, jsonobject, tagName,keepStrings)) {
+ if (parse(x, jsonobject, tagName, config)) {
if (jsonobject.length() == 0) {
context.accumulate(tagName, "");
} else if (jsonobject.length() == 1
- && jsonobject.opt("content") != null) {
+ && jsonobject.opt(config.cDataTagName) != null) {
context.accumulate(tagName,
- jsonobject.opt("content"));
+ jsonobject.opt(config.cDataTagName));
} else {
context.accumulate(tagName, jsonobject);
}
@@ -469,7 +470,7 @@ public static Object stringToValue(String string) {
* @throws JSONException Thrown if there is an errors while parsing the string
*/
public static JSONObject toJSONObject(String string) throws JSONException {
- return toJSONObject(string, false);
+ return toJSONObject(string, XMLParserConfiguration.ORIGINAL);
}
/**
@@ -488,7 +489,7 @@ public static JSONObject toJSONObject(String string) throws JSONException {
* @throws JSONException Thrown if there is an errors while parsing the string
*/
public static JSONObject toJSONObject(Reader reader) throws JSONException {
- return toJSONObject(reader, false);
+ return toJSONObject(reader, XMLParserConfiguration.ORIGINAL);
}
/**
@@ -512,12 +513,38 @@ public static JSONObject toJSONObject(Reader reader) throws JSONException {
* @throws JSONException Thrown if there is an errors while parsing the string
*/
public static JSONObject toJSONObject(Reader reader, boolean keepStrings) throws JSONException {
+ if(keepStrings) {
+ return toJSONObject(reader, XMLParserConfiguration.KEEP_STRINGS);
+ }
+ return toJSONObject(reader, XMLParserConfiguration.ORIGINAL);
+ }
+
+ /**
+ * Convert a well-formed (but not necessarily valid) XML 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 <[ [ ]]>
+ * 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 reader The XML source reader.
+ * @param config Configuration options for the parser
+ * @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(Reader reader, XMLParserConfiguration config) throws JSONException {
JSONObject jo = new JSONObject();
XMLTokener x = new XMLTokener(reader);
while (x.more()) {
x.skipPast("<");
if(x.more()) {
- parse(x, jo, null, keepStrings);
+ parse(x, jo, null, config);
}
}
return jo;
@@ -548,6 +575,30 @@ public static JSONObject toJSONObject(String string, boolean keepStrings) throws
return toJSONObject(new StringReader(string), keepStrings);
}
+ /**
+ * 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 <[ [ ]]>
+ * 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 config Configuration options for the parser.
+ * @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, XMLParserConfiguration config) throws JSONException {
+ return toJSONObject(new StringReader(string), config);
+ }
+
/**
* Convert a JSONObject into a well-formed, element-normal XML string.
*
@@ -557,7 +608,21 @@ public static JSONObject toJSONObject(String string, boolean keepStrings) throws
* @throws JSONException Thrown if there is an error parsing the string
*/
public static String toString(Object object) throws JSONException {
- return toString(object, null);
+ return toString(object, null, XMLParserConfiguration.ORIGINAL);
+ }
+
+ /**
+ * Convert a JSONObject into a well-formed, element-normal XML string.
+ *
+ * @param object
+ * A JSONObject.
+ * @param tagName
+ * The optional name of the enclosing tag.
+ * @return A string.
+ * @throws JSONException Thrown if there is an error parsing the string
+ */
+ public static String toString(final Object object, final String tagName) {
+ return toString(object, tagName, XMLParserConfiguration.ORIGINAL);
}
/**
@@ -567,10 +632,12 @@ public static String toString(Object object) throws JSONException {
* A JSONObject.
* @param tagName
* The optional name of the enclosing tag.
+ * @param config
+ * Configuration that can control output to XML.
* @return A string.
* @throws JSONException Thrown if there is an error parsing the string
*/
- public static String toString(final Object object, final String tagName)
+ public static String toString(final Object object, final String tagName, final XMLParserConfiguration config)
throws JSONException {
StringBuilder sb = new StringBuilder();
JSONArray ja;
@@ -598,7 +665,7 @@ public static String toString(final Object object, final String tagName)
}
// Emit content in body
- if ("content".equals(key)) {
+ if (key.equals(config.cDataTagName)) {
if (value instanceof JSONArray) {
ja = (JSONArray) value;
int jaLength = ja.length();
@@ -626,12 +693,12 @@ public static String toString(final Object object, final String tagName)
sb.append('<');
sb.append(key);
sb.append('>');
- sb.append(toString(val));
+ sb.append(toString(val, null, config));
sb.append("");
sb.append(key);
sb.append('>');
} else {
- sb.append(toString(val, key));
+ sb.append(toString(val, key, config));
}
}
} else if ("".equals(value)) {
@@ -642,7 +709,7 @@ public static String toString(final Object object, final String tagName)
// Emit a new tag
} else {
- sb.append(toString(value, key));
+ sb.append(toString(value, key, config));
}
}
if (tagName != null) {
@@ -669,7 +736,7 @@ public static String toString(final Object object, final String tagName)
// XML does not have good support for arrays. If an array
// appears in a place where XML is lacking, synthesize an
// element.
- sb.append(toString(val, tagName == null ? "array" : tagName));
+ sb.append(toString(val, tagName == null ? "array" : tagName, config));
}
return sb.toString();
}
diff --git a/XMLParserConfiguration.java b/XMLParserConfiguration.java
new file mode 100644
index 000000000..f1f001bc4
--- /dev/null
+++ b/XMLParserConfiguration.java
@@ -0,0 +1,86 @@
+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.
+*/
+
+/**
+ * Configuration object for the XML parser.
+ * @author AylwardJ
+ *
+ */
+public class XMLParserConfiguration {
+ /** Original Configuration of the XML Parser. */
+ public static final XMLParserConfiguration ORIGINAL = new XMLParserConfiguration();
+ /** Original configuration of the XML Parser except that values are kept as strings. */
+ public static final XMLParserConfiguration KEEP_STRINGS = new XMLParserConfiguration(true);
+ /**
+ * When parsing the XML into JSON, specifies if values should be kept as strings (true), or if
+ * they should try to be guessed into JSON values (numeric, boolean, string)
+ */
+ public final boolean keepStrings;
+ /**
+ * The name of the key in a JSON Ojbect that indicates a CDATA section. Historically this has
+ * been the value "content" but can be changed. Use null
to indicate no CDATA
+ * processing.
+ */
+ public final String cDataTagName;
+
+ /**
+ * Default parser configuration. Does not keep strings, and the CDATA Tag Name is "content".
+ */
+ public XMLParserConfiguration () {
+ this(false, "content");
+ }
+
+ /**
+ * Configure the parser string processing and use the default CDATA Tag Name as "content".
+ * @param keepStrings true
to parse all values as string.
+ * false
to try and convert XML string values into a JSON value.
+ */
+ public XMLParserConfiguration (final boolean keepStrings) {
+ this(keepStrings, "content");
+ }
+
+ /**
+ * Configure the parser string processing to try and convert XML values to JSON values and
+ * use the passed CDATA Tag Name the processing value. Pass null
to
+ * disable CDATA processing
+ * @param cDataTagNamenull
to disable CDATA processing. Any other value
+ * to use that value as the JSONObject key name to process as CDATA.
+ */
+ public XMLParserConfiguration (final String cDataTagName) {
+ this(false, cDataTagName);
+ }
+
+ /**
+ * Configure the parser to use custom settings.
+ * @param keepStrings true
to parse all values as string.
+ * false
to try and convert XML string values into a JSON value.
+ * @param cDataTagNamenull
to disable CDATA processing. Any other value
+ * to use that value as the JSONObject key name to process as CDATA.
+ */
+ public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName) {
+ this.keepStrings = keepStrings;
+ this.cDataTagName = cDataTagName;
+ }
+}