mirror of
https://github.com/stleary/JSON-java.git
synced 2025-08-03 11:25:30 -04:00
work on issue 841
This commit is contained in:
parent
4917e3579d
commit
8dbf03e76b
@ -355,10 +355,20 @@ public class XML {
|
||||
&& TYPE_ATTR.equals(string)) {
|
||||
xmlXsiTypeConverter = config.getXsiTypeMap().get(token);
|
||||
} else if (!nilAttributeFound) {
|
||||
Object obj = stringToValue((String) token);
|
||||
if (obj instanceof Boolean) {
|
||||
jsonObject.accumulate(string,
|
||||
config.isKeepStrings()
|
||||
config.isKeepBooleanAsString()
|
||||
? ((String) token)
|
||||
: stringToValue((String) token));
|
||||
: obj);
|
||||
} else if (obj instanceof Number) {
|
||||
jsonObject.accumulate(string,
|
||||
config.isKeepNumberAsString()
|
||||
? ((String) token)
|
||||
: obj);
|
||||
} else {
|
||||
jsonObject.accumulate(string, stringToValue((String) token));
|
||||
}
|
||||
}
|
||||
token = null;
|
||||
} else {
|
||||
@ -407,8 +417,20 @@ public class XML {
|
||||
jsonObject.accumulate(config.getcDataTagName(),
|
||||
stringToValue(string, xmlXsiTypeConverter));
|
||||
} else {
|
||||
Object obj = stringToValue((String) token);
|
||||
if (obj instanceof Boolean) {
|
||||
jsonObject.accumulate(config.getcDataTagName(),
|
||||
config.isKeepStrings() ? string : stringToValue(string));
|
||||
config.isKeepBooleanAsString()
|
||||
? ((String) token)
|
||||
: obj);
|
||||
} else if (obj instanceof Number) {
|
||||
jsonObject.accumulate(config.getcDataTagName(),
|
||||
config.isKeepNumberAsString()
|
||||
? ((String) token)
|
||||
: obj);
|
||||
} else {
|
||||
jsonObject.accumulate(config.getcDataTagName(), stringToValue((String) token));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -688,6 +710,44 @@ public class XML {
|
||||
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 <pre>{@code
|
||||
* <[ [ ]]>}</pre>
|
||||
* are ignored.
|
||||
*
|
||||
* All numbers 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 depending
|
||||
* on how flag is set.
|
||||
* All booleans are converted as strings, for true, false will not be coerced to
|
||||
* booleans but will instead be the exact value as seen in the XML document depending
|
||||
* on how flag is set.
|
||||
*
|
||||
* @param reader The XML source reader.
|
||||
* @param keepNumberAsString If true, then numeric values will not be coerced into
|
||||
* numeric values and will instead be left as strings
|
||||
* @param keepBooleanAsString If true, then boolean values will not be coerced into
|
||||
* * 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(Reader reader, boolean keepNumberAsString, boolean keepBooleanAsString) throws JSONException {
|
||||
XMLParserConfiguration xmlParserConfiguration = new XMLParserConfiguration();
|
||||
if(keepNumberAsString) {
|
||||
xmlParserConfiguration = xmlParserConfiguration.withKeepNumberAsString(keepNumberAsString);
|
||||
}
|
||||
if(keepBooleanAsString) {
|
||||
xmlParserConfiguration = xmlParserConfiguration.withKeepBooleanAsString(keepBooleanAsString);
|
||||
}
|
||||
return toJSONObject(reader, xmlParserConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML into a
|
||||
* JSONObject. Some information may be lost in this transformation because
|
||||
@ -746,6 +806,38 @@ public class XML {
|
||||
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 <pre>{@code
|
||||
* <[ [ ]]>}</pre>
|
||||
* are ignored.
|
||||
*
|
||||
* All numbers 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 depending
|
||||
* on how flag is set.
|
||||
* All booleans are converted as strings, for true, false will not be coerced to
|
||||
* booleans but will instead be the exact value as seen in the XML document depending
|
||||
* on how flag is set.
|
||||
*
|
||||
* @param string
|
||||
* The source string.
|
||||
* @param keepNumberAsString If true, then numeric values will not be coerced into
|
||||
* numeric values and will instead be left as strings
|
||||
* @param keepBooleanAsString If true, then boolean values will not be coerced into
|
||||
* 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 keepNumberAsString, boolean keepBooleanAsString) throws JSONException {
|
||||
return toJSONObject(new StringReader(string), keepNumberAsString, keepBooleanAsString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONObject. Some information may be lost in this transformation because
|
||||
|
@ -22,6 +22,16 @@ public class XMLParserConfiguration extends ParserConfiguration {
|
||||
*/
|
||||
// public static final int DEFAULT_MAXIMUM_NESTING_DEPTH = 512; // We could override
|
||||
|
||||
/**
|
||||
* Allow user to control how numbers are parsed
|
||||
*/
|
||||
private boolean keepNumberAsString;
|
||||
|
||||
/**
|
||||
* Allow user to control how booleans are parsed
|
||||
*/
|
||||
private boolean keepBooleanAsString;
|
||||
|
||||
/** Original Configuration of the XML Parser. */
|
||||
public static final XMLParserConfiguration ORIGINAL
|
||||
= new XMLParserConfiguration();
|
||||
@ -142,7 +152,9 @@ public class XMLParserConfiguration extends ParserConfiguration {
|
||||
*/
|
||||
@Deprecated
|
||||
public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName, final boolean convertNilAttributeToNull) {
|
||||
super(keepStrings, DEFAULT_MAXIMUM_NESTING_DEPTH);
|
||||
super(false, DEFAULT_MAXIMUM_NESTING_DEPTH);
|
||||
this.keepNumberAsString = keepStrings;
|
||||
this.keepBooleanAsString = keepStrings;
|
||||
this.cDataTagName = cDataTagName;
|
||||
this.convertNilAttributeToNull = convertNilAttributeToNull;
|
||||
}
|
||||
@ -163,8 +175,10 @@ public class XMLParserConfiguration extends ParserConfiguration {
|
||||
*/
|
||||
private XMLParserConfiguration (final boolean keepStrings, final String cDataTagName,
|
||||
final boolean convertNilAttributeToNull, final Map<String, XMLXsiTypeConverter<?>> xsiTypeMap, final Set<String> forceList,
|
||||
final int maxNestingDepth, final boolean closeEmptyTag) {
|
||||
super(keepStrings, maxNestingDepth);
|
||||
final int maxNestingDepth, final boolean closeEmptyTag, final boolean keepNumberAsString, final boolean keepBooleanAsString) {
|
||||
super(false, maxNestingDepth);
|
||||
this.keepNumberAsString = keepNumberAsString;
|
||||
this.keepBooleanAsString = keepBooleanAsString;
|
||||
this.cDataTagName = cDataTagName;
|
||||
this.convertNilAttributeToNull = convertNilAttributeToNull;
|
||||
this.xsiTypeMap = Collections.unmodifiableMap(xsiTypeMap);
|
||||
@ -189,7 +203,9 @@ public class XMLParserConfiguration extends ParserConfiguration {
|
||||
this.xsiTypeMap,
|
||||
this.forceList,
|
||||
this.maxNestingDepth,
|
||||
this.closeEmptyTag
|
||||
this.closeEmptyTag,
|
||||
this.keepNumberAsString,
|
||||
this.keepBooleanAsString
|
||||
);
|
||||
config.shouldTrimWhiteSpace = this.shouldTrimWhiteSpace;
|
||||
return config;
|
||||
@ -207,7 +223,40 @@ public class XMLParserConfiguration extends ParserConfiguration {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public XMLParserConfiguration withKeepStrings(final boolean newVal) {
|
||||
return super.withKeepStrings(newVal);
|
||||
XMLParserConfiguration newConfig = this.clone();
|
||||
newConfig.keepNumberAsString = newVal;
|
||||
newConfig.keepBooleanAsString = newVal;
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* When parsing the XML into JSON, specifies if numbers should be kept as strings (<code>1</code>), or if
|
||||
* they should try to be guessed into JSON values (numeric, boolean, string)
|
||||
*
|
||||
* @param newVal
|
||||
* new value to use for the <code>keepNumberAsString</code> configuration option.
|
||||
*
|
||||
* @return The existing configuration will not be modified. A new configuration is returned.
|
||||
*/
|
||||
public XMLParserConfiguration withKeepNumberAsString(final boolean newVal) {
|
||||
XMLParserConfiguration newConfig = this.clone();
|
||||
newConfig.keepNumberAsString = newVal;
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* When parsing the XML into JSON, specifies if booleans should be kept as strings (<code>true</code>), or if
|
||||
* they should try to be guessed into JSON values (numeric, boolean, string)
|
||||
*
|
||||
* @param newVal
|
||||
* new value to use for the <code>withKeepBooleanAsString</code> configuration option.
|
||||
*
|
||||
* @return The existing configuration will not be modified. A new configuration is returned.
|
||||
*/
|
||||
public XMLParserConfiguration withKeepBooleanAsString(final boolean newVal) {
|
||||
XMLParserConfiguration newConfig = this.clone();
|
||||
newConfig.keepBooleanAsString = newVal;
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -221,6 +270,26 @@ public class XMLParserConfiguration extends ParserConfiguration {
|
||||
return this.cDataTagName;
|
||||
}
|
||||
|
||||
/**
|
||||
* When parsing the XML into JSONML, specifies if numbers should be kept as strings (<code>true</code>), or if
|
||||
* they should try to be guessed into JSON values (numeric, boolean, string).
|
||||
*
|
||||
* @return The <code>keepStrings</code> configuration value.
|
||||
*/
|
||||
public boolean isKeepNumberAsString() {
|
||||
return this.keepNumberAsString;
|
||||
}
|
||||
|
||||
/**
|
||||
* When parsing the XML into JSONML, specifies if booleans should be kept as strings (<code>true</code>), or if
|
||||
* they should try to be guessed into JSON values (numeric, boolean, string).
|
||||
*
|
||||
* @return The <code>keepStrings</code> configuration value.
|
||||
*/
|
||||
public boolean isKeepBooleanAsString() {
|
||||
return this.keepBooleanAsString;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the key in a JSON Object that indicates a CDATA section. Historically this has
|
||||
* been the value "content" but can be changed. Use <code>null</code> to indicate no CDATA
|
||||
|
@ -574,15 +574,18 @@ public class XMLConfigurationTest {
|
||||
XMLParserConfiguration keepStringsAndCloseEmptyTag = keepStrings.withCloseEmptyTag(true);
|
||||
XMLParserConfiguration keepDigits = keepStringsAndCloseEmptyTag.withKeepStrings(false);
|
||||
XMLParserConfiguration keepDigitsAndNoCloseEmptyTag = keepDigits.withCloseEmptyTag(false);
|
||||
assertTrue(keepStrings.isKeepStrings());
|
||||
assertTrue(keepStrings.isKeepNumberAsString());
|
||||
assertTrue(keepStrings.isKeepBooleanAsString());
|
||||
assertFalse(keepStrings.isCloseEmptyTag());
|
||||
assertTrue(keepStringsAndCloseEmptyTag.isKeepStrings());
|
||||
assertTrue(keepStringsAndCloseEmptyTag.isKeepNumberAsString());
|
||||
assertTrue(keepStringsAndCloseEmptyTag.isKeepBooleanAsString());
|
||||
assertTrue(keepStringsAndCloseEmptyTag.isCloseEmptyTag());
|
||||
assertFalse(keepDigits.isKeepStrings());
|
||||
assertFalse(keepDigits.isKeepNumberAsString());
|
||||
assertFalse(keepDigits.isKeepBooleanAsString());
|
||||
assertTrue(keepDigits.isCloseEmptyTag());
|
||||
assertFalse(keepDigitsAndNoCloseEmptyTag.isKeepStrings());
|
||||
assertFalse(keepDigitsAndNoCloseEmptyTag.isKeepNumberAsString());
|
||||
assertFalse(keepDigitsAndNoCloseEmptyTag.isKeepBooleanAsString());
|
||||
assertFalse(keepDigitsAndNoCloseEmptyTag.isCloseEmptyTag());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -767,6 +770,30 @@ public class XMLConfigurationTest {
|
||||
Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON string lost leading zero and converted "True" to true.
|
||||
*/
|
||||
@Test
|
||||
public void testToJSONArray_jsonOutput_withKeepNumberAsString() {
|
||||
final String originalXml = "<root><id>01</id><id>1</id><id>00</id><id>0</id><item id=\"01\"/><title>True</title></root>";
|
||||
final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",\"1\",\"00\",\"0\"],\"title\":true}}");
|
||||
final JSONObject actualJsonOutput = XML.toJSONObject(originalXml,
|
||||
new XMLParserConfiguration().withKeepNumberAsString(true));
|
||||
Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON string lost leading zero and converted "True" to true.
|
||||
*/
|
||||
@Test
|
||||
public void testToJSONArray_jsonOutput_withKeepBooleanAsString() {
|
||||
final String originalXml = "<root><id>01</id><id>1</id><id>00</id><id>0</id><item id=\"01\"/><title>True</title></root>";
|
||||
final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",1,\"00\",0],\"title\":\"True\"}}");
|
||||
final JSONObject actualJsonOutput = XML.toJSONObject(originalXml,
|
||||
new XMLParserConfiguration().withKeepBooleanAsString(true));
|
||||
Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON string cannot be reverted to original xml.
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user