diff --git a/src/main/java/com/github/underscore/U.java b/src/main/java/com/github/underscore/U.java index 1c0a5c63..7f545360 100644 --- a/src/main/java/com/github/underscore/U.java +++ b/src/main/java/com/github/underscore/U.java @@ -103,6 +103,7 @@ public class U extends Underscore { java.util.regex.Pattern.compile( UPPER + "+(?=" + UPPER + LOWER + ")|" + UPPER + "?" + LOWER + "|" + UPPER + "+|\\d+"); + private static final String ENCODING = "#encoding"; static { String[] deburredLetters = @@ -2826,8 +2827,8 @@ public static void fileJsonToXml( Path xmlFilePath = Paths.get(xmlFileName); String lineSeparator = System.lineSeparator(); if (result instanceof Map) { - if (((Map) result).containsKey("#encoding")) { - String encoding = String.valueOf(((Map) result).get("#encoding")); + if (((Map) result).containsKey(ENCODING)) { + String encoding = String.valueOf(((Map) result).get(ENCODING)); Files.write( xmlFilePath, formatString(Xml.toXml((Map) result, identStep), lineSeparator) @@ -2850,6 +2851,35 @@ public static void fileJsonToXml(String jsonFileName, String xmlFileName) throws fileJsonToXml(jsonFileName, xmlFileName, Xml.XmlStringBuilder.Step.TWO_SPACES); } + public static void streamJsonToXml( + InputStream jsonInputStream, + OutputStream xmlOutputStream, + Xml.XmlStringBuilder.Step identStep) + throws IOException { + byte[] bytes = jsonInputStream.readAllBytes(); + String jsonText = new String(removeBom(bytes), detectEncoding(bytes)); + Object jsonObject = U.fromJson(jsonText); + String lineSeparator = System.lineSeparator(); + String xml; + if (jsonObject instanceof Map) { + xml = formatString(Xml.toXml((Map) jsonObject, identStep), lineSeparator); + if (((Map) jsonObject).containsKey(ENCODING)) { + String encoding = String.valueOf(((Map) jsonObject).get(ENCODING)); + xmlOutputStream.write(xml.getBytes(encoding)); + } else { + xmlOutputStream.write(xml.getBytes(StandardCharsets.UTF_8)); + } + } else { + xml = formatString(Xml.toXml((List) jsonObject, identStep), lineSeparator); + xmlOutputStream.write(xml.getBytes(StandardCharsets.UTF_8)); + } + } + + public static void streamJsonToXml(InputStream jsonInputStream, OutputStream xmlOutputStream) + throws IOException { + streamJsonToXml(jsonInputStream, xmlOutputStream, Xml.XmlStringBuilder.Step.TWO_SPACES); + } + public static byte[] removeBom(byte[] bytes) { if ((bytes.length >= 3) && (bytes[0] == -17) && (bytes[1] == -69) && (bytes[2] == -65)) { return Arrays.copyOfRange(bytes, 3, bytes.length); diff --git a/src/test/java/com/github/underscore/UnderscoreTest.java b/src/test/java/com/github/underscore/UnderscoreTest.java index 21605d8b..f018e03c 100644 --- a/src/test/java/com/github/underscore/UnderscoreTest.java +++ b/src/test/java/com/github/underscore/UnderscoreTest.java @@ -1226,4 +1226,86 @@ void testListResult(@TempDir Path tempDir) throws IOException { xmlStr, "Should write XML using UTF-8 when result is a List"); } + + @Test + void testStreamJsonToXml_ObjectMap_DefaultEncoding() throws Exception { + String inputJson = "{\"root\":\"value\"}"; + ByteArrayInputStream inputStream = + new ByteArrayInputStream(inputJson.getBytes(StandardCharsets.UTF_8)); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + U.streamJsonToXml(inputStream, outputStream); + String expectedXml = + "" + + System.lineSeparator() + + "value"; + String actualXml = outputStream.toString(StandardCharsets.UTF_8); + assertEquals( + expectedXml, + actualXml, + "XML output should match expected XML for simple JSON object with default encoding"); + } + + @Test + void testStreamJsonToXml_ObjectMap_CustomEncoding() throws Exception { + String inputJson = "{\"root\":\"value\",\"#encoding\":\"UTF-16\"}"; + ByteArrayInputStream inputStream = + new ByteArrayInputStream(inputJson.getBytes(StandardCharsets.UTF_8)); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + U.streamJsonToXml(inputStream, outputStream, Xml.XmlStringBuilder.Step.TWO_SPACES); + String expectedXml = + "" + + System.lineSeparator() + + "value"; + String actualXml = outputStream.toString(StandardCharsets.UTF_16); + assertEquals( + expectedXml, + actualXml, + "XML output should match expected XML for simple JSON object with default encoding"); + } + + @Test + void testStreamJsonToXml_List() throws Exception { + String inputJson = "[{\"item\":42}]"; + ByteArrayInputStream inputStream = + new ByteArrayInputStream(inputJson.getBytes(StandardCharsets.UTF_8)); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + U.streamJsonToXml(inputStream, outputStream, Xml.XmlStringBuilder.Step.TWO_SPACES); + String expectedXml = + "" + + System.lineSeparator() + + "" + + System.lineSeparator() + + " " + + System.lineSeparator() + + " 42" + + System.lineSeparator() + + " " + + System.lineSeparator() + + ""; + String actualXml = outputStream.toString(StandardCharsets.UTF_8); + assertEquals( + expectedXml, + actualXml, + "XML output should match expected XML for JSON array root with default encoding"); + } + + @Test + void testStreamJsonToXml_InvalidJson_ThrowsException() { + String inputJson = "invalid"; + ByteArrayInputStream inputStream = + new ByteArrayInputStream(inputJson.getBytes(StandardCharsets.UTF_8)); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + Exception exception = + assertThrows( + Json.ParseException.class, + () -> + U.streamJsonToXml( + inputStream, + outputStream, + Xml.XmlStringBuilder.Step.TWO_SPACES)); + String actualMessage = exception.getMessage(); + assertTrue( + actualMessage.contains("Expected value"), + "Should throw exception if JSON is invalid"); + } }