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

add configuration for xsi:nil="true" conversion to null

This commit is contained in:
meiskalt7 2019-04-09 18:47:45 +07:00
parent 12bbe8cd9a
commit d5b278539e
2 changed files with 72 additions and 34 deletions

View file

@ -31,7 +31,7 @@ import java.util.Iterator;
/** /**
* This provides static methods to convert an XML text into a JSONObject, and to * This provides static methods to convert an XML text into a JSONObject, and to
* covert a JSONObject into an XML text. * covert a JSONObject into an XML text.
* *
* @author JSON.org * @author JSON.org
* @version 2016-08-10 * @version 2016-08-10
*/ */
@ -64,7 +64,12 @@ public class XML {
/** The Character '/'. */ /** The Character '/'. */
public static final Character SLASH = '/'; public static final Character SLASH = '/';
/**
* Null attrubute name
*/
public static final String NULL_ATTR = "xsi:nil";
/** /**
* Creates an iterator for navigating Code Points in a string instead of * Creates an iterator for navigating Code Points in a string instead of
* characters. Once Java7 support is dropped, this can be replaced with * characters. Once Java7 support is dropped, this can be replaced with
@ -72,7 +77,7 @@ public class XML {
* string.codePoints() * string.codePoints()
* </code> * </code>
* which is available in Java8 and above. * which is available in Java8 and above.
* *
* @see <a href= * @see <a href=
* "http://stackoverflow.com/a/21791059/6030888">http://stackoverflow.com/a/21791059/6030888</a> * "http://stackoverflow.com/a/21791059/6030888">http://stackoverflow.com/a/21791059/6030888</a>
*/ */
@ -107,7 +112,7 @@ public class XML {
/** /**
* Replace special characters with XML escapes: * Replace special characters with XML escapes:
* *
* <pre> * <pre>
* &amp; <small>(ampersand)</small> is replaced by &amp;amp; * &amp; <small>(ampersand)</small> is replaced by &amp;amp;
* &lt; <small>(less than)</small> is replaced by &amp;lt; * &lt; <small>(less than)</small> is replaced by &amp;lt;
@ -115,7 +120,7 @@ public class XML {
* &quot; <small>(double quote)</small> is replaced by &amp;quot; * &quot; <small>(double quote)</small> is replaced by &amp;quot;
* &apos; <small>(single quote / apostrophe)</small> is replaced by &amp;apos; * &apos; <small>(single quote / apostrophe)</small> is replaced by &amp;apos;
* </pre> * </pre>
* *
* @param string * @param string
* The string to be escaped. * The string to be escaped.
* @return The escaped string. * @return The escaped string.
@ -151,17 +156,17 @@ public class XML {
} }
return sb.toString(); return sb.toString();
} }
/** /**
* @param cp code point to test * @param cp code point to test
* @return true if the code point is not valid for an XML * @return true if the code point is not valid for an XML
*/ */
private static boolean mustEscape(int cp) { private static boolean mustEscape(int cp) {
/* Valid range from https://www.w3.org/TR/REC-xml/#charsets /* Valid range from https://www.w3.org/TR/REC-xml/#charsets
* *
* #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] * #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
* *
* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
*/ */
// isISOControl is true when (cp >= 0 && cp <= 0x1F) || (cp >= 0x7F && cp <= 0x9F) // isISOControl is true when (cp >= 0 && cp <= 0x1F) || (cp >= 0x7F && cp <= 0x9F)
// all ISO control characters are out of range except tabs and new lines // all ISO control characters are out of range except tabs and new lines
@ -180,7 +185,7 @@ public class XML {
/** /**
* Removes XML escapes from the string. * Removes XML escapes from the string.
* *
* @param string * @param string
* string to remove escapes from * string to remove escapes from
* @return string with converted entities * @return string with converted entities
@ -212,7 +217,7 @@ public class XML {
/** /**
* Throw an exception if the string contains whitespace. Whitespace is not * Throw an exception if the string contains whitespace. Whitespace is not
* allowed in tagNames and attributes. * allowed in tagNames and attributes.
* *
* @param string * @param string
* A string. * A string.
* @throws JSONException Thrown if the string contains whitespace or is empty. * @throws JSONException Thrown if the string contains whitespace or is empty.
@ -232,7 +237,7 @@ public class XML {
/** /**
* Scan the content following the named tag, attaching it to the context. * Scan the content following the named tag, attaching it to the context.
* *
* @param x * @param x
* The XMLTokener containing the source string. * The XMLTokener containing the source string.
* @param context * @param context
@ -328,6 +333,7 @@ public class XML {
tagName = (String) token; tagName = (String) token;
token = null; token = null;
jsonobject = new JSONObject(); jsonobject = new JSONObject();
boolean nilAttributeFound = false;
for (;;) { for (;;) {
if (token == null) { if (token == null) {
token = x.nextToken(); token = x.nextToken();
@ -341,8 +347,17 @@ public class XML {
if (!(token instanceof String)) { if (!(token instanceof String)) {
throw x.syntaxError("Missing value"); throw x.syntaxError("Missing value");
} }
jsonobject.accumulate(string,
config.keepStrings ? ((String)token) : stringToValue((String) token)); if (config.convertNilAttributeToNull
&& NULL_ATTR.equals(string)
&& Boolean.parseBoolean((String) token)) {
nilAttributeFound = true;
} else if (!nilAttributeFound) {
jsonobject.accumulate(string,
config.keepStrings
? ((String) token)
: stringToValue((String) token));
}
token = null; token = null;
} else { } else {
jsonobject.accumulate(string, ""); jsonobject.accumulate(string, "");
@ -354,7 +369,9 @@ public class XML {
if (x.nextToken() != GT) { if (x.nextToken() != GT) {
throw x.syntaxError("Misshaped tag"); throw x.syntaxError("Misshaped tag");
} }
if (jsonobject.length() > 0) { if (nilAttributeFound) {
context.accumulate(tagName, JSONObject.NULL);
} else if (jsonobject.length() > 0) {
context.accumulate(tagName, jsonobject); context.accumulate(tagName, jsonobject);
} else { } else {
context.accumulate(tagName, ""); context.accumulate(tagName, "");
@ -399,10 +416,10 @@ public class XML {
} }
} }
} }
/** /**
* This method is the same as {@link JSONObject#stringToValue(String)}. * This method is the same as {@link JSONObject#stringToValue(String)}.
* *
* @param string String to convert * @param string String to convert
* @return JSON value of this string or the string * @return JSON value of this string or the string
*/ */
@ -463,7 +480,7 @@ public class XML {
* elements are represented as JSONArrays. Content text may be placed in a * elements are represented as JSONArrays. Content text may be placed in a
* "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> * "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code>
* are ignored. * are ignored.
* *
* @param string * @param string
* The source string. * The source string.
* @return A JSONObject containing the structured data from the XML string. * @return A JSONObject containing the structured data from the XML string.
@ -518,7 +535,7 @@ public class XML {
} }
return toJSONObject(reader, XMLParserConfiguration.ORIGINAL); return toJSONObject(reader, XMLParserConfiguration.ORIGINAL);
} }
/** /**
* Convert a well-formed (but not necessarily valid) XML into a * Convert a well-formed (but not necessarily valid) XML into a
* JSONObject. Some information may be lost in this transformation because * JSONObject. Some information may be lost in this transformation because
@ -560,10 +577,10 @@ public class XML {
* elements are represented as JSONArrays. Content text may be placed in a * elements are represented as JSONArrays. Content text may be placed in a
* "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> * "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code>
* are ignored. * are ignored.
* *
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to * 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. * numbers but will instead be the exact value as seen in the XML document.
* *
* @param string * @param string
* The source string. * The source string.
* @param keepStrings If true, then values will not be coerced into boolean * @param keepStrings If true, then values will not be coerced into boolean
@ -585,10 +602,10 @@ public class XML {
* elements are represented as JSONArrays. Content text may be placed in a * elements are represented as JSONArrays. Content text may be placed in a
* "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> * "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code>
* are ignored. * are ignored.
* *
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to * 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. * numbers but will instead be the exact value as seen in the XML document.
* *
* @param string * @param string
* The source string. * The source string.
* @param config Configuration options for the parser. * @param config Configuration options for the parser.
@ -601,7 +618,7 @@ public class XML {
/** /**
* Convert a JSONObject into a well-formed, element-normal XML string. * Convert a JSONObject into a well-formed, element-normal XML string.
* *
* @param object * @param object
* A JSONObject. * A JSONObject.
* @return A string. * @return A string.
@ -610,10 +627,10 @@ public class XML {
public static String toString(Object object) throws JSONException { public static String toString(Object object) throws JSONException {
return toString(object, null, XMLParserConfiguration.ORIGINAL); return toString(object, null, XMLParserConfiguration.ORIGINAL);
} }
/** /**
* Convert a JSONObject into a well-formed, element-normal XML string. * Convert a JSONObject into a well-formed, element-normal XML string.
* *
* @param object * @param object
* A JSONObject. * A JSONObject.
* @param tagName * @param tagName
@ -627,7 +644,7 @@ public class XML {
/** /**
* Convert a JSONObject into a well-formed, element-normal XML string. * Convert a JSONObject into a well-formed, element-normal XML string.
* *
* @param object * @param object
* A JSONObject. * A JSONObject.
* @param tagName * @param tagName

View file

@ -32,7 +32,7 @@ public class XMLParserConfiguration {
/** Original Configuration of the XML Parser. */ /** Original Configuration of the XML Parser. */
public static final XMLParserConfiguration ORIGINAL = new XMLParserConfiguration(); public static final XMLParserConfiguration ORIGINAL = new XMLParserConfiguration();
/** Original configuration of the XML Parser except that values are kept as strings. */ /** Original configuration of the XML Parser except that values are kept as strings. */
public static final XMLParserConfiguration KEEP_STRINGS = new XMLParserConfiguration(true); 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 * 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) * they should try to be guessed into JSON values (numeric, boolean, string)
@ -44,12 +44,17 @@ public class XMLParserConfiguration {
* processing. * processing.
*/ */
public final String cDataTagName; public final String cDataTagName;
/**
* When parsing the XML into JSON, specifies if values with attribute xsi:nil="true"
* should be kept as attribute(false), or they should be converted to null(true)
*/
public final boolean convertNilAttributeToNull;
/** /**
* Default parser configuration. Does not keep strings, and the CDATA Tag Name is "content". * Default parser configuration. Does not keep strings, and the CDATA Tag Name is "content".
*/ */
public XMLParserConfiguration () { public XMLParserConfiguration () {
this(false, "content"); this(false, "content", false);
} }
/** /**
@ -58,7 +63,7 @@ public class XMLParserConfiguration {
* <code>false</code> to try and convert XML string values into a JSON value. * <code>false</code> to try and convert XML string values into a JSON value.
*/ */
public XMLParserConfiguration (final boolean keepStrings) { public XMLParserConfiguration (final boolean keepStrings) {
this(keepStrings, "content"); this(keepStrings, "content", false);
} }
/** /**
@ -69,7 +74,7 @@ public class XMLParserConfiguration {
* to use that value as the JSONObject key name to process as CDATA. * to use that value as the JSONObject key name to process as CDATA.
*/ */
public XMLParserConfiguration (final String cDataTagName) { public XMLParserConfiguration (final String cDataTagName) {
this(false, cDataTagName); this(false, cDataTagName, false);
} }
/** /**
@ -80,7 +85,23 @@ public class XMLParserConfiguration {
* to use that value as the JSONObject key name to process as CDATA. * to use that value as the JSONObject key name to process as CDATA.
*/ */
public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName) { public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName) {
this.keepStrings = keepStrings; this.keepStrings = keepStrings;
this.cDataTagName = cDataTagName; this.cDataTagName = cDataTagName;
this.convertNilAttributeToNull = false;
}
/**
* Configure the parser to use custom settings.
* @param keepStrings <code>true</code> to parse all values as string.
* <code>false</code> to try and convert XML string values into a JSON value.
* @param cDataTagName <code>null</code> to disable CDATA processing. Any other value
* to use that value as the JSONObject key name to process as CDATA.
* @param convertNilAttributeToNull <code>true</code> to parse values with attribute xsi:nil="true" as null.
* <code>false</code> to parse values with attribute xsi:nil="true" as {"xsi:nil":true}.
*/
public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName, final boolean convertNilAttributeToNull) {
this.keepStrings = keepStrings;
this.cDataTagName = cDataTagName;
this.convertNilAttributeToNull = convertNilAttributeToNull;
} }
} }