Skip to content

Commit

Permalink
Added type conversion support
Browse files Browse the repository at this point in the history
  • Loading branch information
Rahul Kumar committed Jul 19, 2020
1 parent 6ddaa13 commit bba8246
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 6 deletions.
35 changes: 33 additions & 2 deletions src/main/java/org/json/XML.java
Expand Up @@ -26,10 +26,12 @@ of this software and associated documentation files (the "Software"), to deal

import java.io.Reader;
import java.io.StringReader;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Iterator;


/**
* This provides static methods to convert an XML text into a JSONObject, and to
* covert a JSONObject into an XML text.
Expand Down Expand Up @@ -72,6 +74,8 @@ public class XML {
*/
public static final String NULL_ATTR = "xsi:nil";

public static final String TYPE_ATTR = "xsi:type";

/**
* Creates an iterator for navigating Code Points in a string instead of
* characters. Once Java7 support is dropped, this can be replaced with
Expand Down Expand Up @@ -257,6 +261,7 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, XMLP
String string;
String tagName;
Object token;
String typeCastClass;

// Test for and skip past these forms:
// <!-- ... -->
Expand Down Expand Up @@ -336,6 +341,7 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, XMLP
token = null;
jsonObject = new JSONObject();
boolean nilAttributeFound = false;
typeCastClass = null;
for (;;) {
if (token == null) {
token = x.nextToken();
Expand All @@ -354,6 +360,9 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, XMLP
&& NULL_ATTR.equals(string)
&& Boolean.parseBoolean((String) token)) {
nilAttributeFound = true;
} else if(config.useValueTypeCast
&& TYPE_ATTR.equals(string)) {
typeCastClass = (String) token;
} else if (!nilAttributeFound) {
jsonObject.accumulate(string,
config.keepStrings
Expand Down Expand Up @@ -392,8 +401,12 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, XMLP
} else if (token instanceof String) {
string = (String) token;
if (string.length() > 0) {
jsonObject.accumulate(config.cDataTagName,
config.keepStrings ? string : stringToValue(string));
if(typeCastClass != null) {
jsonObject.accumulate(config.cDataTagName, stringToValue(string, typeCastClass));
} else {
jsonObject.accumulate(config.cDataTagName,
config.keepStrings ? string : stringToValue(string));
}
}

} else if (token == LT) {
Expand All @@ -418,6 +431,24 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, XMLP
}
}

/**
* This method tries to convert the given string value to the target object
* @param string String to convert
* @param className target class name
* @return JSON value of this string or the string
*/
public static Object stringToValue(String string, String className) {
try {
if(className.equals(String.class.getName())) return string;
Class<?> clazz = Class.forName(className);
Method method = clazz.getMethod("valueOf", String.class);
return method.invoke(null, string);
} catch (Exception e){
e.printStackTrace();
}
return stringToValue(string);
}

/**
* This method is the same as {@link JSONObject#stringToValue(String)}.
*
Expand Down
28 changes: 25 additions & 3 deletions src/main/java/org/json/XMLParserConfiguration.java
Expand Up @@ -50,6 +50,12 @@ public class XMLParserConfiguration {
*/
public final boolean convertNilAttributeToNull;

/**
* When parsing the XML into JSON, specifies if values with attribute xsi:type="java.lang.Integer"
* should be kept as attribute(false), or they should be converted to the given type
*/
public final boolean useValueTypeCast;

/**
* Default parser configuration. Does not keep strings, and the CDATA Tag Name is "content".
*/
Expand Down Expand Up @@ -85,9 +91,7 @@ public XMLParserConfiguration (final String cDataTagName) {
* to use that value as the JSONObject key name to process as CDATA.
*/
public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName) {
this.keepStrings = keepStrings;
this.cDataTagName = cDataTagName;
this.convertNilAttributeToNull = false;
this(keepStrings, cDataTagName, false);
}

/**
Expand All @@ -100,8 +104,26 @@ public XMLParserConfiguration (final boolean keepStrings, final String cDataTagN
* <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, cDataTagName, 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}.
* @param useValueTypeCast <code>true</code> to parse values with attribute xsi:type="java.lang.Integer" as
* integer, xsi:type="java.lang.String" as string
* <code>false</code> to parse values with attribute xsi:type="java.lang.Integer" as {"xsi:type":"java.lang.Integer"}.
*/
public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName,
final boolean convertNilAttributeToNull, final boolean useValueTypeCast ) {
this.keepStrings = keepStrings;
this.cDataTagName = cDataTagName;
this.convertNilAttributeToNull = convertNilAttributeToNull;
this.useValueTypeCast = useValueTypeCast;
}
}
30 changes: 29 additions & 1 deletion src/test/java/org/json/junit/XMLTest.java
Expand Up @@ -898,4 +898,32 @@ public void testToJsonWithNullWhenNilConversionDisabled() {
final JSONObject json = XML.toJSONObject(originalXml, new XMLParserConfiguration());
assertEquals(expectedJsonString, json.toString());
}
}

/**
* test passes when xsi:type="java.lang.String" not converting to string
*/
@Test
public void testToJsonWithTypeWhenTypeConversionDisabled() {
final String originalXml = "<root><id xsi:type=\"java.lang.String\">1234</id></root>";
final String expectedJsonString = "{\"root\":{\"id\":{\"xsi:type\":\"java.lang.String\",\"content\":1234}}}";

final JSONObject json = XML.toJSONObject(originalXml, new XMLParserConfiguration());
assertEquals(expectedJsonString, json.toString());
}

/**
* test passes when xsi:type="java.lang.String" converting to String
*/
@Test
public void testToJsonWithTypeWhenTypeConversionEnabled() {
final String originalXml = "<root><id1 xsi:type=\"java.lang.String\">1234</id1>"
+ "<id2 xsi:type=\"java.lang.Integer\">1234</id2></root>";
final String expectedJsonString = "{\"root\":{\"id2\":1234,\"id1\":\"1234\"}}";

final JSONObject json = XML.toJSONObject(originalXml, new XMLParserConfiguration(false,
"content", false, true));
assertEquals(expectedJsonString, json.toString());
}


}

0 comments on commit bba8246

Please sign in to comment.