mirror of
https://github.com/stleary/JSON-java.git
synced 2025-08-03 03:15:32 -04:00
Merge pull request #646 from Zetmas/feature/issue#595
XMLParserConfiguration support for xml to json arrays
This commit is contained in:
commit
cff5cc6c74
@ -380,12 +380,23 @@ public class XML {
|
|||||||
if (x.nextToken() != GT) {
|
if (x.nextToken() != GT) {
|
||||||
throw x.syntaxError("Misshaped tag");
|
throw x.syntaxError("Misshaped tag");
|
||||||
}
|
}
|
||||||
if (nilAttributeFound) {
|
if (config.getForceList().contains(tagName)) {
|
||||||
context.accumulate(tagName, JSONObject.NULL);
|
// Force the value to be an array
|
||||||
} else if (jsonObject.length() > 0) {
|
if (nilAttributeFound) {
|
||||||
context.accumulate(tagName, jsonObject);
|
context.append(tagName, JSONObject.NULL);
|
||||||
|
} else if (jsonObject.length() > 0) {
|
||||||
|
context.append(tagName, jsonObject);
|
||||||
|
} else {
|
||||||
|
context.put(tagName, new JSONArray());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
context.accumulate(tagName, "");
|
if (nilAttributeFound) {
|
||||||
|
context.accumulate(tagName, JSONObject.NULL);
|
||||||
|
} else if (jsonObject.length() > 0) {
|
||||||
|
context.accumulate(tagName, jsonObject);
|
||||||
|
} else {
|
||||||
|
context.accumulate(tagName, "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -413,14 +424,27 @@ public class XML {
|
|||||||
} else if (token == LT) {
|
} else if (token == LT) {
|
||||||
// Nested element
|
// Nested element
|
||||||
if (parse(x, jsonObject, tagName, config)) {
|
if (parse(x, jsonObject, tagName, config)) {
|
||||||
if (jsonObject.length() == 0) {
|
if (config.getForceList().contains(tagName)) {
|
||||||
context.accumulate(tagName, "");
|
// Force the value to be an array
|
||||||
} else if (jsonObject.length() == 1
|
if (jsonObject.length() == 0) {
|
||||||
&& jsonObject.opt(config.getcDataTagName()) != null) {
|
context.put(tagName, new JSONArray());
|
||||||
context.accumulate(tagName, jsonObject.opt(config.getcDataTagName()));
|
} else if (jsonObject.length() == 1
|
||||||
|
&& jsonObject.opt(config.getcDataTagName()) != null) {
|
||||||
|
context.append(tagName, jsonObject.opt(config.getcDataTagName()));
|
||||||
|
} else {
|
||||||
|
context.append(tagName, jsonObject);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
context.accumulate(tagName, jsonObject);
|
if (jsonObject.length() == 0) {
|
||||||
|
context.accumulate(tagName, "");
|
||||||
|
} else if (jsonObject.length() == 1
|
||||||
|
&& jsonObject.opt(config.getcDataTagName()) != null) {
|
||||||
|
context.accumulate(tagName, jsonObject.opt(config.getcDataTagName()));
|
||||||
|
} else {
|
||||||
|
context.accumulate(tagName, jsonObject);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,9 @@ SOFTWARE.
|
|||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,6 +68,12 @@ public class XMLParserConfiguration {
|
|||||||
*/
|
*/
|
||||||
private Map<String, XMLXsiTypeConverter<?>> xsiTypeMap;
|
private Map<String, XMLXsiTypeConverter<?>> xsiTypeMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When parsing the XML into JSON, specifies the tags whose values should be converted
|
||||||
|
* to arrays
|
||||||
|
*/
|
||||||
|
private Set<String> forceList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default parser configuration. Does not keep strings (tries to implicitly convert
|
* Default parser configuration. Does not keep strings (tries to implicitly convert
|
||||||
* values), and the CDATA Tag Name is "content".
|
* values), and the CDATA Tag Name is "content".
|
||||||
@ -75,6 +83,7 @@ public class XMLParserConfiguration {
|
|||||||
this.cDataTagName = "content";
|
this.cDataTagName = "content";
|
||||||
this.convertNilAttributeToNull = false;
|
this.convertNilAttributeToNull = false;
|
||||||
this.xsiTypeMap = Collections.emptyMap();
|
this.xsiTypeMap = Collections.emptyMap();
|
||||||
|
this.forceList = Collections.emptySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -151,13 +160,15 @@ public class XMLParserConfiguration {
|
|||||||
* <code>false</code> to parse values with attribute xsi:nil="true" as {"xsi:nil":true}.
|
* <code>false</code> to parse values with attribute xsi:nil="true" as {"xsi:nil":true}.
|
||||||
* @param xsiTypeMap <code>new HashMap<String, XMLXsiTypeConverter<?>>()</code> to parse values with attribute
|
* @param xsiTypeMap <code>new HashMap<String, XMLXsiTypeConverter<?>>()</code> to parse values with attribute
|
||||||
* xsi:type="integer" as integer, xsi:type="string" as string
|
* xsi:type="integer" as integer, xsi:type="string" as string
|
||||||
|
* @param forceList <code>new HashSet<String>()</code> to parse the provided tags' values as arrays
|
||||||
*/
|
*/
|
||||||
private XMLParserConfiguration (final boolean keepStrings, final String cDataTagName,
|
private XMLParserConfiguration (final boolean keepStrings, final String cDataTagName,
|
||||||
final boolean convertNilAttributeToNull, final Map<String, XMLXsiTypeConverter<?>> xsiTypeMap ) {
|
final boolean convertNilAttributeToNull, final Map<String, XMLXsiTypeConverter<?>> xsiTypeMap, final Set<String> forceList ) {
|
||||||
this.keepStrings = keepStrings;
|
this.keepStrings = keepStrings;
|
||||||
this.cDataTagName = cDataTagName;
|
this.cDataTagName = cDataTagName;
|
||||||
this.convertNilAttributeToNull = convertNilAttributeToNull;
|
this.convertNilAttributeToNull = convertNilAttributeToNull;
|
||||||
this.xsiTypeMap = Collections.unmodifiableMap(xsiTypeMap);
|
this.xsiTypeMap = Collections.unmodifiableMap(xsiTypeMap);
|
||||||
|
this.forceList = Collections.unmodifiableSet(forceList);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -174,7 +185,8 @@ public class XMLParserConfiguration {
|
|||||||
this.keepStrings,
|
this.keepStrings,
|
||||||
this.cDataTagName,
|
this.cDataTagName,
|
||||||
this.convertNilAttributeToNull,
|
this.convertNilAttributeToNull,
|
||||||
this.xsiTypeMap
|
this.xsiTypeMap,
|
||||||
|
this.forceList
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,4 +295,26 @@ public class XMLParserConfiguration {
|
|||||||
newConfig.xsiTypeMap = Collections.unmodifiableMap(cloneXsiTypeMap);
|
newConfig.xsiTypeMap = Collections.unmodifiableMap(cloneXsiTypeMap);
|
||||||
return newConfig;
|
return newConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When parsing the XML into JSON, specifies that tags that will be converted to arrays
|
||||||
|
* in this configuration {@code Set<String>} to parse the provided tags' values as arrays
|
||||||
|
* @return <code>forceList</code> unmodifiable configuration set.
|
||||||
|
*/
|
||||||
|
public Set<String> getForceList() {
|
||||||
|
return this.forceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When parsing the XML into JSON, specifies that tags that will be converted to arrays
|
||||||
|
* in this configuration {@code Set<String>} to parse the provided tags' values as arrays
|
||||||
|
* @param forceList {@code new HashSet<String>()} to parse the provided tags' values as arrays
|
||||||
|
* @return The existing configuration will not be modified. A new configuration is returned.
|
||||||
|
*/
|
||||||
|
public XMLParserConfiguration withForceList(final Set<String> forceList) {
|
||||||
|
XMLParserConfiguration newConfig = this.clone();
|
||||||
|
Set<String> cloneForceList = new HashSet<String>(forceList);
|
||||||
|
newConfig.forceList = Collections.unmodifiableSet(cloneForceList);
|
||||||
|
return newConfig;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@ import java.io.FileWriter;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
@ -903,7 +905,172 @@ public class XMLConfigurationTest {
|
|||||||
Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray);
|
Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test forceList parameter
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSimpleForceList() {
|
||||||
|
String xmlStr =
|
||||||
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"+
|
||||||
|
"<addresses>\n"+
|
||||||
|
" <address>\n"+
|
||||||
|
" <name>Sherlock Holmes</name>\n"+
|
||||||
|
" </address>\n"+
|
||||||
|
"</addresses>";
|
||||||
|
|
||||||
|
String expectedStr =
|
||||||
|
"{\"addresses\":[{\"address\":{\"name\":\"Sherlock Holmes\"}}]}";
|
||||||
|
|
||||||
|
Set<String> forceList = new HashSet<String>();
|
||||||
|
forceList.add("addresses");
|
||||||
|
|
||||||
|
XMLParserConfiguration config =
|
||||||
|
new XMLParserConfiguration()
|
||||||
|
.withForceList(forceList);
|
||||||
|
JSONObject jsonObject = XML.toJSONObject(xmlStr, config);
|
||||||
|
JSONObject expetedJsonObject = new JSONObject(expectedStr);
|
||||||
|
|
||||||
|
Util.compareActualVsExpectedJsonObjects(jsonObject, expetedJsonObject);
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void testLongForceList() {
|
||||||
|
String xmlStr =
|
||||||
|
"<servers>"+
|
||||||
|
"<server>"+
|
||||||
|
"<name>host1</name>"+
|
||||||
|
"<os>Linux</os>"+
|
||||||
|
"<interfaces>"+
|
||||||
|
"<interface>"+
|
||||||
|
"<name>em0</name>"+
|
||||||
|
"<ip_address>10.0.0.1</ip_address>"+
|
||||||
|
"</interface>"+
|
||||||
|
"</interfaces>"+
|
||||||
|
"</server>"+
|
||||||
|
"</servers>";
|
||||||
|
|
||||||
|
String expectedStr =
|
||||||
|
"{"+
|
||||||
|
"\"servers\": ["+
|
||||||
|
"{"+
|
||||||
|
"\"server\": {"+
|
||||||
|
"\"name\": \"host1\","+
|
||||||
|
"\"os\": \"Linux\","+
|
||||||
|
"\"interfaces\": ["+
|
||||||
|
"{"+
|
||||||
|
"\"interface\": {"+
|
||||||
|
"\"name\": \"em0\","+
|
||||||
|
"\"ip_address\": \"10.0.0.1\""+
|
||||||
|
"}}]}}]}";
|
||||||
|
|
||||||
|
Set<String> forceList = new HashSet<String>();
|
||||||
|
forceList.add("servers");
|
||||||
|
forceList.add("interfaces");
|
||||||
|
|
||||||
|
XMLParserConfiguration config =
|
||||||
|
new XMLParserConfiguration()
|
||||||
|
.withForceList(forceList);
|
||||||
|
JSONObject jsonObject = XML.toJSONObject(xmlStr, config);
|
||||||
|
JSONObject expetedJsonObject = new JSONObject(expectedStr);
|
||||||
|
|
||||||
|
Util.compareActualVsExpectedJsonObjects(jsonObject, expetedJsonObject);
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void testMultipleTagForceList() {
|
||||||
|
String xmlStr =
|
||||||
|
"<addresses>\n"+
|
||||||
|
" <address>\n"+
|
||||||
|
" <name>Sherlock Holmes</name>\n"+
|
||||||
|
" <name>John H. Watson</name>\n"+
|
||||||
|
" </address>\n"+
|
||||||
|
"</addresses>";
|
||||||
|
|
||||||
|
String expectedStr =
|
||||||
|
"{"+
|
||||||
|
"\"addresses\":["+
|
||||||
|
"{"+
|
||||||
|
"\"address\":["+
|
||||||
|
"{"+
|
||||||
|
"\"name\":["+
|
||||||
|
"\"Sherlock Holmes\","+
|
||||||
|
"\"John H. Watson\""+
|
||||||
|
"]"+
|
||||||
|
"}"+
|
||||||
|
"]"+
|
||||||
|
"}"+
|
||||||
|
"]"+
|
||||||
|
"}";
|
||||||
|
|
||||||
|
Set<String> forceList = new HashSet<String>();
|
||||||
|
forceList.add("addresses");
|
||||||
|
forceList.add("address");
|
||||||
|
forceList.add("name");
|
||||||
|
|
||||||
|
XMLParserConfiguration config =
|
||||||
|
new XMLParserConfiguration()
|
||||||
|
.withForceList(forceList);
|
||||||
|
JSONObject jsonObject = XML.toJSONObject(xmlStr, config);
|
||||||
|
JSONObject expetedJsonObject = new JSONObject(expectedStr);
|
||||||
|
|
||||||
|
Util.compareActualVsExpectedJsonObjects(jsonObject, expetedJsonObject);
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void testEmptyForceList() {
|
||||||
|
String xmlStr =
|
||||||
|
"<addresses></addresses>";
|
||||||
|
|
||||||
|
String expectedStr =
|
||||||
|
"{\"addresses\":[]}";
|
||||||
|
|
||||||
|
Set<String> forceList = new HashSet<String>();
|
||||||
|
forceList.add("addresses");
|
||||||
|
|
||||||
|
XMLParserConfiguration config =
|
||||||
|
new XMLParserConfiguration()
|
||||||
|
.withForceList(forceList);
|
||||||
|
JSONObject jsonObject = XML.toJSONObject(xmlStr, config);
|
||||||
|
JSONObject expetedJsonObject = new JSONObject(expectedStr);
|
||||||
|
|
||||||
|
Util.compareActualVsExpectedJsonObjects(jsonObject, expetedJsonObject);
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void testContentForceList() {
|
||||||
|
String xmlStr =
|
||||||
|
"<addresses>Baker Street</addresses>";
|
||||||
|
|
||||||
|
String expectedStr =
|
||||||
|
"{\"addresses\":[\"Baker Street\"]}";
|
||||||
|
|
||||||
|
Set<String> forceList = new HashSet<String>();
|
||||||
|
forceList.add("addresses");
|
||||||
|
|
||||||
|
XMLParserConfiguration config =
|
||||||
|
new XMLParserConfiguration()
|
||||||
|
.withForceList(forceList);
|
||||||
|
JSONObject jsonObject = XML.toJSONObject(xmlStr, config);
|
||||||
|
JSONObject expetedJsonObject = new JSONObject(expectedStr);
|
||||||
|
|
||||||
|
Util.compareActualVsExpectedJsonObjects(jsonObject, expetedJsonObject);
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void testEmptyTagForceList() {
|
||||||
|
String xmlStr =
|
||||||
|
"<addresses />";
|
||||||
|
|
||||||
|
String expectedStr =
|
||||||
|
"{\"addresses\":[]}";
|
||||||
|
|
||||||
|
Set<String> forceList = new HashSet<String>();
|
||||||
|
forceList.add("addresses");
|
||||||
|
|
||||||
|
XMLParserConfiguration config =
|
||||||
|
new XMLParserConfiguration()
|
||||||
|
.withForceList(forceList);
|
||||||
|
JSONObject jsonObject = XML.toJSONObject(xmlStr, config);
|
||||||
|
JSONObject expetedJsonObject = new JSONObject(expectedStr);
|
||||||
|
|
||||||
|
Util.compareActualVsExpectedJsonObjects(jsonObject, expetedJsonObject);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method, given an input string and expected result,
|
* Convenience method, given an input string and expected result,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user