@@ -27,7 +27,32 @@ private static Object parse(
2727 XMLTokener x ,
2828 boolean arrayForm ,
2929 JSONArray ja ,
30- boolean keepStrings
30+ boolean keepStrings ,
31+ int currentNestingDepth
32+ ) throws JSONException {
33+ return parse (x ,arrayForm , ja ,
34+ keepStrings ? JSONMLParserConfiguration .KEEP_STRINGS : JSONMLParserConfiguration .ORIGINAL ,
35+ currentNestingDepth );
36+ }
37+
38+ /**
39+ * Parse XML values and store them in a JSONArray.
40+ * @param x The XMLTokener containing the source string.
41+ * @param arrayForm true if array form, false if object form.
42+ * @param ja The JSONArray that is containing the current tag or null
43+ * if we are at the outermost level.
44+ * @param config The parser configuration:
45+ * JSONMLParserConfiguration.ORIGINAL is the default behaviour;
46+ * JSONMLParserConfiguration.KEEP_STRINGS means Don't type-convert text nodes and attribute values.
47+ * @return A JSONArray if the value is the outermost tag, otherwise null.
48+ * @throws JSONException if a parsing error occurs
49+ */
50+ private static Object parse (
51+ XMLTokener x ,
52+ boolean arrayForm ,
53+ JSONArray ja ,
54+ JSONMLParserConfiguration config ,
55+ int currentNestingDepth
3156 ) throws JSONException {
3257 String attribute ;
3358 char c ;
@@ -152,7 +177,7 @@ private static Object parse(
152177 if (!(token instanceof String )) {
153178 throw x .syntaxError ("Missing value" );
154179 }
155- newjo .accumulate (attribute , keepStrings ? ((String )token ) :XML .stringToValue ((String )token ));
180+ newjo .accumulate (attribute , config . isKeepStrings () ? ((String )token ) :XML .stringToValue ((String )token ));
156181 token = null ;
157182 } else {
158183 newjo .accumulate (attribute , "" );
@@ -181,7 +206,12 @@ private static Object parse(
181206 if (token != XML .GT ) {
182207 throw x .syntaxError ("Misshaped tag" );
183208 }
184- closeTag = (String )parse (x , arrayForm , newja , keepStrings );
209+
210+ if (currentNestingDepth == config .getMaxNestingDepth ()) {
211+ throw x .syntaxError ("Maximum nesting depth of " + config .getMaxNestingDepth () + " reached" );
212+ }
213+
214+ closeTag = (String )parse (x , arrayForm , newja , config , currentNestingDepth + 1 );
185215 if (closeTag != null ) {
186216 if (!closeTag .equals (tagName )) {
187217 throw x .syntaxError ("Mismatched '" + tagName +
@@ -203,7 +233,7 @@ private static Object parse(
203233 } else {
204234 if (ja != null ) {
205235 ja .put (token instanceof String
206- ? keepStrings ? XML .unescape ((String )token ) :XML .stringToValue ((String )token )
236+ ? ( config . isKeepStrings () ? XML .unescape ((String )token ) : XML .stringToValue ((String )token ) )
207237 : token );
208238 }
209239 }
@@ -224,7 +254,7 @@ private static Object parse(
224254 * @throws JSONException Thrown on error converting to a JSONArray
225255 */
226256 public static JSONArray toJSONArray (String string ) throws JSONException {
227- return (JSONArray )parse (new XMLTokener (string ), true , null , false );
257+ return (JSONArray )parse (new XMLTokener (string ), true , null , JSONMLParserConfiguration . ORIGINAL , 0 );
228258 }
229259
230260
@@ -235,8 +265,8 @@ public static JSONArray toJSONArray(String string) throws JSONException {
235265 * attributes, then the second element will be JSONObject containing the
236266 * name/value pairs. If the tag contains children, then strings and
237267 * JSONArrays will represent the child tags.
238- * As opposed to toJSONArray this method does not attempt to convert
239- * any text node or attribute value to any type
268+ * As opposed to toJSONArray this method does not attempt to convert
269+ * any text node or attribute value to any type
240270 * but just leaves it as a string.
241271 * Comments, prologs, DTDs, and <pre>{@code <[ [ ]]>}</pre> are ignored.
242272 * @param string The source string.
@@ -246,7 +276,56 @@ public static JSONArray toJSONArray(String string) throws JSONException {
246276 * @throws JSONException Thrown on error converting to a JSONArray
247277 */
248278 public static JSONArray toJSONArray (String string , boolean keepStrings ) throws JSONException {
249- return (JSONArray )parse (new XMLTokener (string ), true , null , keepStrings );
279+ return (JSONArray )parse (new XMLTokener (string ), true , null , keepStrings , 0 );
280+ }
281+
282+
283+
284+ /**
285+ * Convert a well-formed (but not necessarily valid) XML string into a
286+ * JSONArray using the JsonML transform. Each XML tag is represented as
287+ * a JSONArray in which the first element is the tag name. If the tag has
288+ * attributes, then the second element will be JSONObject containing the
289+ * name/value pairs. If the tag contains children, then strings and
290+ * JSONArrays will represent the child tags.
291+ * As opposed to toJSONArray this method does not attempt to convert
292+ * any text node or attribute value to any type
293+ * but just leaves it as a string.
294+ * Comments, prologs, DTDs, and <pre>{@code <[ [ ]]>}</pre> are ignored.
295+ * @param string The source string.
296+ * @param config The parser configuration:
297+ * JSONMLParserConfiguration.ORIGINAL is the default behaviour;
298+ * JSONMLParserConfiguration.KEEP_STRINGS means values will not be coerced into boolean
299+ * or numeric values and will instead be left as strings
300+ * @return A JSONArray containing the structured data from the XML string.
301+ * @throws JSONException Thrown on error converting to a JSONArray
302+ */
303+ public static JSONArray toJSONArray (String string , JSONMLParserConfiguration config ) throws JSONException {
304+ return (JSONArray )parse (new XMLTokener (string ), true , null , config , 0 );
305+ }
306+
307+
308+ /**
309+ * Convert a well-formed (but not necessarily valid) XML string into a
310+ * JSONArray using the JsonML transform. Each XML tag is represented as
311+ * a JSONArray in which the first element is the tag name. If the tag has
312+ * attributes, then the second element will be JSONObject containing the
313+ * name/value pairs. If the tag contains children, then strings and
314+ * JSONArrays will represent the child content and tags.
315+ * As opposed to toJSONArray this method does not attempt to convert
316+ * any text node or attribute value to any type
317+ * but just leaves it as a string.
318+ * Comments, prologs, DTDs, and <pre>{@code <[ [ ]]>}</pre> are ignored.
319+ * @param x An XMLTokener.
320+ * @param config The parser configuration:
321+ * JSONMLParserConfiguration.ORIGINAL is the default behaviour;
322+ * JSONMLParserConfiguration.KEEP_STRINGS means values will not be coerced into boolean
323+ * or numeric values and will instead be left as strings
324+ * @return A JSONArray containing the structured data from the XML string.
325+ * @throws JSONException Thrown on error converting to a JSONArray
326+ */
327+ public static JSONArray toJSONArray (XMLTokener x , JSONMLParserConfiguration config ) throws JSONException {
328+ return (JSONArray )parse (x , true , null , config , 0 );
250329 }
251330
252331
@@ -257,8 +336,8 @@ public static JSONArray toJSONArray(String string, boolean keepStrings) throws J
257336 * attributes, then the second element will be JSONObject containing the
258337 * name/value pairs. If the tag contains children, then strings and
259338 * JSONArrays will represent the child content and tags.
260- * As opposed to toJSONArray this method does not attempt to convert
261- * any text node or attribute value to any type
339+ * As opposed to toJSONArray this method does not attempt to convert
340+ * any text node or attribute value to any type
262341 * but just leaves it as a string.
263342 * Comments, prologs, DTDs, and <pre>{@code <[ [ ]]>}</pre> are ignored.
264343 * @param x An XMLTokener.
@@ -268,7 +347,7 @@ public static JSONArray toJSONArray(String string, boolean keepStrings) throws J
268347 * @throws JSONException Thrown on error converting to a JSONArray
269348 */
270349 public static JSONArray toJSONArray (XMLTokener x , boolean keepStrings ) throws JSONException {
271- return (JSONArray )parse (x , true , null , keepStrings );
350+ return (JSONArray )parse (x , true , null , keepStrings , 0 );
272351 }
273352
274353
@@ -285,7 +364,7 @@ public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JS
285364 * @throws JSONException Thrown on error converting to a JSONArray
286365 */
287366 public static JSONArray toJSONArray (XMLTokener x ) throws JSONException {
288- return (JSONArray )parse (x , true , null , false );
367+ return (JSONArray )parse (x , true , null , false , 0 );
289368 }
290369
291370
@@ -303,10 +382,10 @@ public static JSONArray toJSONArray(XMLTokener x) throws JSONException {
303382 * @throws JSONException Thrown on error converting to a JSONObject
304383 */
305384 public static JSONObject toJSONObject (String string ) throws JSONException {
306- return (JSONObject )parse (new XMLTokener (string ), false , null , false );
385+ return (JSONObject )parse (new XMLTokener (string ), false , null , false , 0 );
307386 }
308-
309-
387+
388+
310389 /**
311390 * Convert a well-formed (but not necessarily valid) XML string into a
312391 * JSONObject using the JsonML transform. Each XML tag is represented as
@@ -323,10 +402,32 @@ public static JSONObject toJSONObject(String string) throws JSONException {
323402 * @throws JSONException Thrown on error converting to a JSONObject
324403 */
325404 public static JSONObject toJSONObject (String string , boolean keepStrings ) throws JSONException {
326- return (JSONObject )parse (new XMLTokener (string ), false , null , keepStrings );
405+ return (JSONObject )parse (new XMLTokener (string ), false , null , keepStrings , 0 );
406+ }
407+
408+
409+ /**
410+ * Convert a well-formed (but not necessarily valid) XML string into a
411+ * JSONObject using the JsonML transform. Each XML tag is represented as
412+ * a JSONObject with a "tagName" property. If the tag has attributes, then
413+ * the attributes will be in the JSONObject as properties. If the tag
414+ * contains children, the object will have a "childNodes" property which
415+ * will be an array of strings and JsonML JSONObjects.
416+
417+ * Comments, prologs, DTDs, and <pre>{@code <[ [ ]]>}</pre> are ignored.
418+ * @param string The XML source text.
419+ * @param config The parser configuration:
420+ * JSONMLParserConfiguration.ORIGINAL is the default behaviour;
421+ * JSONMLParserConfiguration.KEEP_STRINGS means values will not be coerced into boolean
422+ * or numeric values and will instead be left as strings
423+ * @return A JSONObject containing the structured data from the XML string.
424+ * @throws JSONException Thrown on error converting to a JSONObject
425+ */
426+ public static JSONObject toJSONObject (String string , JSONMLParserConfiguration config ) throws JSONException {
427+ return (JSONObject )parse (new XMLTokener (string ), false , null , config , 0 );
327428 }
328429
329-
430+
330431 /**
331432 * Convert a well-formed (but not necessarily valid) XML string into a
332433 * JSONObject using the JsonML transform. Each XML tag is represented as
@@ -341,7 +442,7 @@ public static JSONObject toJSONObject(String string, boolean keepStrings) throws
341442 * @throws JSONException Thrown on error converting to a JSONObject
342443 */
343444 public static JSONObject toJSONObject (XMLTokener x ) throws JSONException {
344- return (JSONObject )parse (x , false , null , false );
445+ return (JSONObject )parse (x , false , null , false , 0 );
345446 }
346447
347448
@@ -361,7 +462,29 @@ public static JSONObject toJSONObject(XMLTokener x) throws JSONException {
361462 * @throws JSONException Thrown on error converting to a JSONObject
362463 */
363464 public static JSONObject toJSONObject (XMLTokener x , boolean keepStrings ) throws JSONException {
364- return (JSONObject )parse (x , false , null , keepStrings );
465+ return (JSONObject )parse (x , false , null , keepStrings , 0 );
466+ }
467+
468+
469+ /**
470+ * Convert a well-formed (but not necessarily valid) XML string into a
471+ * JSONObject using the JsonML transform. Each XML tag is represented as
472+ * a JSONObject with a "tagName" property. If the tag has attributes, then
473+ * the attributes will be in the JSONObject as properties. If the tag
474+ * contains children, the object will have a "childNodes" property which
475+ * will be an array of strings and JsonML JSONObjects.
476+
477+ * Comments, prologs, DTDs, and <pre>{@code <[ [ ]]>}</pre> are ignored.
478+ * @param x An XMLTokener of the XML source text.
479+ * @param config The parser configuration:
480+ * JSONMLParserConfiguration.ORIGINAL is the default behaviour;
481+ * JSONMLParserConfiguration.KEEP_STRINGS means values will not be coerced into boolean
482+ * or numeric values and will instead be left as strings
483+ * @return A JSONObject containing the structured data from the XML string.
484+ * @throws JSONException Thrown on error converting to a JSONObject
485+ */
486+ public static JSONObject toJSONObject (XMLTokener x , JSONMLParserConfiguration config ) throws JSONException {
487+ return (JSONObject )parse (x , false , null , config , 0 );
365488 }
366489
367490
@@ -442,6 +565,7 @@ public static String toString(JSONArray ja) throws JSONException {
442565 return sb .toString ();
443566 }
444567
568+
445569 /**
446570 * Reverse the JSONML transformation, making an XML text from a JSONObject.
447571 * The JSONObject must contain a "tagName" property. If it has children,
0 commit comments