You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2022/03/07 16:40:33 UTC

[groovy] 01/01: GROOVY-10495: Invalid newlines generated by XmlTemplateEngine

This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY-10495
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit c9916f02d44f5d1996c24f4da9ffdd8b3ffadd3c
Author: Daniel Sun <su...@apache.org>
AuthorDate: Tue Mar 8 00:39:15 2022 +0800

    GROOVY-10495: Invalid newlines generated by XmlTemplateEngine
---
 .../main/groovy/groovy/text/XmlTemplateEngine.java | 45 +++++++++++++++---
 .../src/spec/test/TemplateEnginesTest.groovy       |  4 +-
 .../java/groovy/text/XmlTemplateEngineTest.java    |  9 ++++
 .../src/main/java/groovy/xml/XmlNodePrinter.java   | 54 ++++++++++++++--------
 4 files changed, 83 insertions(+), 29 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..98d1e36 100644
--- a/subprojects/groovy-templates/src/main/groovy/groovy/text/XmlTemplateEngine.java
+++ b/subprojects/groovy-templates/src/main/groovy/groovy/text/XmlTemplateEngine.java
@@ -23,11 +23,12 @@ import groovy.lang.GroovyRuntimeException;
 import groovy.lang.GroovyShell;
 import groovy.lang.Script;
 import groovy.lang.Writable;
+import groovy.namespace.QName;
 import groovy.util.IndentPrinter;
 import groovy.util.Node;
+import groovy.util.NodeList;
 import groovy.xml.XmlNodePrinter;
 import groovy.xml.XmlParser;
-import groovy.namespace.QName;
 import org.apache.groovy.io.StringBuilderWriter;
 import org.codehaus.groovy.control.CompilationFailedException;
 import org.codehaus.groovy.runtime.FormatHelper;
@@ -137,10 +138,10 @@ public class XmlTemplateEngine extends TemplateEngine {
         }
 
         @Override
