@@ -31,7 +31,7 @@ of this software and associated documentation files (the "Software"), to deal
31
31
/**
32
32
* This provides static methods to convert an XML text into a JSONObject, and to
33
33
* covert a JSONObject into an XML text.
34
- *
34
+ *
35
35
* @author JSON.org
36
36
* @version 2016-08-10
37
37
*/
@@ -64,15 +64,20 @@ public class XML {
64
64
65
65
/** The Character '/'. */
66
66
public static final Character SLASH = '/' ;
67
-
67
+
68
+ /**
69
+ * Null attrubute name
70
+ */
71
+ public static final String NULL_ATTR = "xsi:nil" ;
72
+
68
73
/**
69
74
* Creates an iterator for navigating Code Points in a string instead of
70
75
* characters. Once Java7 support is dropped, this can be replaced with
71
76
* <code>
72
77
* string.codePoints()
73
78
* </code>
74
79
* which is available in Java8 and above.
75
- *
80
+ *
76
81
* @see <a href=
77
82
* "http://stackoverflow.com/a/21791059/6030888">http://stackoverflow.com/a/21791059/6030888</a>
78
83
*/
@@ -107,15 +112,15 @@ public void remove() {
107
112
108
113
/**
109
114
* Replace special characters with XML escapes:
110
- *
115
+ *
111
116
* <pre>
112
117
* & <small>(ampersand)</small> is replaced by &amp;
113
118
* < <small>(less than)</small> is replaced by &lt;
114
119
* > <small>(greater than)</small> is replaced by &gt;
115
120
* " <small>(double quote)</small> is replaced by &quot;
116
121
* ' <small>(single quote / apostrophe)</small> is replaced by &apos;
117
122
* </pre>
118
- *
123
+ *
119
124
* @param string
120
125
* The string to be escaped.
121
126
* @return The escaped string.
@@ -151,17 +156,17 @@ public static String escape(String string) {
151
156
}
152
157
return sb .toString ();
153
158
}
154
-
159
+
155
160
/**
156
161
* @param cp code point to test
157
162
* @return true if the code point is not valid for an XML
158
163
*/
159
164
private static boolean mustEscape (int cp ) {
160
165
/* Valid range from https://www.w3.org/TR/REC-xml/#charsets
161
- *
162
- * #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
163
- *
164
- * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
166
+ *
167
+ * #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
168
+ *
169
+ * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
165
170
*/
166
171
// isISOControl is true when (cp >= 0 && cp <= 0x1F) || (cp >= 0x7F && cp <= 0x9F)
167
172
// all ISO control characters are out of range except tabs and new lines
@@ -180,7 +185,7 @@ private static boolean mustEscape(int cp) {
180
185
181
186
/**
182
187
* Removes XML escapes from the string.
183
- *
188
+ *
184
189
* @param string
185
190
* string to remove escapes from
186
191
* @return string with converted entities
@@ -212,7 +217,7 @@ public static String unescape(String string) {
212
217
/**
213
218
* Throw an exception if the string contains whitespace. Whitespace is not
214
219
* allowed in tagNames and attributes.
215
- *
220
+ *
216
221
* @param string
217
222
* A string.
218
223
* @throws JSONException Thrown if the string contains whitespace or is empty.
@@ -232,7 +237,7 @@ public static void noSpace(String string) throws JSONException {
232
237
233
238
/**
234
239
* Scan the content following the named tag, attaching it to the context.
235
- *
240
+ *
236
241
* @param x
237
242
* The XMLTokener containing the source string.
238
243
* @param context
@@ -328,6 +333,7 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, XMLP
328
333
tagName = (String ) token ;
329
334
token = null ;
330
335
jsonobject = new JSONObject ();
336
+ boolean nilAttributeFound = false ;
331
337
for (;;) {
332
338
if (token == null ) {
333
339
token = x .nextToken ();
@@ -341,8 +347,17 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, XMLP
341
347
if (!(token instanceof String )) {
342
348
throw x .syntaxError ("Missing value" );
343
349
}
344
- jsonobject .accumulate (string ,
345
- config .keepStrings ? ((String )token ) : stringToValue ((String ) token ));
350
+
351
+ if (config .convertNilAttributeToNull
352
+ && NULL_ATTR .equals (string )
353
+ && Boolean .parseBoolean ((String ) token )) {
354
+ nilAttributeFound = true ;
355
+ } else if (!nilAttributeFound ) {
356
+ jsonobject .accumulate (string ,
357
+ config .keepStrings
358
+ ? ((String ) token )
359
+ : stringToValue ((String ) token ));
360
+ }
346
361
token = null ;
347
362
} else {
348
363
jsonobject .accumulate (string , "" );
@@ -354,7 +369,9 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, XMLP
354
369
if (x .nextToken () != GT ) {
355
370
throw x .syntaxError ("Misshaped tag" );
356
371
}
357
- if (jsonobject .length () > 0 ) {
372
+ if (nilAttributeFound ) {
373
+ context .accumulate (tagName , JSONObject .NULL );
374
+ } else if (jsonobject .length () > 0 ) {
358
375
context .accumulate (tagName , jsonobject );
359
376
} else {
360
377
context .accumulate (tagName , "" );
@@ -399,10 +416,10 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, XMLP
399
416
}
400
417
}
401
418
}
402
-
419
+
403
420
/**
404
421
* This method is the same as {@link JSONObject#stringToValue(String)}.
405
- *
422
+ *
406
423
* @param string String to convert
407
424
* @return JSON value of this string or the string
408
425
*/
@@ -463,7 +480,7 @@ public static Object stringToValue(String string) {
463
480
* elements are represented as JSONArrays. Content text may be placed in a
464
481
* "content" member. Comments, prologs, DTDs, and <code><[ [ ]]></code>
465
482
* are ignored.
466
- *
483
+ *
467
484
* @param string
468
485
* The source string.
469
486
* @return A JSONObject containing the structured data from the XML string.
@@ -518,7 +535,7 @@ public static JSONObject toJSONObject(Reader reader, boolean keepStrings) throws
518
535
}
519
536
return toJSONObject (reader , XMLParserConfiguration .ORIGINAL );
520
537
}
521
-
538
+
522
539
/**
523
540
* Convert a well-formed (but not necessarily valid) XML into a
524
541
* JSONObject. Some information may be lost in this transformation because
@@ -560,10 +577,10 @@ public static JSONObject toJSONObject(Reader reader, XMLParserConfiguration conf
560
577
* elements are represented as JSONArrays. Content text may be placed in a
561
578
* "content" member. Comments, prologs, DTDs, and <code><[ [ ]]></code>
562
579
* are ignored.
563
- *
580
+ *
564
581
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to
565
582
* numbers but will instead be the exact value as seen in the XML document.
566
- *
583
+ *
567
584
* @param string
568
585
* The source string.
569
586
* @param keepStrings If true, then values will not be coerced into boolean
@@ -585,10 +602,10 @@ public static JSONObject toJSONObject(String string, boolean keepStrings) throws
585
602
* elements are represented as JSONArrays. Content text may be placed in a
586
603
* "content" member. Comments, prologs, DTDs, and <code><[ [ ]]></code>
587
604
* are ignored.
588
- *
605
+ *
589
606
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to
590
607
* numbers but will instead be the exact value as seen in the XML document.
591
- *
608
+ *
592
609
* @param string
593
610
* The source string.
594
611
* @param config Configuration options for the parser.
@@ -601,7 +618,7 @@ public static JSONObject toJSONObject(String string, XMLParserConfiguration conf
601
618
602
619
/**
603
620
* Convert a JSONObject into a well-formed, element-normal XML string.
604
- *
621
+ *
605
622
* @param object
606
623
* A JSONObject.
607
624
* @return A string.
@@ -610,10 +627,10 @@ public static JSONObject toJSONObject(String string, XMLParserConfiguration conf
610
627
public static String toString (Object object ) throws JSONException {
611
628
return toString (object , null , XMLParserConfiguration .ORIGINAL );
612
629
}
613
-
630
+
614
631
/**
615
632
* Convert a JSONObject into a well-formed, element-normal XML string.
616
- *
633
+ *
617
634
* @param object
618
635
* A JSONObject.
619
636
* @param tagName
@@ -627,7 +644,7 @@ public static String toString(final Object object, final String tagName) {
627
644
628
645
/**
629
646
* Convert a JSONObject into a well-formed, element-normal XML string.
630
- *
647
+ *
631
648
* @param object
632
649
* A JSONObject.
633
650
* @param tagName
0 commit comments