Looly 5 years ago
parent
commit
7e8096a75c

+ 1 - 0
CHANGELOG.md

@@ -13,6 +13,7 @@
 * 【core   】     增加XmlUtil.setNamespaceAware,getByPath支持UniversalNamespaceCache
 * 【core   】     增加XmlUtil.setNamespaceAware,getByPath支持UniversalNamespaceCache
 * 【aop    】     增加Spring-cglib支持,改为SPI实现
+* 【json   】     增加JSONUtil.parseXXX增加JSONConfig参数
 
 ### Bug修复
 * 【json   】     修复解析JSON字符串时配置无法传递问题

+ 1 - 2
hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java

@@ -188,8 +188,7 @@ final class InternalJSONUtil {
 	 * @return JSONObject
 	 */
 	protected static JSONObject propertyPut(JSONObject jsonObject, Object key, Object value) {
-		String keyStr = Convert.toStr(key);
-		String[] path = StrUtil.split(keyStr, StrUtil.DOT);
+		final String[] path = StrUtil.split(Convert.toStr(key), StrUtil.DOT);
 		int last = path.length - 1;
 		JSONObject target = jsonObject;
 		for (int i = 0; i < last; i += 1) {

+ 3 - 3
hutool-json/src/main/java/cn/hutool/json/JSON.java

@@ -1,13 +1,13 @@
 package cn.hutool.json;
 
+import cn.hutool.core.bean.BeanPath;
+import cn.hutool.core.lang.TypeReference;
+
 import java.io.Serializable;
 import java.io.StringWriter;
 import java.io.Writer;
 import java.lang.reflect.Type;
 
-import cn.hutool.core.bean.BeanPath;
-import cn.hutool.core.lang.TypeReference;
-
 /**
  * JSON接口
  *

+ 98 - 64
hutool-json/src/main/java/cn/hutool/json/JSONObject.java

@@ -23,32 +23,41 @@ import java.lang.reflect.Method;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.Collection;
+import java.util.Enumeration;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.ResourceBundle;
 import java.util.Set;
 
 /**
  * JSON对象<br>
  * 例:<br>
- * 
+ *
  * <pre>
  * json = new JSONObject().put(&quot;JSON&quot;, &quot;Hello, World!&quot;).toString();
  * </pre>
- * 
+ *
  * @author looly
  */
 public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object> {
 	private static final long serialVersionUID = -330220388580734346L;
 
-	/** 默认初始大小 */
-	public static final int DEFAULT_CAPACITY = 16;
+	/**
+	 * 默认初始大小
+	 */
+	public static final int DEFAULT_CAPACITY = MapUtil.DEFAULT_INITIAL_CAPACITY;
 
-	/** JSON的KV持有Map */
+	/**
+	 * JSON的KV持有Map
+	 */
 	private final Map<String, Object> rawHashMap;
-	/** 配置项 */
+	/**
+	 * 配置项
+	 */
 	private final JSONConfig config;
 
 	// -------------------------------------------------------------------------------------------------------------------- Constructor start
+
 	/**
 	 * 构造,初始容量为 {@link #DEFAULT_CAPACITY},KEY无序
 	 */
@@ -58,7 +67,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 
 	/**
 	 * 构造,初始容量为 {@link #DEFAULT_CAPACITY}
-	 * 
+	 *
 	 * @param isOrder 是否有序
 	 * @since 3.0.9
 	 */
@@ -68,9 +77,9 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 
 	/**
 	 * 构造
-	 * 
+	 *
 	 * @param capacity 初始大小
-	 * @param isOrder 是否有序
+	 * @param isOrder  是否有序
 	 * @since 3.0.9
 	 */
 	public JSONObject(int capacity, boolean isOrder) {
@@ -79,19 +88,19 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 
 	/**
 	 * 构造
-	 * 
-	 * @param capacity 初始大小
+	 *
+	 * @param capacity     初始大小
 	 * @param isIgnoreCase 是否忽略KEY大小写
-	 * @param isOrder 是否有序
+	 * @param isOrder      是否有序
 	 * @since 3.3.1
 	 */
 	public JSONObject(int capacity, boolean isIgnoreCase, boolean isOrder) {
 		this(capacity, JSONConfig.create().setIgnoreCase(isIgnoreCase).setOrder(isOrder));
 	}
-	
+
 	/**
 	 * 构造
-	 * 
+	 *
 	 * @param config JSON配置项
 	 * @since 4.6.5
 	 */
@@ -101,13 +110,13 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 
 	/**
 	 * 构造
-	 * 
+	 *
 	 * @param capacity 初始大小
-	 * @param config JSON配置项,null表示默认配置
+	 * @param config   JSON配置项,null表示默认配置
 	 * @since 4.1.19
 	 */
 	public JSONObject(int capacity, JSONConfig config) {
-		if(null == config){
+		if (null == config) {
 			config = JSONConfig.create();
 		}
 		if (config.isIgnoreCase()) {
@@ -127,7 +136,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 	 * <li>value为普通JavaBean,如果为普通的JavaBean,调用其getters方法(getXXX或者isXXX)获得值,加入到JSON对象。
 	 * 例如:如果JavaBean对象中有个方法getName(),值为"张三",获得的键值对为:name: "张三"</li>
 	 * </ol>
-	 * 
+	 *
 	 * @param source JavaBean或者Map对象或者String
 	 */
 	public JSONObject(Object source) {
@@ -142,8 +151,8 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 	 * <li>value为JSONTokener,直接解析</li>
 	 * <li>value为普通JavaBean,如果为普通的JavaBean,调用其getters方法(getXXX或者isXXX)获得值,加入到JSON对象。例如:如果JavaBean对象中有个方法getName(),值为"张三",获得的键值对为:name: "张三"</li>
 	 * </ol>
-	 * 
-	 * @param source JavaBean或者Map对象或者String
+	 *
+	 * @param source          JavaBean或者Map对象或者String
 	 * @param ignoreNullValue 是否忽略空值
 	 * @since 3.0.9
 	 */
@@ -159,10 +168,10 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 	 * <li>value为JSONTokener,直接解析</li>
 	 * <li>value为普通JavaBean,如果为普通的JavaBean,调用其getters方法(getXXX或者isXXX)获得值,加入到JSON对象。例如:如果JavaBean对象中有个方法getName(),值为"张三",获得的键值对为:name: "张三"</li>
 	 * </ol>
-	 * 
-	 * @param source JavaBean或者Map对象或者String
+	 *
+	 * @param source          JavaBean或者Map对象或者String
 	 * @param ignoreNullValue 是否忽略空值,如果source为JSON字符串,不忽略空值
-	 * @param isOrder 是否有序
+	 * @param isOrder         是否有序
 	 * @since 4.2.2
 	 */
 	public JSONObject(Object source, boolean ignoreNullValue, boolean isOrder) {
@@ -179,11 +188,11 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 	 * <li>value为JSONTokener,直接解析</li>
 	 * <li>value为普通JavaBean,如果为普通的JavaBean,调用其getters方法(getXXX或者isXXX)获得值,加入到JSON对象。例如:如果JavaBean对象中有个方法getName(),值为"张三",获得的键值对为:name: "张三"</li>
 	 * </ol>
-	 * 
+	 * <p>
 	 * 如果给定值为Map,将键值对加入JSON对象;<br>
 	 * 如果为普通的JavaBean,调用其getters方法(getXXX或者isXXX)获得值,加入到JSON对象<br>
 	 * 例如:如果JavaBean对象中有个方法getName(),值为"张三",获得的键值对为:name: "张三"
-	 * 
+	 *
 	 * @param source JavaBean或者Map对象或者String
 	 * @param config JSON配置文件
 	 * @since 4.2.2
@@ -195,16 +204,16 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 
 	/**
 	 * 构建指定name列表对应的键值对为新的JSONObject,情况如下:
-	 * 
+	 *
 	 * <pre>
 	 * 1. 若obj为Map,则获取name列表对应键值对
 	 * 2. 若obj为普通Bean,使用反射方式获取字段名和字段值
 	 * </pre>
-	 * 
+	 * <p>
 	 * KEY或VALUE任意一个为null则不加入,字段不存在也不加入<br>
 	 * 若names列表为空,则字段全部加入
 	 *
-	 * @param obj 包含需要字段的Bean对象或者Map对象
+	 * @param obj   包含需要字段的Bean对象或者Map对象
 	 * @param names 需要构建JSONObject的字段名列表
 	 */
 	public JSONObject(Object obj, String... names) {
@@ -234,9 +243,9 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 	/**
 	 * 从JSON字符串解析为JSON对象,对于排序单独配置参数
 	 *
-	 * @param source 以大括号 {} 包围的字符串,其中KEY和VALUE使用 : 分隔,每个键值对使用逗号分隔
+	 * @param source  以大括号 {} 包围的字符串,其中KEY和VALUE使用 : 分隔,每个键值对使用逗号分隔
 	 * @param isOrder 是否有序
-	 * @exception JSONException JSON字符串语法错误
+	 * @throws JSONException JSON字符串语法错误
 	 * @since 4.2.2
 	 */
 	public JSONObject(CharSequence source, boolean isOrder) throws JSONException {
@@ -252,7 +261,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 
 	/**
 	 * 设置转为字符串时的日期格式,默认为时间戳(null值)
-	 * 
+	 *
 	 * @param format 格式,null表示使用时间戳
 	 * @return this
 	 * @since 4.1.19
@@ -333,7 +342,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 	/**
 	 * PUT 键值对到JSONObject中,在忽略null模式下,如果值为<code>null</code>,将此键移除
 	 *
-	 * @param key 键
+	 * @param key   
 	 * @param value 值对象. 可以是以下类型: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
 	 * @return this.
 	 * @throws JSONException 值是无穷数字抛出此异常
@@ -360,7 +369,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 	/**
 	 * 设置键值对到JSONObject中,在忽略null模式下,如果值为<code>null</code>,将此键移除
 	 *
-	 * @param key 键
+	 * @param key   
 	 * @param value 值对象. 可以是以下类型: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
 	 * @return this.
 	 * @throws JSONException 值是无穷数字抛出此异常
@@ -373,7 +382,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 	/**
 	 * 一次性Put 键值对,如果key已经存在抛出异常,如果键值中有null值,忽略
 	 *
-	 * @param key 键
+	 * @param key   
 	 * @param value 值对象,可以是以下类型: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
 	 * @return this.
 	 * @throws JSONException 值是无穷数字、键重复抛出异常
@@ -391,7 +400,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 	/**
 	 * 在键和值都为非空的情况下put到JSONObject中
 	 *
-	 * @param key 键
+	 * @param key   
 	 * @param value 值对象,可以是以下类型: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
 	 * @return this.
 	 * @throws JSONException 值是无穷数字
@@ -414,7 +423,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 	 * 积累值。类似于put,当key对应value已经存在时,与value组成新的JSONArray. <br>
 	 * 如果只有一个值,此值就是value,如果多个值,则是添加到新的JSONArray中
 	 *
-	 * @param key 键
+	 * @param key   
 	 * @param value 被积累的值
 	 * @return this.
 	 * @throws JSONException 如果给定键为<code>null</code>或者键对应的值存在且为非JSONArray
@@ -435,7 +444,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 	/**
 	 * 追加值,如果key无对应值,就添加一个JSONArray,其元素只有value,如果值已经是一个JSONArray,则添加到值JSONArray中。
 	 *
-	 * @param key 键
+	 * @param key   
 	 * @param value 值
 	 * @return this.
 	 * @throws JSONException 如果给定键为<code>null</code>或者键对应的值存在且为非JSONArray
@@ -559,12 +568,13 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 	}
 
 	// ------------------------------------------------------------------------------------------------- Private method start
+
 	/**
 	 * 将JSON内容写入Writer
-	 * 
-	 * @param writer writer
+	 *
+	 * @param writer       writer
 	 * @param indentFactor 缩进因子,定义每一级别增加的缩进量
-	 * @param indent 本级别缩进量
+	 * @param indent       本级别缩进量
 	 * @return Writer
 	 * @throws JSONException JSON相关异常
 	 */
@@ -610,7 +620,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 
 	/**
 	 * Bean对象转Map
-	 * 
+	 *
 	 * @param bean Bean对象
 	 */
 	private void populateMap(Object bean) {
@@ -654,7 +664,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 	 * <li>value为JSONTokener,直接解析</li>
 	 * <li>value为普通JavaBean,如果为普通的JavaBean,调用其getters方法(getXXX或者isXXX)获得值,加入到JSON对象。例如:如果JavaBean对象中有个方法getName(),值为"张三",获得的键值对为:name: "张三"</li>
 	 * </ol>
-	 * 
+	 *
 	 * @param source JavaBean或者Map对象或者String
 	 */
 	@SuppressWarnings({"rawtypes", "unchecked"})
@@ -662,9 +672,9 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 		if (null == source) {
 			return;
 		}
-		
+
 		final JSONSerializer serializer = GlobalSerializeMapping.getSerializer(source.getClass());
-		if(serializer instanceof JSONObjectSerializer) {
+		if (serializer instanceof JSONObjectSerializer) {
 			// 自定义序列化
 			serializer.serialize(this, source);
 		} else if (source instanceof Map) {
@@ -678,7 +688,10 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 		} else if (source instanceof JSONTokener) {
 			// JSONTokener
 			init((JSONTokener) source);
-		} else if(BeanUtil.isReadableBean(source.getClass())){
+		} else if (source instanceof ResourceBundle) {
+			// JSONTokener
+			init((ResourceBundle) source);
+		} else if (BeanUtil.isReadableBean(source.getClass())) {
 			// 普通Bean
 			this.populateMap(source);
 		}
@@ -686,16 +699,37 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 
 	/**
 	 * 初始化
-	 * 
+	 *
+	 * @param bundle ResourceBundle
+	 * @since 5.3.1
+	 */
+	private void init(ResourceBundle bundle) {
+		Enumeration<String> keys = bundle.getKeys();
+		while (keys.hasMoreElements()) {
+			String key = keys.nextElement();
+			if (key != null) {
+				InternalJSONUtil.propertyPut(this, key, bundle.getString(key));
+			}
+		}
+	}
+
+	/**
+	 * 初始化,可以判断字符串为JSON或者XML
+	 *
 	 * @param source JSON字符串
 	 */
 	private void init(CharSequence source) {
+		final String jsonStr = StrUtil.trim(source);
+		if (StrUtil.startWith(jsonStr, '<')) {
+			// 可能为XML
+			XML.toJSONObject(this, jsonStr, false);
+		}
 		init(new JSONTokener(StrUtil.trim(source), this.config));
 	}
 
 	/**
 	 * 初始化
-	 * 
+	 *
 	 * @param x JSONTokener
 	 */
 	private void init(JSONTokener x) {
@@ -708,13 +742,13 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 		while (true) {
 			c = x.nextClean();
 			switch (c) {
-			case 0:
-				throw x.syntaxError("A JSONObject text must end with '}'");
-			case '}':
-				return;
-			default:
-				x.back();
-				key = x.nextValue().toString();
+				case 0:
+					throw x.syntaxError("A JSONObject text must end with '}'");
+				case '}':
+					return;
+				default:
+					x.back();
+					key = x.nextValue().toString();
 			}
 
 			// The key is followed by ':'.
@@ -728,17 +762,17 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 			// Pairs are separated by ','.
 
 			switch (x.nextClean()) {
-			case ';':
-			case ',':
-				if (x.nextClean() == '}') {
+				case ';':
+				case ',':
+					if (x.nextClean() == '}') {
+						return;
+					}
+					x.back();
+					break;
+				case '}':
 					return;
-				}
-				x.back();
-				break;
-			case '}':
-				return;
-			default:
-				throw x.syntaxError("Expected a ',' or '}'");
+				default:
+					throw x.syntaxError("Expected a ',' or '}'");
 			}
 		}
 	}

+ 54 - 22
hutool-json/src/main/java/cn/hutool/json/JSONUtil.java

@@ -23,9 +23,8 @@ import java.lang.reflect.Type;
 import java.nio.charset.Charset;
 import java.time.temporal.TemporalAccessor;
 import java.util.Calendar;
-import java.util.Collection;
 import java.util.Date;
-import java.util.Enumeration;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.ResourceBundle;
@@ -101,6 +100,19 @@ public final class JSONUtil {
 	}
 
 	/**
+	 * JSON字符串转JSONObject对象<br>
+	 * 此方法会忽略空值,但是对JSON字符串不影响
+	 *
+	 * @param obj    Bean对象或者Map
+	 * @param config JSON配置
+	 * @return JSONObject
+	 * @since 5.3.1
+	 */
+	public static JSONObject parseObj(Object obj, JSONConfig config) {
+		return new JSONObject(obj, config);
+	}
+
+	/**
 	 * JSON字符串转JSONObject对象
 	 *
 	 * @param obj             Bean对象或者Map
@@ -150,6 +162,18 @@ public final class JSONUtil {
 	 * JSON字符串转JSONArray
 	 *
 	 * @param arrayOrCollection 数组或集合对象
+	 * @param config            JSON配置
+	 * @return JSONArray
+	 * @since 5.3.1
+	 */
+	public static JSONArray parseArray(Object arrayOrCollection, JSONConfig config) {
+		return new JSONArray(arrayOrCollection, config);
+	}
+
+	/**
+	 * JSON字符串转JSONArray
+	 *
+	 * @param arrayOrCollection 数组或集合对象
 	 * @param ignoreNullValue   是否忽略空值
 	 * @return JSONArray
 	 * @since 3.2.3
@@ -169,6 +193,22 @@ public final class JSONUtil {
 	 * @return JSON
 	 */
 	public static JSON parse(Object obj) {
+		return parse(obj, JSONConfig.create());
+	}
+
+	/**
+	 * 转换对象为JSON<br>
+	 * 支持的对象:<br>
+	 * String: 转换为相应的对象<br>
+	 * Array、Iterable、Iterator:转换为JSONArray<br>
+	 * Bean对象:转为JSONObject
+	 *
+	 * @param obj    对象
+	 * @param config JSON配置
+	 * @return JSON
+	 * @since 5.3.1
+	 */
+	public static JSON parse(Object obj, JSONConfig config) {
 		if (null == obj) {
 			return null;
 		}
@@ -176,17 +216,13 @@ public final class JSONUtil {
 		JSON json;
 		if (obj instanceof JSON) {
 			json = (JSON) obj;
-		} else if (obj instanceof String) {
-			String jsonStr = ((String) obj).trim();
-			if (jsonStr.startsWith("[")) {
-				json = parseArray(jsonStr);
-			} else {
-				json = parseObj(jsonStr);
-			}
-		} else if (obj instanceof Collection || obj.getClass().isArray()) {// 列表
-			json = new JSONArray(obj);
+		} else if (obj instanceof CharSequence) {
+			final String jsonStr = StrUtil.trim((CharSequence) obj);
+			json = StrUtil.startWith(jsonStr, '[') ? parseArray(jsonStr) : parseObj(jsonStr);
+		} else if (obj instanceof Iterable || obj instanceof Iterator || ArrayUtil.isArray(obj)) {// 列表
+			json = new JSONArray(obj, config);
 		} else {// 对象
-			json = new JSONObject(obj);
+			json = new JSONObject(obj, config);
 		}
 
 		return json;
@@ -206,8 +242,10 @@ public final class JSONUtil {
 	 * Map转化为JSONObject
 	 *
 	 * @param map {@link Map}
-	 * @return JSONObject
+	 * @return JSONObjec
+	 * @deprecated 请直接使用 {@link #parseObj(Object)}
 	 */
+	@Deprecated
 	public static JSONObject parseFromMap(Map<?, ?> map) {
 		return new JSONObject(map);
 	}
@@ -217,17 +255,11 @@ public final class JSONUtil {
 	 *
 	 * @param bundle ResourceBundle文件
 	 * @return JSONObject
+	 * @deprecated 请直接使用 {@link #parseObj(Object)}
 	 */
+	@Deprecated
 	public static JSONObject parseFromResourceBundle(ResourceBundle bundle) {
-		JSONObject jsonObject = new JSONObject();
-		Enumeration<String> keys = bundle.getKeys();
-		while (keys.hasMoreElements()) {
-			String key = keys.nextElement();
-			if (key != null) {
-				InternalJSONUtil.propertyPut(jsonObject, key, bundle.getString(key));
-			}
-		}
-		return jsonObject;
+		return new JSONObject(bundle);
 	}
 	// -------------------------------------------------------------------- Pause end
 

+ 85 - 53
hutool-json/src/main/java/cn/hutool/json/XML.java

@@ -9,44 +9,109 @@ import java.util.Iterator;
 
 /**
  * 提供静态方法在XML和JSONObject之间转换
- * 
+ *
  * @author JSON.org
  */
 public class XML {
 
-	/** The Character '&amp;'. */
+	/**
+	 * The Character '&amp;'.
+	 */
 	public static final Character AMP = CharUtil.AMP;
 
-	/** The Character '''. */
+	/**
+	 * The Character '''.
+	 */
 	public static final Character APOS = CharUtil.SINGLE_QUOTE;
 
-	/** The Character '!'. */
+	/**
+	 * The Character '!'.
+	 */
 	public static final Character BANG = '!';
 
-	/** The Character '='. */
+	/**
+	 * The Character '='.
+	 */
 	public static final Character EQ = '=';
 
-	/** The Character '&gt;'. */
+	/**
+	 * The Character '&gt;'.
+	 */
 	public static final Character GT = '>';
 
-	/** The Character '&lt;'. */
+	/**
+	 * The Character '&lt;'.
+	 */
 	public static final Character LT = '<';
 
-	/** The Character '?'. */
+	/**
+	 * The Character '?'.
+	 */
 	public static final Character QUEST = '?';
 
-	/** The Character '"'. */
+	/**
+	 * The Character '"'.
+	 */
 	public static final Character QUOT = CharUtil.DOUBLE_QUOTES;
 
-	/** The Character '/'. */
+	/**
+	 * The Character '/'.
+	 */
 	public static final Character SLASH = CharUtil.SLASH;
 
 	/**
+	 * 转换XML为JSONObject
+	 * 转换过程中一些信息可能会丢失,JSON中无法区分节点和属性,相同的节点将被处理为JSONArray。
+	 * Content text may be placed in a "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]&gt;</code> are ignored.
+	 *
+	 * @param string The source string.
+	 * @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) throws JSONException {
+		return toJSONObject(string, false);
+	}
+
+	/**
+	 * 转换XML为JSONObject
+	 * 转换过程中一些信息可能会丢失,JSON中无法区分节点和属性,相同的节点将被处理为JSONArray。
+	 * Content text may be placed in a "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]&gt;</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 {
+		return toJSONObject(new JSONObject(), string, keepStrings);
+	}
+
+	/**
+	 * 转换XML为JSONObject
+	 * 转换过程中一些信息可能会丢失,JSON中无法区分节点和属性,相同的节点将被处理为JSONArray。
+	 *
+	 * @param jo          JSONObject
+	 * @param string      XML字符串
+	 * @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
+	 * @since 5.3.1
+	 */
+	public static JSONObject toJSONObject(JSONObject jo, String string, boolean keepStrings) throws JSONException {
+		XMLTokener x = new XMLTokener(string, jo.getConfig());
+		while (x.more() && x.skipPast("<")) {
+			parse(x, jo, null, keepStrings);
+		}
+		return jo;
+	}
+
+	/**
 	 * Scan the content following the named tag, attaching it to the context.
-	 * 
-	 * @param x The XMLTokener containing the source string.
+	 *
+	 * @param x       The XMLTokener containing the source string.
 	 * @param context The JSONObject that will include the new material.
-	 * @param name The tag name.
+	 * @param name    The tag name.
 	 * @return true if the close tag is processed.
 	 * @throws JSONException JSON异常
 	 */
@@ -135,7 +200,7 @@ public class XML {
 			tagName = (String) token;
 			token = null;
 			jsonobject = new JSONObject();
-			for (;;) {
+			for (; ; ) {
 				if (token == null) {
 					token = x.nextToken();
 				}
@@ -169,7 +234,7 @@ public class XML {
 
 				} else if (token == GT) {
 					// Content, between <...> and </...>
-					for (;;) {
+					for (; ; ) {
 						token = x.nextContent();
 						if (token == null) {
 							if (tagName != null) {
@@ -204,42 +269,9 @@ public class XML {
 	}
 
 	/**
-	 * 转换XML为JSONObject
-	 * 转换过程中一些信息可能会丢失,JSON中无法区分节点和属性,相同的节点将被处理为JSONArray。
-	 * Content text may be placed in a "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]&gt;</code> are ignored.
-	 * 
-	 * @param string The source string.
-	 * @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) throws JSONException {
-		return toJSONObject(string, false);
-	}
-
-	/**
-	 * 转换XML为JSONObject
-	 * 转换过程中一些信息可能会丢失,JSON中无法区分节点和属性,相同的节点将被处理为JSONArray。
-	 * Content text may be placed in a "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]&gt;</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, jo.getConfig());
-		while (x.more() && x.skipPast("<")) {
-			parse(x, jo, null, keepStrings);
-		}
-		return jo;
-	}
-
-	/**
 	 * 转换JSONObject为XML
 	 * Convert a JSONObject into a well-formed, element-normal XML string.
-	 * 
+	 *
 	 * @param object A JSONObject.
 	 * @return A string.
 	 * @throws JSONException Thrown if there is an error parsing the string
@@ -251,17 +283,17 @@ public class XML {
 	/**
 	 * 转换JSONObject为XML
 	 * Convert a JSONObject into a well-formed, element-normal XML string.
-	 * 
-	 * @param object A JSONObject.
+	 *
+	 * @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 toXml(Object object, String tagName) throws JSONException {
-		if(null == object) {
+		if (null == object) {
 			return null;
 		}
-		
+
 		StringBuilder sb = new StringBuilder();
 		JSONArray ja;
 		JSONObject jo;