-        protected void printSimpleItem(Object value) {
-            this.printLineBegin();
+        protected void printSimpleItem(Node node, Object value) {
+            this.printLineBegin(node);
             out.print(escapeSpecialChars(FormatHelper.toString(value)));
-            printLineEnd();
+            printLineEnd(node);
         }
 
         private String escapeSpecialChars(String s) {
@@ -186,13 +187,21 @@ public class XmlTemplateEngine extends TemplateEngine {
 
         @Override
         protected void printLineBegin() {
+            printLineBegin(null);
+        }
+
+        @Override
+        protected void printLineBegin(Node node) {
             out.print("out.print(\"\"\"");
-            out.printIndent();
+            if (needNewlineAndRelatedIndents(node)){
+                out.printIndent();
+            }
         }
 
         @Override
-        protected void printLineEnd(String comment) {
-            out.print("\\n\"\"\");");
+        protected void printLineEnd(Node node, String comment) {
+            out.print((needNewlineAndRelatedIndents(node) ? "\\n" : "") + "\"\"\");");
+
             if (comment != null) {
                 out.print(" // ");
                 out.print(comment);
@@ -200,6 +209,28 @@ public class XmlTemplateEngine extends TemplateEngine {
             out.print("\n");
         }
 
+        private boolean needNewlineAndRelatedIndents(Node node) {
+            return !containsValueOrNone(node);
+        }
+
+        private boolean containsValueOrNone(Node node) {
+            if (null == node) return false;
+
+            final Object value = node.value();
+            if (!(value instanceof NodeList)) {
+                return true;
+            }
+            NodeList nodeList = (NodeList) value;
+            final int size = nodeList.size();
+            if (0 == size) {
+                return true;
+            }
+            if (1 == size && !(nodeList.get(0) instanceof Node)) {
+                return true;
+            }
+            return false;
+        }
+
         @Override
         protected boolean printSpecialNode(Node node) {
             Object name = node.name();
diff --git a/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy b/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy
index 3999d8b..397c279 100644
--- a/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy
+++ b/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy
@@ -188,9 +188,7 @@ The conference committee.'''
         assert template.toString() == '''\
 <document type='letter'>
   Dearest
-  <foo:to xmlns:foo='baz'>
-    Jochen &quot;blackdrag&quot; Theodorou
-  </foo:to>
+  <foo:to xmlns:foo='baz'>Jochen &quot;blackdrag&quot; Theodorou</foo:to>
   How are you today?
 </document>
 '''
diff --git a/subprojects/groovy-templates/src/test/java/groovy/text/XmlTemplateEngineTest.java b/subprojects/groovy-templates/src/test/java/groovy/text/XmlTemplateEngineTest.java
index 39eb607..58dd335 100644
--- a/subprojects/groovy-templates/src/test/java/groovy/text/XmlTemplateEngineTest.java
+++ b/subprojects/groovy-templates/src/test/java/groovy/text/XmlTemplateEngineTest.java
@@ -45,6 +45,15 @@ public class XmlTemplateEngineTest extends TestCase {
         assertEquals(xmlResult, template.make(binding).toString());
     }
 
+    public void testFormat() throws Exception {
+        XmlTemplateEngine xmlTemplateEngine = new XmlTemplateEngine();
+        String xmlScript = "<person>\n"
+                         + "  <name>Daniel</name>\n"
+                         + "</person>";
+        Template template = xmlTemplateEngine.createTemplate(xmlScript);
+        assertTrue(template.make().toString().contains("<name>Daniel</name>")); // no newlines
+    }
+
     public void testQuotes() throws Exception {
         Map binding = new HashMap();
         binding.put("Christian", "Stein");
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 8dcb086..66cbabc 100644
--- a/subprojects/groovy-xml/src/main/java/groovy/xml/XmlNodePrinter.java
+++ b/subprojects/groovy-xml/src/main/java/groovy/xml/XmlNodePrinter.java
@@ -203,7 +203,7 @@ public class XmlNodePrinter {
         Object value = node.value();
         if (value instanceof List) {
             printName(node, ctx, true, isListOfSimple((List) value));
-            printList((List) value, ctx);
+            printList(node, ctx);
             printName(node, ctx, false, isListOfSimple((List) value));
             out.flush();
             return;
@@ -211,7 +211,7 @@ public class XmlNodePrinter {
 
         // treat as simple type - probably a String
         printName(node, ctx, true, preserveWhitespace);
-        printSimpleItemWithIndent(value);
+        printSimpleItemWithIndent(node);
         printName(node, ctx, false, preserveWhitespace);
         out.flush();
     }
@@ -224,14 +224,26 @@ public class XmlNodePrinter {
     }
 
     protected void printLineBegin() {
+        printLineBegin(null);
+    }
+
+    protected void printLineBegin(Node node) {
         out.printIndent();
     }
 
     protected void printLineEnd() {
-        printLineEnd(null);
+        printLineEnd(null, null);
+    }
+
+    protected void printLineEnd(Node node) {
+        printLineEnd(node, null);
     }
 
     protected void printLineEnd(String comment) {
+        printLineEnd(null, comment);
+    }
+
+    protected void printLineEnd(Node node, String comment) {
         if (comment != null) {
             out.print(" <!-- ");
             out.print(comment);
@@ -241,22 +253,26 @@ public class XmlNodePrinter {
         out.flush();
     }
 
-    protected void printList(List list, NamespaceContext ctx) {
-        out.incrementIndent();
-        for (Object value : list) {
-            /*
-             * If the current value is a node, recurse into that node.
-             */
-            if (value instanceof Node) {
-                print((Node) value, new NamespaceContext(ctx));
-                continue;
+    protected void printList(Node node, NamespaceContext ctx) {
+        final Object v = node.value();
+        if (v instanceof List) {
+            List list = (List) v;
+            out.incrementIndent();
+            for (Object value : list) {
+                /*
+                 * If the current value is a node, recurse into that node.
+                 */
+                if (value instanceof Node) {
+                    print((Node) value, new NamespaceContext(ctx));
+                    continue;
+                }
+                printSimpleItem(node, value);
             }
-            printSimpleItem(value);
+            out.decrementIndent();
         }
-        out.decrementIndent();
     }
 
-    protected void printSimpleItem(Object value) {
+    protected void printSimpleItem(Node node, Object value) {
         if (!preserveWhitespace) printLineBegin();
         printEscaped(FormatHelper.toString(value), false);
         if (!preserveWhitespace) printLineEnd();
@@ -270,7 +286,7 @@ public class XmlNodePrinter {
         if (name == null) {
             throw new NullPointerException("Name must not be null.");
         }
-        if (!preserve || begin) printLineBegin();
+        if (!preserve || begin) printLineBegin(begin ? null : node);
         out.print("<");
         if (!begin) {
             out.print("/");
@@ -283,7 +299,7 @@ public class XmlNodePrinter {
             printNameAttributes(node.attributes(), ctx);
         }
         out.print(">");
-        if (!preserve || !begin) printLineEnd();
+        if (!preserve || !begin) printLineEnd(!begin ? null : node);
     }
 
     protected boolean printSpecialNode(Node node) {
@@ -363,9 +379,9 @@ public class XmlNodePrinter {
         return object.toString();
     }
 
-    private void printSimpleItemWithIndent(Object value) {
+    private void printSimpleItemWithIndent(Node node) {
         if (!preserveWhitespace) out.incrementIndent();
-        printSimpleItem(value);
+        printSimpleItem(node, node.value());
         if (!preserveWhitespace) out.decrementIndent();
     }