You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2015/12/28 22:35:59 UTC

incubator-freemarker git commit: Two freemarker.ext.dom xmlns prefix outputting bugs fixed:

Repository: incubator-freemarker
Updated Branches:
  refs/heads/2.3-gae 33ba278fd -> 02459623e


Two freemarker.ext.dom xmlns prefix outputting bugs fixed:

- Bug fixed: The @@qname of elements that belong to the XML namespace declared as the default via <#ftl ns_prefixes={'D':'...', ... }> no longer starts with D:, instead they just start with no name space prefix.
- Bug fixed: In the markup returned by the @@markup key, when there were multiple namespaces for which there was no prefix associated with via <#ftl ns_prefixes=...>, all those namespaces were assigned to the same auto-generated xmlns prefix (usually a). Now they will get a, b, c, etc. prefixes.


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/02459623
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/02459623
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/02459623

Branch: refs/heads/2.3-gae
Commit: 02459623e11efc5ddce66e6a8310c8f628272102
Parents: 33ba278
Author: ddekany <dd...@apache.org>
Authored: Mon Dec 28 22:35:43 2015 +0100
Committer: ddekany <dd...@apache.org>
Committed: Mon Dec 28 22:35:43 2015 +0100

----------------------------------------------------------------------
 .../java/freemarker/ext/dom/ElementModel.java   |   2 +-
 .../java/freemarker/ext/dom/NodeOutputter.java  |  39 +++---
 src/manual/en_US/book.xml                       | 118 ++++++++++++++-----
 src/test/java/freemarker/ext/dom/DOMTest.java   |  31 +++++
 src/test/java/freemarker/test/TemplateTest.java |  21 +++-
 5 files changed, 153 insertions(+), 58 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/02459623/src/main/java/freemarker/ext/dom/ElementModel.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/ext/dom/ElementModel.java b/src/main/java/freemarker/ext/dom/ElementModel.java
