package org.json.junit; /* Public Domain. */ import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.HashSet; import java.util.Set; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.XML; import org.json.XMLParserConfiguration; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import static org.junit.Assert.*; /** * Tests for JSON-Java XML.java with XMLParserConfiguration.java */ public class XMLConfigurationTest { /** * JUnit supports temporary files and folders that are cleaned up after the test. * https://garygregory.wordpress.com/2010/01/20/junit-tip-use-rules-to-manage-temporary-files-and-folders/ */ @Rule public TemporaryFolder testFolder = new TemporaryFolder(); /** * JSONObject from a null XML string. * Expects a NullPointerException */ @Test(expected=NullPointerException.class) public void shouldHandleNullXML() { String xmlStr = null; JSONObject jsonObject = XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); assertTrue("jsonObject should be empty", jsonObject.isEmpty()); } /** * Empty JSONObject from an empty XML string. */ @Test public void shouldHandleEmptyXML() { String xmlStr = ""; JSONObject jsonObject = XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); assertTrue("jsonObject should be empty", jsonObject.isEmpty()); } /** * Empty JSONObject from a non-XML string. */ @Test public void shouldHandleNonXML() { String xmlStr = "{ \"this is\": \"not xml\"}"; JSONObject jsonObject = XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); assertTrue("xml string should be empty", jsonObject.isEmpty()); } /** * Invalid XML string (tag contains a frontslash). * Expects a JSONException */ @Test public void shouldHandleInvalidSlashInTag() { String xmlStr = "\n"+ "\n"+ "
\n"+ " \n"+ " abc street\n"+ "
\n"+ "
"; try { XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); fail("Expecting a JSONException"); } catch (JSONException e) { assertEquals("Expecting an exception message", "Misshaped tag at 176 [character 14 line 4]", e.getMessage()); } } /** * Invalid XML string ('!' char in tag) * Expects a JSONException */ @Test public void shouldHandleInvalidBangInTag() { String xmlStr = "\n"+ "\n"+ "
\n"+ " \n"+ " \n"+ "
\n"+ "
"; try { XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); fail("Expecting a JSONException"); } catch (JSONException e) { assertEquals("Expecting an exception message", "Misshaped meta tag at 214 [character 12 line 7]", e.getMessage()); } } /** * Invalid XML string ('!' char and no closing tag brace) * Expects a JSONException */ @Test public void shouldHandleInvalidBangNoCloseInTag() { String xmlStr = "\n"+ "\n"+ "
\n"+ " \n"+ " \n"+ ""; try { XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); fail("Expecting a JSONException"); } catch (JSONException e) { assertEquals("Expecting an exception message", "Misshaped meta tag at 213 [character 12 line 7]", e.getMessage()); } } /** * Invalid XML string (no end brace for tag) * Expects JSONException */ @Test public void shouldHandleNoCloseStartTag() { String xmlStr = "\n"+ "\n"+ "
\n"+ " \n"+ " \n"+ ""; try { XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); fail("Expecting a JSONException"); } catch (JSONException e) { assertEquals("Expecting an exception message", "Misplaced '<' at 193 [character 4 line 6]", e.getMessage()); } } /** * Invalid XML string (partial CDATA chars in tag name) * Expects JSONException */ @Test public void shouldHandleInvalidCDATABangInTag() { String xmlStr = "\n"+ "\n"+ "
\n"+ " Joe Tester\n"+ " \n"+ "
\n"+ "
"; try { XMLParserConfiguration config = new XMLParserConfiguration().withcDataTagName("altContent"); XML.toJSONObject(xmlStr, config); fail("Expecting a JSONException"); } catch (JSONException e) { assertEquals("Expecting an exception message", "Expected 'CDATA[' at 204 [character 11 line 5]", e.getMessage()); } } /** * Null JSONObject in XML.toString() */ @Test public void shouldHandleNullJSONXML() { JSONObject jsonObject= null; String actualXml = XML.toString(jsonObject, null, XMLParserConfiguration.KEEP_STRINGS); assertEquals("generated XML does not equal expected XML","\"null\"",actualXml); } /** * Empty JSONObject in XML.toString() */ @Test public void shouldHandleEmptyJSONXML() { JSONObject jsonObject= new JSONObject(); String xmlStr = XML.toString(jsonObject, null, XMLParserConfiguration.KEEP_STRINGS); assertTrue("xml string should be empty", xmlStr.isEmpty()); } /** * No SML start tag. The ending tag ends up being treated as content. */ @Test public void shouldHandleNoStartTag() { String xmlStr = "\n"+ "\n"+ "
\n"+ " \n"+ " >\n"+ "
\n"+ "
"; String expectedStr = "{\"addresses\":{\"address\":{\"name\":\"\",\"nocontent\":\"\",\""+ "content\":\">\"},\"xsi:noNamespaceSchemaLocation\":\"test.xsd\",\""+ "xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"}}"; JSONObject jsonObject = XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); JSONObject expectedJsonObject = new JSONObject(expectedStr); Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); } /** * Valid XML to JSONObject */ @Test public void shouldHandleSimpleXML() { String xmlStr = "\n"+ "\n"+ "
\n"+ " Joe Tester\n"+ " [CDATA[Baker street 5]\n"+ " \n"+ " true\n"+ " false\n"+ " null\n"+ " 42\n"+ " -23\n"+ " -23.45\n"+ " -23x.45\n"+ " 1, 2, 3, 4.1, 5.2\n"+ "
\n"+ "
"; String expectedStr = "{\"addresses\":{\"address\":{\"street\":\"[CDATA[Baker street 5]\","+ "\"name\":\"Joe Tester\",\"NothingHere\":\"\",TrueValue:true,\n"+ "\"FalseValue\":false,\"NullValue\":null,\"PositiveValue\":42,\n"+ "\"NegativeValue\":-23,\"DoubleValue\":-23.45,\"Nan\":-23x.45,\n"+ "\"ArrayOfNum\":\"1, 2, 3, 4.1, 5.2\"\n"+ "},\"xsi:noNamespaceSchemaLocation\":"+ "\"test.xsd\",\"xmlns:xsi\":\"http://www.w3.org/2001/"+ "XMLSchema-instance\"}}"; XMLParserConfiguration config = new XMLParserConfiguration().withcDataTagName("altContent"); compareStringToJSONObject(xmlStr, expectedStr, config); compareReaderToJSONObject(xmlStr, expectedStr, config); compareFileToJSONObject(xmlStr, expectedStr); } /** * Valid XML with comments to JSONObject */ @Test public void shouldHandleCommentsInXML() { String xmlStr = "\n"+ "\n"+ "\n"+ "
\n"+ " comment ]]>\n"+ " Joe Tester\n"+ " \n"+ " Baker street 5\n"+ "
\n"+ "
"; XMLParserConfiguration config = new XMLParserConfiguration().withcDataTagName("altContent"); JSONObject jsonObject = XML.toJSONObject(xmlStr, config); String expectedStr = "{\"addresses\":{\"address\":{\"street\":\"Baker "+ "street 5\",\"name\":\"Joe Tester\",\"altContent\":\" this is -- "+ " comment \"}}}"; JSONObject expectedJsonObject = new JSONObject(expectedStr); Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); } /** * Valid XML to XML.toString() */ @Test public void shouldHandleToString() { String xmlStr = "\n"+ "\n"+ "
\n"+ " [CDATA[Joe & T > e < s " t ' er]]\n"+ " Baker street 5\n"+ " 1, 2, 3, 4.1, 5.2\n"+ "
\n"+ "
"; String expectedStr = "{\"addresses\":{\"address\":{\"street\":\"Baker street 5\","+ "\"name\":\"[CDATA[Joe & T > e < s \\\" t \\\' er]]\","+ "\"ArrayOfNum\":\"1, 2, 3, 4.1, 5.2\"\n"+ "},\"xsi:noNamespaceSchemaLocation\":"+ "\"test.xsd\",\"xmlns:xsi\":\"http://www.w3.org/2001/"+ "XMLSchema-instance\"}}"; JSONObject jsonObject = XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); String xmlToStr = XML.toString(jsonObject, null, XMLParserConfiguration.KEEP_STRINGS); JSONObject finalJsonObject = XML.toJSONObject(xmlToStr, XMLParserConfiguration.KEEP_STRINGS); JSONObject expectedJsonObject = new JSONObject(expectedStr); Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); Util.compareActualVsExpectedJsonObjects(finalJsonObject,expectedJsonObject); } /** * Converting a JSON doc containing '>' content to JSONObject, then * XML.toString() should result in valid XML. */ @Test public void shouldHandleContentNoArraytoString() { String expectedStr = "{\"addresses\":{\"altContent\":\">\"}}"; JSONObject expectedJsonObject = new JSONObject(expectedStr); XMLParserConfiguration config = new XMLParserConfiguration().withcDataTagName("altContent"); String finalStr = XML.toString(expectedJsonObject, null, config); String expectedFinalStr = ">"; assertTrue("Should handle expectedFinal: ["+expectedStr+"] final: ["+ finalStr+"]", expectedFinalStr.equals(finalStr)); } /** * Converting a JSON doc containing a 'content' array to JSONObject, then * XML.toString() should result in valid XML. * TODO: This is probably an error in how the 'content' keyword is used. */ @Test public void shouldHandleContentArraytoString() { String expectedStr = "{\"addresses\":{\"altContent\":[1, 2, 3]}}"; JSONObject expectedJsonObject = new JSONObject(expectedStr); XMLParserConfiguration config = new XMLParserConfiguration().withcDataTagName("altContent"); String finalStr = XML.toString(expectedJsonObject, null, config); String expectedFinalStr = ""+ "1\n2\n3"+ ""; assertTrue("Should handle expectedFinal: ["+expectedStr+"] final: ["+ finalStr+"]", expectedFinalStr.equals(finalStr)); } /** * Converting a JSON doc containing a named array to JSONObject, then * XML.toString() should result in valid XML. */ @Test public void shouldHandleArraytoString() { String expectedStr = "{\"addresses\":{"+ "\"something\":[1, 2, 3]}}"; JSONObject expectedJsonObject = new JSONObject(expectedStr); String finalStr = XML.toString(expectedJsonObject, null, XMLParserConfiguration.KEEP_STRINGS); String expectedFinalStr = ""+ "123"+ ""; assertTrue("Should handle expectedFinal: ["+expectedStr+"] final: ["+ finalStr+"]", expectedFinalStr.equals(finalStr)); } /** * Tests that the XML output for empty arrays is consistent. */ @Test public void shouldHandleEmptyArray(){ final JSONObject jo1 = new JSONObject(); jo1.put("array",new Object[]{}); final JSONObject jo2 = new JSONObject(); jo2.put("array",new JSONArray()); final String expected = ""; String output1 = XML.toString(jo1, "jo", XMLParserConfiguration.KEEP_STRINGS); assertEquals("Expected an empty root tag", expected, output1); String output2 = XML.toString(jo2, "jo", XMLParserConfiguration.KEEP_STRINGS); assertEquals("Expected an empty root tag", expected, output2); } /** * Tests that the XML output for arrays is consistent when an internal array is empty. */ @Test public void shouldHandleEmptyMultiArray(){ final JSONObject jo1 = new JSONObject(); jo1.put("arr",new Object[]{"One", new String[]{}, "Four"}); final JSONObject jo2 = new JSONObject(); jo2.put("arr",new JSONArray(new Object[]{"One", new JSONArray(new String[]{}), "Four"})); final String expected = "OneFour"; String output1 = XML.toString(jo1, "jo", XMLParserConfiguration.KEEP_STRINGS); assertEquals("Expected a matching array", expected, output1); String output2 = XML.toString(jo2, "jo", XMLParserConfiguration.KEEP_STRINGS); assertEquals("Expected a matching array", expected, output2); } /** * Tests that the XML output for arrays is consistent when arrays are not empty. */ @Test public void shouldHandleNonEmptyArray(){ final JSONObject jo1 = new JSONObject(); jo1.put("arr",new String[]{"One", "Two", "Three"}); final JSONObject jo2 = new JSONObject(); jo2.put("arr",new JSONArray(new String[]{"One", "Two", "Three"})); final String expected = "OneTwoThree"; String output1 = XML.toString(jo1, "jo", XMLParserConfiguration.KEEP_STRINGS); assertEquals("Expected a non empty root tag", expected, output1); String output2 = XML.toString(jo2, "jo", XMLParserConfiguration.KEEP_STRINGS); assertEquals("Expected a non empty root tag", expected, output2); } /** * Tests that the XML output for arrays is consistent when arrays are not empty and contain internal arrays. */ @Test public void shouldHandleMultiArray(){ final JSONObject jo1 = new JSONObject(); jo1.put("arr",new Object[]{"One", new String[]{"Two", "Three"}, "Four"}); final JSONObject jo2 = new JSONObject(); jo2.put("arr",new JSONArray(new Object[]{"One", new JSONArray(new String[]{"Two", "Three"}), "Four"})); final String expected = "OneTwoThreeFour"; String output1 = XML.toString(jo1, "jo", XMLParserConfiguration.KEEP_STRINGS); assertEquals("Expected a matching array", expected, output1); String output2 = XML.toString(jo2, "jo", XMLParserConfiguration.KEEP_STRINGS); assertEquals("Expected a matching array", expected, output2); } /** * Converting a JSON doc containing a named array of nested arrays to * JSONObject, then XML.toString() should result in valid XML. */ @Test public void shouldHandleNestedArraytoString() { String xmlStr = "{\"addresses\":{\"address\":{\"name\":\"\",\"nocontent\":\"\","+ "\"outer\":[[1], [2], [3]]},\"xsi:noNamespaceSchemaLocation\":\"test.xsd\",\""+ "xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"}}"; JSONObject jsonObject = new JSONObject(xmlStr); String finalStr = XML.toString(jsonObject, null, XMLParserConfiguration.ORIGINAL); JSONObject finalJsonObject = XML.toJSONObject(finalStr); String expectedStr = "
"+ "12"+ "3"+ "
test.xsdhttp://www.w3.org/2001/XMLSche"+ "ma-instance
"; JSONObject expectedJsonObject = XML.toJSONObject(expectedStr, XMLParserConfiguration.ORIGINAL); Util.compareActualVsExpectedJsonObjects(finalJsonObject,expectedJsonObject); } /** * Possible bug: * Illegal node-names must be converted to legal XML-node-names. * The given example shows 2 nodes which are valid for JSON, but not for XML. * Therefore illegal arguments should be converted to e.g. an underscore (_). */ @Test public void shouldHandleIllegalJSONNodeNames() { JSONObject inputJSON = new JSONObject(); inputJSON.append("123IllegalNode", "someValue1"); inputJSON.append("Illegal@node", "someValue2"); String result = XML.toString(inputJSON, null, XMLParserConfiguration.KEEP_STRINGS); /* * This is invalid XML. Names should not begin with digits or contain * certain values, including '@'. One possible solution is to replace * illegal chars with '_', in which case the expected output would be: * <___IllegalNode>someValue1someValue2 */ String expected = "<123IllegalNode>someValue1someValue2"; assertEquals("Length", expected.length(), result.length()); assertTrue("123IllegalNode", result.contains("<123IllegalNode>someValue1")); assertTrue("Illegal@node", result.contains("someValue2")); } /** * JSONObject with NULL value, to XML.toString() */ @Test public void shouldHandleNullNodeValue() { JSONObject inputJSON = new JSONObject(); inputJSON.put("nullValue", JSONObject.NULL); // This is a possible preferred result // String expectedXML = ""; /** * This is the current behavior. JSONObject.NULL is emitted as * the string, "null". */ String actualXML = "null"; String resultXML = XML.toString(inputJSON, null, XMLParserConfiguration.KEEP_STRINGS); assertEquals(actualXML, resultXML); } @Test public void shouldHandleEmptyNodeValue() { JSONObject inputJSON = new JSONObject(); inputJSON.put("Emptyness", ""); String expectedXmlWithoutExplicitEndTag = ""; String expectedXmlWithExplicitEndTag = ""; assertEquals(expectedXmlWithoutExplicitEndTag, XML.toString(inputJSON, null, new XMLParserConfiguration().withCloseEmptyTag(false))); assertEquals(expectedXmlWithExplicitEndTag, XML.toString(inputJSON, null, new XMLParserConfiguration().withCloseEmptyTag(true))); } @Test public void shouldKeepConfigurationIntactAndUpdateCloseEmptyTagChoice() { XMLParserConfiguration keepStrings = XMLParserConfiguration.KEEP_STRINGS; XMLParserConfiguration keepStringsAndCloseEmptyTag = keepStrings.withCloseEmptyTag(true); XMLParserConfiguration keepDigits = keepStringsAndCloseEmptyTag.withKeepStrings(false); XMLParserConfiguration keepDigitsAndNoCloseEmptyTag = keepDigits.withCloseEmptyTag(false); assertTrue(keepStrings.isKeepStrings()); assertFalse(keepStrings.isCloseEmptyTag()); assertTrue(keepStringsAndCloseEmptyTag.isKeepStrings()); assertTrue(keepStringsAndCloseEmptyTag.isCloseEmptyTag()); assertFalse(keepDigits.isKeepStrings()); assertTrue(keepDigits.isCloseEmptyTag()); assertFalse(keepDigitsAndNoCloseEmptyTag.isKeepStrings()); assertFalse(keepDigitsAndNoCloseEmptyTag.isCloseEmptyTag()); } /** * Investigate exactly how the "content" keyword works */ @Test public void contentOperations() { /* * When a standalone 0) then return]]>"; JSONObject jsonObject = XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); assertTrue("1. 3 items", 3 == jsonObject.length()); assertTrue("1. empty tag1", "".equals(jsonObject.get("tag1"))); assertTrue("1. empty tag2", "".equals(jsonObject.get("tag2"))); assertTrue("1. content found", "if (a < b && a > 0) then return".equals(jsonObject.get("content"))); // multiple consecutive standalone cdatas are accumulated into an array xmlStr = " 0) then return]]>"; jsonObject = XML.toJSONObject(xmlStr, new XMLParserConfiguration() .withKeepStrings(true) .withcDataTagName("altContent")); assertTrue("2. 3 items", 3 == jsonObject.length()); assertTrue("2. empty tag1", "".equals(jsonObject.get("tag1"))); assertTrue("2. empty tag2", "".equals(jsonObject.get("tag2"))); assertTrue("2. content array found", jsonObject.get("altContent") instanceof JSONArray); JSONArray jsonArray = jsonObject.getJSONArray("altContent"); assertTrue("2. array size", jsonArray.length() == 2); assertTrue("2. content array entry 0", "if (a < b && a > 0) then return".equals(jsonArray.get(0))); assertTrue("2. content array entry 1", "here is another cdata".equals(jsonArray.get(1))); /* * text content is accumulated in a "content" inside a local JSONObject. * If there is only one instance, it is saved in the context (a different JSONObject * from the calling code. and the content element is discarded. */ xmlStr = "value 1"; jsonObject = XML.toJSONObject(xmlStr, new XMLParserConfiguration() .withKeepStrings(true) .withcDataTagName("altContent")); assertTrue("3. 2 items", 1 == jsonObject.length()); assertTrue("3. value tag1", "value 1".equals(jsonObject.get("tag1"))); /* * array-style text content (multiple tags with the same name) is * accumulated in a local JSONObject with key="content" and value=JSONArray, * saved in the context, and then the local JSONObject is discarded. */ xmlStr = "value 12true"; jsonObject = XML.toJSONObject(xmlStr, new XMLParserConfiguration() .withKeepStrings(true) .withcDataTagName("altContent")); assertTrue("4. 1 item", 1 == jsonObject.length()); assertTrue("4. content array found", jsonObject.get("tag1") instanceof JSONArray); jsonArray = jsonObject.getJSONArray("tag1"); assertTrue("4. array size", jsonArray.length() == 3); assertTrue("4. content array entry 0", "value 1".equals(jsonArray.get(0))); assertTrue("4. content array entry 1", jsonArray.getInt(1) == 2); assertTrue("4. content array entry 2", jsonArray.getBoolean(2) == true); /* * Complex content is accumulated in a "content" field. For example, an element * may contain a mix of child elements and text. Each text segment is * accumulated to content. */ xmlStr = "val1val2"; jsonObject = XML.toJSONObject(xmlStr, new XMLParserConfiguration() .withKeepStrings(true) .withcDataTagName("altContent")); assertTrue("5. 1 item", 1 == jsonObject.length()); assertTrue("5. jsonObject found", jsonObject.get("tag1") instanceof JSONObject); jsonObject = jsonObject.getJSONObject("tag1"); assertTrue("5. 2 contained items", 2 == jsonObject.length()); assertTrue("5. contained tag", "".equals(jsonObject.get("tag2"))); assertTrue("5. contained content jsonArray found", jsonObject.get("altContent") instanceof JSONArray); jsonArray = jsonObject.getJSONArray("altContent"); assertTrue("5. array size", jsonArray.length() == 2); assertTrue("5. content array entry 0", "val1".equals(jsonArray.get(0))); assertTrue("5. content array entry 1", "val2".equals(jsonArray.get(1))); /* * If there is only 1 complex text content, then it is accumulated in a * "content" field as a string. */ xmlStr = "val1"; jsonObject = XML.toJSONObject(xmlStr, new XMLParserConfiguration() .withKeepStrings(true) .withcDataTagName("altContent")); assertTrue("6. 1 item", 1 == jsonObject.length()); assertTrue("6. jsonObject found", jsonObject.get("tag1") instanceof JSONObject); jsonObject = jsonObject.getJSONObject("tag1"); assertTrue("6. contained content found", "val1".equals(jsonObject.get("altContent"))); assertTrue("6. contained tag2", "".equals(jsonObject.get("tag2"))); /* * In this corner case, the content sibling happens to have key=content * We end up with an array within an array, and no content element. * This is probably a bug. */ xmlStr = "val1"; jsonObject = XML.toJSONObject(xmlStr, new XMLParserConfiguration() .withKeepStrings(true) .withcDataTagName("altContent")); assertTrue("7. 1 item", 1 == jsonObject.length()); assertTrue("7. jsonArray found", jsonObject.get("tag1") instanceof JSONArray); jsonArray = jsonObject.getJSONArray("tag1"); assertTrue("array size 1", jsonArray.length() == 1); assertTrue("7. contained array found", jsonArray.get(0) instanceof JSONArray); jsonArray = jsonArray.getJSONArray(0); assertTrue("7. inner array size 2", jsonArray.length() == 2); assertTrue("7. inner array item 0", "val1".equals(jsonArray.get(0))); assertTrue("7. inner array item 1", "".equals(jsonArray.get(1))); /* * Confirm behavior of original issue */ String jsonStr = "{"+ "\"Profile\": {"+ "\"list\": {"+ "\"history\": {"+ "\"entries\": ["+ "{"+ "\"deviceId\": \"id\","+ "\"altContent\": {"+ "\"material\": ["+ "{"+ "\"stuff\": false"+ "}"+ "]"+ "}"+ "}"+ "]"+ "}"+ "}"+ "}"+ "}"; jsonObject = new JSONObject(jsonStr); xmlStr = XML.toString(jsonObject, null, new XMLParserConfiguration() .withKeepStrings(true) .withcDataTagName("altContent")); /* * This is the created XML. Looks like content was mistaken for * complex (child node + text) XML. * * * * * id * {"material":[{"stuff":false}]} * * * * */ assertTrue("nothing to test here, see comment on created XML, above", true); } /** * JSON string lost leading zero and converted "True" to true. */ @Test public void testToJSONArray_jsonOutput() { final String originalXml = "011000True"; final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",1,\"00\",0],\"title\":true}}"); final JSONObject actualJsonOutput = XML.toJSONObject(originalXml, new XMLParserConfiguration().withKeepStrings(false)); Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected); } /** * JSON string cannot be reverted to original xml. */ @Test public void testToJSONArray_reversibility() { final String originalXml = "011000True"; XMLParserConfiguration config = new XMLParserConfiguration().withKeepStrings(false); final String revertedXml = XML.toString(XML.toJSONObject(originalXml, config), null, config); assertNotEquals(revertedXml, originalXml); } /** * test passes when using the new method toJsonArray. */ @Test public void testToJsonXML() { final String originalXml = "011000True"; final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",\"1\",\"00\",\"0\"],\"title\":\"True\"}}"); final JSONObject json = XML.toJSONObject(originalXml, new XMLParserConfiguration().withKeepStrings(true)); Util.compareActualVsExpectedJsonObjects(json, expected); final String reverseXml = XML.toString(json); // this reversal isn't exactly the same. use JSONML for an exact reversal final String expectedReverseXml = "01011000True"; assertEquals("length",expectedReverseXml.length(), reverseXml.length()); assertTrue("array contents", reverseXml.contains("011000")); assertTrue("item contents", reverseXml.contains("01")); assertTrue("title contents", reverseXml.contains("True")); } /** * test to validate certain conditions of XML unescaping. */ @Test public void testUnescape() { assertEquals("{\"xml\":\"Can cope <;\"}", XML.toJSONObject("Can cope <; ", XMLParserConfiguration.KEEP_STRINGS).toString()); assertEquals("Can cope <; ", XML.unescape("Can cope <; ")); assertEquals("{\"xml\":\"Can cope & ;\"}", XML.toJSONObject("Can cope & ; ", XMLParserConfiguration.KEEP_STRINGS).toString()); assertEquals("Can cope & ; ", XML.unescape("Can cope & ; ")); assertEquals("{\"xml\":\"Can cope &;\"}", XML.toJSONObject("Can cope &; ", XMLParserConfiguration.KEEP_STRINGS).toString()); assertEquals("Can cope &; ", XML.unescape("Can cope &; ")); // unicode entity assertEquals("{\"xml\":\"Can cope 4;\"}", XML.toJSONObject("Can cope 4; ", XMLParserConfiguration.KEEP_STRINGS).toString()); assertEquals("Can cope 4; ", XML.unescape("Can cope 4; ")); // double escaped assertEquals("{\"xml\":\"Can cope <\"}", XML.toJSONObject("Can cope &lt; ", XMLParserConfiguration.KEEP_STRINGS).toString()); assertEquals("Can cope < ", XML.unescape("Can cope &lt; ")); assertEquals("{\"xml\":\"Can cope 4\"}", XML.toJSONObject("Can cope &#x34; ", XMLParserConfiguration.KEEP_STRINGS).toString()); assertEquals("Can cope 4 ", XML.unescape("Can cope &#x34; ")); } /** * Confirm XMLParserConfiguration functionality */ @Test public void testConfig() { /** * 1st param is whether to keep the raw string, or call * XML.stringToValue(), which may convert the token to * boolean, null, or number. * 2nd param is what JSON name to use for strings that are * evaluated as xml content data in complex objects, e.g. * * value * content data * */ String xmlStr = "\n"+ "\n"+ "
\n"+ " content 1\n"+ " Sherlock Holmes\n"+ " content 2\n"+ " Baker street 5\n"+ " content 3\n"+ " 1\n"+ "
\n"+ "
"; // keep strings, use the altContent tag XMLParserConfiguration config = new XMLParserConfiguration() .withKeepStrings(true) .withcDataTagName("altContent"); JSONObject jsonObject = XML.toJSONObject(xmlStr, config); // num is parsed as a string assertEquals(jsonObject.getJSONObject("addresses"). getJSONObject("address").getString("num"), "1"); // complex content is collected in an 'altContent' array JSONArray jsonArray = jsonObject.getJSONObject("addresses"). getJSONObject("address").getJSONArray("altContent"); String expectedStr = "[\"content 1\", \"content 2\", \"content 3\"]"; JSONArray expectedJsonArray = new JSONArray(expectedStr); Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray); // keepstrings only jsonObject = XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); // num is parsed as a string assertEquals(jsonObject.getJSONObject("addresses"). getJSONObject("address").getString("num"), "1"); // complex content is collected in an 'content' array jsonArray = jsonObject.getJSONObject("addresses"). getJSONObject("address").getJSONArray("content"); expectedJsonArray = new JSONArray(expectedStr); Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray); // use alternate content name config = new XMLParserConfiguration().withcDataTagName("altContent"); jsonObject = XML.toJSONObject(xmlStr, config); // num is parsed as a number assertEquals(jsonObject.getJSONObject("addresses"). getJSONObject("address").getInt("num"), 1); // complex content is collected in an 'altContent' array jsonArray = jsonObject.getJSONObject("addresses"). getJSONObject("address").getJSONArray("altContent"); expectedJsonArray = new JSONArray(expectedStr); Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray); } /** * Test forceList parameter */ @Test public void testSimpleForceList() { String xmlStr = "\n"+ "\n"+ "
\n"+ " Sherlock Holmes\n"+ "
\n"+ "
"; String expectedStr = "{\"addresses\":[{\"address\":{\"name\":\"Sherlock Holmes\"}}]}"; Set forceList = new HashSet(); 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 = ""+ ""+ "host1"+ "Linux"+ ""+ ""+ "em0"+ "10.0.0.1"+ ""+ ""+ ""+ ""; String expectedStr = "{"+ "\"servers\": ["+ "{"+ "\"server\": {"+ "\"name\": \"host1\","+ "\"os\": \"Linux\","+ "\"interfaces\": ["+ "{"+ "\"interface\": {"+ "\"name\": \"em0\","+ "\"ip_address\": \"10.0.0.1\""+ "}}]}}]}"; Set forceList = new HashSet(); 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 = "\n"+ "
\n"+ " Sherlock Holmes\n"+ " John H. Watson\n"+ "
\n"+ "
"; String expectedStr = "{"+ "\"addresses\":["+ "{"+ "\"address\":["+ "{"+ "\"name\":["+ "\"Sherlock Holmes\","+ "\"John H. Watson\""+ "]"+ "}"+ "]"+ "}"+ "]"+ "}"; Set forceList = new HashSet(); 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 = ""; String expectedStr = "{\"addresses\":[]}"; Set forceList = new HashSet(); 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 = "Baker Street"; String expectedStr = "{\"addresses\":[\"Baker Street\"]}"; Set forceList = new HashSet(); 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 = ""; String expectedStr = "{\"addresses\":[]}"; Set forceList = new HashSet(); 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 testMaxNestingDepthIsSet() { XMLParserConfiguration xmlParserConfiguration = XMLParserConfiguration.ORIGINAL; assertEquals(xmlParserConfiguration.getMaxNestingDepth(), XMLParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH); xmlParserConfiguration = xmlParserConfiguration.withMaxNestingDepth(42); assertEquals(xmlParserConfiguration.getMaxNestingDepth(), 42); xmlParserConfiguration = xmlParserConfiguration.withMaxNestingDepth(0); assertEquals(xmlParserConfiguration.getMaxNestingDepth(), 0); xmlParserConfiguration = xmlParserConfiguration.withMaxNestingDepth(-31415926); assertEquals(xmlParserConfiguration.getMaxNestingDepth(), XMLParserConfiguration.UNDEFINED_MAXIMUM_NESTING_DEPTH); xmlParserConfiguration = xmlParserConfiguration.withMaxNestingDepth(Integer.MIN_VALUE); assertEquals(xmlParserConfiguration.getMaxNestingDepth(), XMLParserConfiguration.UNDEFINED_MAXIMUM_NESTING_DEPTH); } /** * Convenience method, given an input string and expected result, * convert to JSONObject and compare actual to expected result. * @param xmlStr the string to parse * @param expectedStr the expected JSON string * @param config provides more flexible XML parsing * flexible XML parsing. */ private void compareStringToJSONObject(String xmlStr, String expectedStr, XMLParserConfiguration config) { JSONObject expectedJsonObject = new JSONObject(expectedStr); JSONObject jsonObject = XML.toJSONObject(xmlStr, config); Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); } /** * Convenience method, given an input string and expected result, * convert to JSONObject via reader and compare actual to expected result. * @param xmlStr the string to parse * @param expectedStr the expected JSON string * @param config provides more flexible XML parsing */ private void compareReaderToJSONObject(String xmlStr, String expectedStr, XMLParserConfiguration config) { /* * Commenting out this method until the JSON-java code is updated * to support XML.toJSONObject(reader) */ JSONObject expectedJsonObject = new JSONObject(expectedStr); Reader reader = new StringReader(xmlStr); try { JSONObject jsonObject = XML.toJSONObject(reader, config); Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); } catch (Exception e) { assertTrue("Reader error: " +e.getMessage(), false); } finally { try { reader.close(); } catch (Exception e) {} } } /** * Convenience method, given an input string and expected result, convert to * JSONObject via file and compare actual to expected result. * * @param xmlStr * the string to parse * @param expectedStr * the expected JSON string * @throws IOException */ private void compareFileToJSONObject(String xmlStr, String expectedStr) { /* * Commenting out this method until the JSON-java code is updated * to support XML.toJSONObject(reader) */ try { JSONObject expectedJsonObject = new JSONObject(expectedStr); File tempFile = this.testFolder.newFile("fileToJSONObject.xml"); FileWriter fileWriter = new FileWriter(tempFile); try { fileWriter.write(xmlStr); } finally { fileWriter.close(); } Reader reader = new FileReader(tempFile); try { JSONObject jsonObject = XML.toJSONObject(reader); Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); } finally { reader.close(); } } catch (IOException e) { assertTrue("Error: " +e.getMessage(), false); } } }