This is an automated email from the ASF dual-hosted git repository. paulk pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 06c645979f4ae9bc42a2b5462d28af42cfe0781b Author: Paul King <[email protected]> AuthorDate: Mon Apr 13 14:25:58 2026 +1000 GROOVY-7571: XmlUtil should allow user to specify a character encoding when serializing --- .../src/main/java/groovy/xml/XmlUtil.java | 159 ++++++++++++++++++++- .../groovy-xml/src/spec/doc/xml-userguide.adoc | 9 ++ .../src/spec/test/UserGuideXmlUtilTest.groovy | 19 +++ 3 files changed, 182 insertions(+), 5 deletions(-) diff --git a/subprojects/groovy-xml/src/main/java/groovy/xml/XmlUtil.java b/subprojects/groovy-xml/src/main/java/groovy/xml/XmlUtil.java index f8530d957c..21304f80e2 100644 --- a/subprojects/groovy-xml/src/main/java/groovy/xml/XmlUtil.java +++ b/subprojects/groovy-xml/src/main/java/groovy/xml/XmlUtil.java @@ -55,7 +55,7 @@ import java.io.PrintWriter; import java.io.StringReader; import java.io.Writer; import java.net.URL; -import java.nio.charset.StandardCharsets; +import java.nio.charset.Charset; /** * Used for pretty printing XML content and other XML related utilities. @@ -283,6 +283,138 @@ public class XmlUtil { serialize(asStreamSource(xmlString), w, allowDocTypeDeclaration); } + // --- SerializeOptions overloads --- + + /** + * Return a pretty String version of the Element using the specified options. + * + * @param element the Element to serialize + * @param options the serialization options + * @return the pretty String representation of the Element + * @since 6.0.0 + */ + public static String serialize(Element element, SerializeOptions options) { + Writer sw = new StringBuilderWriter(); + serialize(new DOMSource(element), sw, options); + return sw.toString(); + } + + /** + * Write a pretty version of the Element to the OutputStream using the specified options. + * + * @param element the Element to serialize + * @param os the OutputStream to write to + * @param options the serialization options + * @since 6.0.0 + */ + public static void serialize(Element element, OutputStream os, SerializeOptions options) { + serialize(new DOMSource(element), os, options); + } + + /** + * Return a pretty String version of the Node using the specified options. + * + * @param node the Node to serialize + * @param options the serialization options + * @return the pretty String representation of the Node + * @since 6.0.0 + */ + public static String serialize(Node node, SerializeOptions options) { + Writer sw = new StringBuilderWriter(); + serialize(asStreamSource(asString(node)), sw, options); + return sw.toString(); + } + + /** + * Write a pretty version of the Node to the OutputStream using the specified options. + * + * @param node the Node to serialize + * @param os the OutputStream to write to + * @param options the serialization options + * @since 6.0.0 + */ + public static void serialize(Node node, OutputStream os, SerializeOptions options) { + serialize(asStreamSource(asString(node)), os, options); + } + + /** + * Return a pretty String version of the GPathResult using the specified options. + * + * @param node a GPathResult to serialize to a String + * @param options the serialization options + * @return the pretty String representation of the GPathResult + * @since 6.0.0 + */ + public static String serialize(GPathResult node, SerializeOptions options) { + Writer sw = new StringBuilderWriter(); + serialize(asStreamSource(asString(node)), sw, options); + return sw.toString(); + } + + /** + * Write a pretty version of the GPathResult to the OutputStream using the specified options. + * + * @param node a GPathResult to serialize + * @param os the OutputStream to write to + * @param options the serialization options + * @since 6.0.0 + */ + public static void serialize(GPathResult node, OutputStream os, SerializeOptions options) { + serialize(asStreamSource(asString(node)), os, options); + } + + /** + * Return a pretty String version of the XML content produced by the Writable using the specified options. + * + * @param writable the Writable to serialize + * @param options the serialization options + * @return the pretty String representation of the content from the Writable + * @since 6.0.0 + */ + public static String serialize(Writable writable, SerializeOptions options) { + Writer sw = new StringBuilderWriter(); + serialize(asStreamSource(asString(writable)), sw, options); + return sw.toString(); + } + + /** + * Write a pretty version of the XML content produced by the Writable to the OutputStream using the specified options. + * + * @param writable the Writable to serialize + * @param os the OutputStream to write to + * @param options the serialization options + * @since 6.0.0 + */ + public static void serialize(Writable writable, OutputStream os, SerializeOptions options) { + serialize(asStreamSource(asString(writable)), os, options); + } + + /** + * Return a pretty version of the XML content contained in the given String using the specified options. + * + * @param xmlString the String to serialize + * @param options the serialization options + * @return the pretty String representation of the original content + * @since 6.0.0 + */ + public static String serialize(String xmlString, SerializeOptions options) { + Writer sw = new StringBuilderWriter(); + serialize(asStreamSource(xmlString), sw, options); + return sw.toString(); + } + + /** + * Write a pretty version of the given XML string to the OutputStream using the specified options. + * + * @param xmlString the String to serialize + * @param os the OutputStream to write to + * @param options the serialization options + * @since 6.0.0 + */ + public static void serialize(String xmlString, OutputStream os, SerializeOptions options) { + serialize(asStreamSource(xmlString), os, options); + } + /** * Factory method to create a SAXParser configured to validate according to a particular schema language and * optionally providing the schema sources to validate with. @@ -526,22 +658,39 @@ public class XmlUtil { } private static void serialize(Source source, OutputStream os, boolean allowDocTypeDeclaration) { - serialize(source, new StreamResult(new OutputStreamWriter(os, StandardCharsets.UTF_8)), allowDocTypeDeclaration); + serialize(source, os, SerializeOptions.DEFAULT); + } + + private static void serialize(Source source, OutputStream os, SerializeOptions options) { + serialize(source, new StreamResult(new OutputStreamWriter(os, options.getCharset())), options); } private static void serialize(Source source, Writer w, boolean allowDocTypeDeclaration) { - serialize(source, new StreamResult(w), allowDocTypeDeclaration); + SerializeOptions options = new SerializeOptions(); + options.setAllowDocTypeDeclaration(allowDocTypeDeclaration); + serialize(source, new StreamResult(w), options); + } + + private static void serialize(Source source, Writer w, SerializeOptions options) { + serialize(source, new StreamResult(w), options); } private static void serialize(Source source, StreamResult target, boolean allowDocTypeDeclaration) { + SerializeOptions options = new SerializeOptions(); + options.setAllowDocTypeDeclaration(allowDocTypeDeclaration); + serialize(source, target, options); + } + + private static void serialize(Source source, StreamResult target, SerializeOptions options) { TransformerFactory factory = TransformerFactory.newInstance(); - setFeatureQuietly(factory, "http://apache.org/xml/features/disallow-doctype-decl", !allowDocTypeDeclaration); - setIndent(factory, 2); + setFeatureQuietly(factory, "http://apache.org/xml/features/disallow-doctype-decl", !options.isAllowDocTypeDeclaration()); + setIndent(factory, options.getIndent()); try { Transformer transformer = factory.newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); transformer.setOutputProperty(OutputKeys.MEDIA_TYPE, "text/xml"); + transformer.setOutputProperty(OutputKeys.ENCODING, options.getEncoding()); transformer.transform(source, target); } catch (TransformerException e) { diff --git a/subprojects/groovy-xml/src/spec/doc/xml-userguide.adoc b/subprojects/groovy-xml/src/spec/doc/xml-userguide.adoc index ace9bc78ee..23b596e63a 100644 --- a/subprojects/groovy-xml/src/spec/doc/xml-userguide.adoc +++ b/subprojects/groovy-xml/src/spec/doc/xml-userguide.adoc @@ -641,3 +641,12 @@ methods to serialize the xml fragment from several type of sources include::../test/UserGuideXmlUtilTest.groovy[tags=testGettingANode,indent=0] ---- +Serialization can be customized using `SerializeOptions` to control +encoding, indentation, and DOCTYPE handling: + +[source,groovy] +.Customizing serialization +---- +include::../test/UserGuideXmlUtilTest.groovy[tags=testSerializeOptions,indent=0] +---- + diff --git a/subprojects/groovy-xml/src/spec/test/UserGuideXmlUtilTest.groovy b/subprojects/groovy-xml/src/spec/test/UserGuideXmlUtilTest.groovy index 77aff2d41a..06171eddf2 100644 --- a/subprojects/groovy-xml/src/spec/test/UserGuideXmlUtilTest.groovy +++ b/subprojects/groovy-xml/src/spec/test/UserGuideXmlUtilTest.groovy @@ -51,4 +51,23 @@ class UserGuideXmlUtilTest extends GroovyTestCase { // end::testGettingANode[] } + void testSerializeOptions() { + // tag::testSerializeOptions[] + def response = new XmlParser().parseText(xml) + + // Custom encoding + def latin1 = XmlUtil.serialize(response, new SerializeOptions(encoding: 'ISO-8859-1')) + assert latin1.contains('encoding="ISO-8859-1"') + + // Custom indent (4 spaces instead of default 2) + def wideIndent = XmlUtil.serialize(response, new SerializeOptions(indent: 4)) + assert wideIndent.contains(' <value>') + + // Multiple options + def custom = XmlUtil.serialize(response, new SerializeOptions(encoding: 'ISO-8859-1', indent: 4)) + assert custom.contains('encoding="ISO-8859-1"') + assert custom.contains(' <value>') + // end::testSerializeOptions[] + } + }