index a0f13fa..fb6fccd 100644
--- a/src/main/java/freemarker/ext/dom/ElementModel.java
+++ b/src/main/java/freemarker/ext/dom/ElementModel.java
@@ -145,7 +145,7 @@ class ElementModel extends NodeModel implements TemplateScalarModel {
         String defaultNS = env.getDefaultNS();
         String prefix;
         if (defaultNS != null && defaultNS.equals(nsURI)) {
-            prefix = Template.DEFAULT_NAMESPACE_PREFIX;
+            prefix = "";
         } else {
             prefix = env.getPrefixForNamespace(nsURI);
             

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/02459623/src/main/java/freemarker/ext/dom/NodeOutputter.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/ext/dom/NodeOutputter.java b/src/main/java/freemarker/ext/dom/NodeOutputter.java
index cd59f2b..e4417a2 100644
--- a/src/main/java/freemarker/ext/dom/NodeOutputter.java
+++ b/src/main/java/freemarker/ext/dom/NodeOutputter.java
@@ -19,8 +19,8 @@
  
 package freemarker.ext.dom;
 
-import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
 
 import org.w3c.dom.Attr;
 import org.w3c.dom.Document;
@@ -30,6 +30,7 @@ import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
+import freemarker.core.BugException;
 import freemarker.core.Environment;
 import freemarker.template.Template;
 import freemarker.template.utility.StringUtil;
@@ -41,8 +42,9 @@ class NodeOutputter {
     private String defaultNS;
     private boolean hasDefaultNS;
     private boolean explicitDefaultNSPrefix;
-    private HashMap namespacesToPrefixLookup = new HashMap();
+    private LinkedHashMap<String, String> namespacesToPrefixLookup = new LinkedHashMap<String, String>();
     private String namespaceDecl;
+    int nextGeneratedPrefixNumber = 1;
     
     NodeOutputter(Node node) {
         if (node instanceof Element) {
@@ -72,6 +74,15 @@ class NodeOutputter {
         String nsURI = n.getNamespaceURI();
         if (nsURI != null && nsURI.length() > 0) {
             String prefix = env.getPrefixForNamespace(nsURI);
+            if (prefix == null) {
+                prefix = namespacesToPrefixLookup.get(nsURI);
+                if (prefix == null) {
+                    // Assign a generated prefix:
+                    do {
+                        prefix = StringUtil.toLowerABC(nextGeneratedPrefixNumber++);
+                    } while (env.getNamespaceForPrefix(prefix) != null);
+                }
+            }
             namespacesToPrefixLookup.put(nsURI, prefix);
         } else if (hasDefaultNS && n.getNodeType() == Node.ELEMENT_NODE) {
             namespacesToPrefixLookup.put(defaultNS, Template.DEFAULT_NAMESPACE_PREFIX); 
@@ -93,28 +104,14 @@ class NodeOutputter {
             buf.append(defaultNS);
             buf.append("\"");
         }
-        for (Iterator it = namespacesToPrefixLookup.keySet().iterator(); it.hasNext(); ) {
-            String nsURI = (String) it.next();
+        for (Iterator<String> it = namespacesToPrefixLookup.keySet().iterator(); it.hasNext(); ) {
+            String nsURI = it.next();
             if (nsURI == null || nsURI.length() == 0) {
                 continue;
             }
-            String prefix = (String) namespacesToPrefixLookup.get(nsURI);
+            String prefix = namespacesToPrefixLookup.get(nsURI);
             if (prefix == null) {
-                // Okay, let's auto-assign a prefix.
-                // Should we do this??? (REVISIT)
-                for (int i = 0; i < 26; i++) {
-                    char[] cc = new char[1];
-                    cc[0] = (char) ('a' + i);
-                    prefix = new String(cc);
-                    if (env.getNamespaceForPrefix(prefix) == null) {
-                        break;
-                    }
-                    prefix = null;
-                }
-                if (prefix == null) {
-                    throw new RuntimeException("This will almost never happen!");
-                }
-                namespacesToPrefixLookup.put(nsURI, prefix);
+                throw new BugException("No xmlns prefix was associated to URI: " + nsURI);
             }
             buf.append(" xmlns");
             if (prefix.length() > 0) {
@@ -133,7 +130,7 @@ class NodeOutputter {
         if (nsURI == null || nsURI.length() == 0) {
             buf.append(n.getNodeName());
         } else {
-            String prefix = (String) namespacesToPrefixLookup.get(nsURI);
+            String prefix = namespacesToPrefixLookup.get(nsURI);
             if (prefix == null) {
                 //REVISIT!
                 buf.append(n.getNodeName());

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/02459623/src/manual/en_US/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index ba8c1b1..6318f75 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -26928,22 +26928,49 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
             </listitem>
 
             <listitem>
-              <para>Bug fixed: XPath queries that has only contained
-              characters that are valid in XML element names and has also
-              contained <literal>::</literal> (which is valid in names in
-              namespace-unware documents), like
-              <literal>e['following-sibling::foo']</literal>, were interpreted
-              as literal element names (giving 0 hits) rather than as XPath
-              expressions. Note that there were no such problem with
-              <literal>e['following-sibling::*']</literal> for example, as
-              it's not a valid XML element name according the XML
-              specification. This fix can actually break applications that has
-              processed namespace unaware XML that use <literal>::</literal>
-              as part of element or attribute names, but such an application
-              is highly unlikely, unlike running into the fixed problem.
-              (Unfortunately, using
-              <literal>incompatible_improvements</literal> wasn't technically
-              possible here.)</para>
+              <para>Fixes in the XML processing feature
+              (<literal>freemarker.ext.dom</literal>):</para>
+
+              <itemizedlist>
+                <listitem>
+                  <para>Bug fixed: XPath queries that has only contained
+                  characters that are valid in XML element names and has also
+                  contained <literal>::</literal> (which is valid in names in
+                  namespace-unware documents), like
+                  <literal>e['following-sibling::foo']</literal>, were
+                  interpreted as literal element names (giving 0 hits) rather
+                  than as XPath expressions. Note that there were no such
+                  problem with <literal>e['following-sibling::*']</literal>
+                  for example, as it's not a valid XML element name according
+                  the XML specification. This fix can actually break
+                  applications that has processed namespace unaware XML that
+                  use <literal>::</literal> as part of element or attribute
+                  names, but such an application is highly unlikely, unlike
+                  running into the fixed problem. (Unfortunately, using
+                  <literal>incompatible_improvements</literal> wasn't
+                  technically possible here.)</para>
+                </listitem>
+
+                <listitem>
+                  <para>Bug fixed: The <literal>@@qname</literal> of elements
+                  that belong to the XML namespace declared as the default via
+                  <literal>&lt;#ftl ns_prefixes={'D':'...', ...
+                  }&gt;</literal> no longer starts with <literal>D:</literal>,
+                  instead they just start with no name space prefix.</para>
+                </listitem>
+
+                <listitem>
+                  <para>Bug fixed: In the markup returned by the
+                  <literal>@@markup</literal> key, when there were multiple
+                  namespaces for which there was no prefix associated with via
+                  <literal>&lt;#ftl
+                  ns_prefixes=<replaceable>...</replaceable>&gt;</literal>,
+                  all those namespaces were assigned to the same
+                  auto-generated <literal>xmlns</literal> prefix (usually
+                  <quote>a</quote>). Now they will get <quote>a</quote>,
+                  <quote>b</quote>, <quote>c</quote>, etc. prefixes.</para>
+                </listitem>
+              </itemizedlist>
             </listitem>
 
             <listitem>
@@ -27285,22 +27312,49 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
             </listitem>
 
             <listitem>
-              <para>Bug fixed: XPath queries that has only contained
-              characters that are valid in XML element names and has also
-              contained <literal>::</literal> (which is valid in names in
-              namespace-unware documents), like
-              <literal>e['following-sibling::foo']</literal>, were interpreted
-              as literal element names (giving 0 hits) rather than as XPath
-              expressions. Note that there were no such problem with
-              <literal>e['following-sibling::*']</literal> for example, as
-              it's not a valid XML element name according the XML
-              specification. This fix can actually break applications that has
-              processed namespace unaware XML that use <literal>::</literal>
-              as part of element or attribute names, but such an application
-              is highly unlikely, unlike running into the fixed problem.
-              (Unfortunately, using
-              <literal>incompatible_improvements</literal> wasn't technically
-              possible here.)</para>
+              <para>Fixes in the XML processing feature
+              (<literal>freemarker.ext.dom</literal>):</para>
+
+              <itemizedlist>
+                <listitem>
+                  <para>Bug fixed: XPath queries that has only contained
+                  characters that are valid in XML element names and has also
+                  contained <literal>::</literal> (which is valid in names in
+                  namespace-unware documents), like
+                  <literal>e['following-sibling::foo']</literal>, were
+                  interpreted as literal element names (giving 0 hits) rather
+                  than as XPath expressions. Note that there were no such
+                  problem with <literal>e['following-sibling::*']</literal>
+                  for example, as it's not a valid XML element name according
+                  the XML specification. This fix can actually break
+                  applications that has processed namespace unaware XML that
+                  use <literal>::</literal> as part of element or attribute
+                  names, but such an application is highly unlikely, unlike
+                  running into the fixed problem. (Unfortunately, using
+                  <literal>incompatible_improvements</literal> wasn't
+                  technically possible here.)</para>
+                </listitem>
+
+                <listitem>
+                  <para>Bug fixed: The <literal>@@qname</literal> of elements
+                  that belong to the XML namespace declared as the default via
+                  <literal>&lt;#ftl ns_prefixes={'D':'...', ...
+                  }&gt;</literal> no longer starts with <literal>D:</literal>,
+                  instead they just start with no name space prefix.</para>
+                </listitem>
+
+                <listitem>
+                  <para>Bug fixed: In the markup returned by the
+                  <literal>@@markup</literal> key, when there were multiple
+                  namespaces for which there was no prefix associated with via
+                  <literal>&lt;#ftl
+                  ns_prefixes=<replaceable>...</replaceable>&gt;</literal>,
+                  all those namespaces were assigned to the same
+                  auto-generated <literal>xmlns</literal> prefix (usually
+                  <quote>a</quote>). Now they will get <quote>a</quote>,
+                  <quote>b</quote>, <quote>c</quote>, etc. prefixes.</para>
+                </listitem>
+              </itemizedlist>
             </listitem>
           </itemizedlist>
         </section>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/02459623/src/test/java/freemarker/ext/dom/DOMTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/dom/DOMTest.java b/src/test/java/freemarker/ext/dom/DOMTest.java
index 182ac31..59f1392 100644
--- a/src/test/java/freemarker/ext/dom/DOMTest.java
+++ b/src/test/java/freemarker/ext/dom/DOMTest.java
@@ -28,6 +28,37 @@ public class DOMTest extends TemplateTest {
     }
 
     @Test
+    public void xmlnsPrefixes() throws Exception {
+        addDocToDataModel("<root xmlns='http://example.com/ns1' xmlns:ns2='http://example.com/ns2'>"
+                + "<a>A</a><ns2:b>B</ns2:b><c a1='1' ns2:a2='2'/></root>");
+
+        String ftlHeader = "<#ftl ns_prefixes={'D':'http://example.com/ns1', 'n2':'http://example.com/ns2'}>";
+        
+        // @@markup:
+        assertOutput("${doc.@@markup}",
+                "<a:root xmlns:a=\"http://example.com/ns1\" xmlns:b=\"http://example.com/ns2\">"
+                + "<a:a>A</a:a><b:b>B</b:b><a:c a1=\"1\" b:a2=\"2\" />"
+                + "</a:root>");
+        assertOutput(ftlHeader
+                + "${doc.@@markup}",
+                "<root xmlns=\"http://example.com/ns1\" xmlns:n2=\"http://example.com/ns2\">"
+                + "<a>A</a><n2:b>B</n2:b><c a1=\"1\" n2:a2=\"2\" /></root>");
+        assertOutput("<#ftl ns_prefixes={'D':'http://example.com/ns1'}>"
+                + "${doc.@@markup}",
+                "<root xmlns=\"http://example.com/ns1\" xmlns:a=\"http://example.com/ns2\">"
+                + "<a>A</a><a:b>B</a:b><c a1=\"1\" a:a2=\"2\" /></root>");
+        
+        // 
+        assertOutput("${doc?children[0].@@qname!'null'}", "null");
+        assertOutput("${doc?children[0]?children[1].@@qname!'null'}", "null");
+        assertOutput(ftlHeader + "${doc?children[0].@@qname}", "root");
+        assertOutput(ftlHeader + "${doc?children[0]?children[1].@@qname}", "n2:b");
+        // Unfortunately these include the xmlns attributes, but that would be non-BC to fix now:
+        assertThat(getOutput(ftlHeader + "${doc?children[0].@@start_tag}"), startsWith("<root"));
+        assertThat(getOutput(ftlHeader + "${doc?children[0]?children[1].@@start_tag}"), startsWith("<n2:b"));
+    }
+    
+    @Test
     public void namespaceUnaware() throws Exception {
         addNSUnawareDocToDataModel("<root><x:a>A</x:a><:>B</:><xyz::c>C</xyz::c></root>");
         assertOutput("${doc.root['x:a']}", "A");

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/02459623/src/test/java/freemarker/test/TemplateTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/test/TemplateTest.java b/src/test/java/freemarker/test/TemplateTest.java
index 6047e2e..719ca7c 100644
--- a/src/test/java/freemarker/test/TemplateTest.java
+++ b/src/test/java/freemarker/test/TemplateTest.java
@@ -69,8 +69,12 @@ public abstract class TemplateTest {
     }
 
     protected void assertOutput(String ftl, String expectedOut) throws IOException, TemplateException {
+        assertOutput(createTemplate(ftl), expectedOut, false);
+    }
+
+    private Template createTemplate(String ftl) throws IOException {
         Template t = new Template(null, ftl, getConfiguration());
-        assertOutput(t, expectedOut, false);
+        return t;
     }
 
     protected void assertOutputForNamed(String name, String expectedOut) throws IOException, TemplateException {
@@ -101,9 +105,7 @@ public abstract class TemplateTest {
     
     protected void assertOutput(Template t, String expectedOut, boolean normalizeNewlines)
             throws TemplateException, IOException {
-        StringWriter out = new StringWriter();
-        t.process(getDataModel(), out);
-        String actualOut = out.toString();
+        String actualOut = getOutput(t);
         
         if (normalizeNewlines) {
             expectedOut = normalizeNewLines(expectedOut);
@@ -111,6 +113,17 @@ public abstract class TemplateTest {
         }
         assertEquals(expectedOut, actualOut);
     }
+
+    protected String getOutput(String ftl) throws IOException, TemplateException {
+        return getOutput(createTemplate(ftl));
+    }
+    
+    protected String getOutput(Template t) throws TemplateException, IOException {
+        StringWriter out = new StringWriter();
+        t.process(getDataModel(), out);
+        String actualOut = out.toString();
+        return actualOut;
+    }
     
     protected Configuration createConfiguration() throws Exception {
         return new Configuration(Configuration.VERSION_2_3_0);