You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2022/03/08 12:03:57 UTC
[groovy] 01/02: GROOVY-10495: Invalid newlines generated by XmlTemplateEngine
This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 785f7274171a2053388eacf182e6131134c0e8b0
Author: Paul King <pa...@asert.com.au>
AuthorDate: Tue Mar 8 12:26:18 2022 +1000
GROOVY-10495: Invalid newlines generated by XmlTemplateEngine
---
.../main/groovy/groovy/text/XmlTemplateEngine.java | 46 +++++++++++++-
.../groovy/text/GroovyXmlTemplateEngineTest.groovy | 74 ++++++++++++++++++++++
.../src/main/java/groovy/xml/XmlNodePrinter.java | 2 +-
3 files changed, 118 insertions(+), 4 deletions(-)
diff --git a/subprojects/groovy-templates/src/main/groovy/groovy/text/XmlTemplateEngine.java b/subprojects/groovy-templates/src/main/groovy/groovy/text/XmlTemplateEngine.java
index 68f413d..0decca7 100644
--- a/subprojects/groovy-templates/src/main/groovy/groovy/text/XmlTemplateEngine.java
+++ b/subprojects/groovy-templates/src/main/groovy/groovy/text/XmlTemplateEngine.java
@@ -19,6 +19,7 @@
package groovy.text;
import groovy.lang.Binding;
+import groovy.lang.Closure;
import groovy.lang.GroovyRuntimeException;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
@@ -108,6 +109,19 @@ public class XmlTemplateEngine extends TemplateEngine {
private static AtomicInteger counter = new AtomicInteger(0);
+ private Closure configurePrinter = null;
+
+ /**
+ * Closure that can be used to configure the printer.
+ * The printer is passed as a parameter to the closure.
+ * <pre>
+ * new XmlTemplateEngine(configurePrinter: { it.preserveWhitespace = true })
+ * </pre>
+ */
+ public void setConfigurePrinter(Closure configurePrinter) {
+ this.configurePrinter = configurePrinter;
+ }
+
private static class GspPrinter extends XmlNodePrinter {
public GspPrinter(PrintWriter out, String indent) {
@@ -137,6 +151,27 @@ public class XmlTemplateEngine extends TemplateEngine {
}
@Override
+ protected void printName(Node node, NamespaceContext ctx, boolean begin, boolean preserve) {
+ if (node == null || node.name() == null) {
+ super.printName(node, ctx, begin, preserve);
+ }
+ printLineBegin();
+ out.print("<");
+ if (!begin) {
+ out.print("/");
+ }
+ out.print(getName(node));
+ if (ctx != null) {
+ printNamespace(node, ctx);
+ }
+ if (begin) {
+ printNameAttributes(node.attributes(), ctx);
+ }
+ out.print(">");
+ printLineEnd();
+ }
+
+ @Override
protected void printSimpleItem(Object value) {
this.printLineBegin();
out.print(escapeSpecialChars(FormatHelper.toString(value)));
@@ -187,12 +222,13 @@ public class XmlTemplateEngine extends TemplateEngine {
@Override
protected void printLineBegin() {
out.print("out.print(\"\"\"");
- out.printIndent();
+ if (!isPreserveWhitespace()) out.printIndent();
}
@Override
protected void printLineEnd(String comment) {
- out.print("\\n\"\"\");");
+ if (!isPreserveWhitespace()) out.print("\\n");
+ out.print("\"\"\");");
if (comment != null) {
out.print(" // ");
out.print(comment);
@@ -316,7 +352,11 @@ public class XmlTemplateEngine extends TemplateEngine {
StringBuilderWriter writer = new StringBuilderWriter(1024);
writer.write("/* Generated by XmlTemplateEngine */\n");
- new GspPrinter(new PrintWriter(writer), indentation).print(root);
+ GspPrinter printer = new GspPrinter(new PrintWriter(writer), indentation);
+ if (configurePrinter != null) {
+ configurePrinter.call(printer);
+ }
+ printer.print(root);
Script script;
try {
diff --git a/subprojects/groovy-templates/src/test/groovy/groovy/text/GroovyXmlTemplateEngineTest.groovy b/subprojects/groovy-templates/src/test/groovy/groovy/text/GroovyXmlTemplateEngineTest.groovy
new file mode 100644
index 0000000..c3c4c27
--- /dev/null
+++ b/subprojects/groovy-templates/src/test/groovy/groovy/text/GroovyXmlTemplateEngineTest.groovy
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.text
+
+import groovy.xml.XmlParser
+import org.junit.Test
+
+class GroovyXmlTemplateEngineTest {
+ @Test
+ void testFormat1() {
+ String xmlScript =
+'''<?xml version="1.0"?>
+<person>
+ <name>Daniel</name>
+</person>
+'''
+ def template = new XmlTemplateEngine(configurePrinter: { it.preserveWhitespace = true }).createTemplate(xmlScript).make().toString()
+ def name1 = new XmlParser().parseText(xmlScript).name.text()
+ def name2 = new XmlParser().parseText(template).name.text()
+
+ assert name1 == name2
+ }
+
+ @Test
+ void testFormat2() {
+ String xmlScript =
+'''<person>
+ <name>
+ <firstName>Daniel</firstName>
+ <lastName>Sun</lastName>
+ </name>
+ <age>37</age>
+</person>
+'''
+
+ def expected =
+'<person><name><firstName>Daniel</firstName><lastName>Sun</lastName></name><age>37</age></person>'
+ assert expected == new XmlTemplateEngine(configurePrinter: { it.preserveWhitespace = true }).createTemplate(xmlScript).make().toString()
+ }
+
+ @Test
+ void testRoundTrip() {
+ String xmlScript =
+'''<person>
+ <name>
+ <firstName>Daniel</firstName>
+ <lastName>Sun</lastName>
+ </name>
+ <age>37</age>
+</person>'''
+
+ def parser = new XmlParser(keepIgnorableWhitespace: true)
+ def shell = new GroovyShell()
+ def engine = new XmlTemplateEngine(parser, shell)
+ engine.configurePrinter = { it.preserveWhitespace = true }
+ assert engine.createTemplate(xmlScript).make().toString() == xmlScript
+ }
+}
diff --git a/subprojects/groovy-xml/src/main/java/groovy/xml/XmlNodePrinter.java b/subprojects/groovy-xml/src/main/java/groovy/xml/XmlNodePrinter.java
index fdd419f..0a4716d 100644
--- a/subprojects/groovy-xml/src/main/java/groovy/xml/XmlNodePrinter.java
+++ b/subprojects/groovy-xml/src/main/java/groovy/xml/XmlNodePrinter.java
@@ -348,7 +348,7 @@ public class XmlNodePrinter {
return node.text().length() == 0;
}
- private String getName(Object object) {
+ protected String getName(Object object) {
if (object instanceof String) {
return (String) object;
} else if (object instanceof QName) {