Rewrite XML serialization avoiding string concats
authorJakub Skoczen <jakub@indexdata.dk>
Fri, 22 Jul 2011 14:51:07 +0000 (16:51 +0200)
committerJakub Skoczen <jakub@indexdata.dk>
Fri, 22 Jul 2011 14:51:07 +0000 (16:51 +0200)
src/main/java/org/z3950/zing/cql/CQLBooleanNode.java
src/main/java/org/z3950/zing/cql/CQLNode.java
src/main/java/org/z3950/zing/cql/CQLParser.java
src/main/java/org/z3950/zing/cql/CQLPrefixNode.java
src/main/java/org/z3950/zing/cql/CQLRelation.java
src/main/java/org/z3950/zing/cql/CQLSortNode.java
src/main/java/org/z3950/zing/cql/CQLTermNode.java
src/main/java/org/z3950/zing/cql/Modifier.java
src/main/java/org/z3950/zing/cql/ModifierSet.java
src/main/java/org/z3950/zing/cql/Utils.java [deleted file]
src/main/java/org/z3950/zing/cql/XCQLBuilder.java [new file with mode: 0644]

index 19f96c7..d5a81e8 100644 (file)
@@ -4,9 +4,6 @@ package org.z3950.zing.cql;
 import java.util.List;
 import java.util.Properties;
 
-import static org.z3950.zing.cql.Utils.*;
-
-
 /**
  * Represents a boolean node in a CQL parse-tree.
  *
@@ -47,19 +44,19 @@ public abstract class CQLBooleanNode extends CQLNode {
     }
 
     @Override
-    public String toXCQL(int level, List<CQLPrefix> prefixes,
-                        List<ModifierSet> sortkeys) {
-       return (indent(level) + "<triple>\n" +
-               renderPrefixes(level+1, prefixes) +
-               ms.toXCQL(level+1, "boolean") +
-               indent(level+1) + "<leftOperand>\n" +
-               left.toXCQL(level+2) +
-               indent(level+1) + "</leftOperand>\n" +
-               indent(level+1) + "<rightOperand>\n" +
-               right.toXCQL(level+2) +
-               indent(level+1) + "</rightOperand>\n" +
-               renderSortKeys(level+1, sortkeys) +
-               indent(level) + "</triple>\n");
+    void toXCQLInternal(XCQLBuilder b, int level,
+        List<CQLPrefix> prefixes, List<ModifierSet> sortkeys) {
+       b.indent(level).append("<triple>\n");
+        renderPrefixes(b, level + 1, prefixes);
+        ms.toXCQLInternal(b, level + 1, "boolean");
+        b.indent(level + 1).append("<leftOperand>\n");
+        left.toXCQLInternal(b, level + 2);
+        b.indent(level + 1).append("</leftOperand>\n");
+        b.indent(level + 1).append("<rightOperand>\n");
+        right.toXCQLInternal(b, level + 2);
+        b.indent(level + 1).append("</rightOperand>\n");
+        renderSortKeys(b, level + 1, sortkeys);
+        b.indent(level).append("</triple>\n");
     }
 
     @Override
index 88b50ca..afaa892 100644 (file)
@@ -6,7 +6,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
-import static org.z3950.zing.cql.Utils.*;
 
 
 /**
@@ -41,43 +40,47 @@ public abstract class CQLNode {
      * A String containing an XCQL document equivalent to the
      * parse-tree whose root is this node.
      */
-    public String toXCQL(int level) {
-       return toXCQL(level, null);
+    public String toXCQL() {
+        StringBuilder sb = new StringBuilder();
+       toXCQLInternal(new XCQLBuilder(sb), 0);
+        return sb.toString();
     }
 
-    public String toXCQL(int level, List<CQLPrefix> prefixes) {
-       return toXCQL(level, prefixes, null);
+    void toXCQLInternal(XCQLBuilder b, int level) {
+        toXCQLInternal(b, level, null, null);
     }
 
-    abstract public String toXCQL(int level, List<CQLPrefix> prefixes,
-                                 List<ModifierSet> sortkeys);
+    abstract void toXCQLInternal(XCQLBuilder b, int level,
+      List<CQLPrefix> prefixes, List<ModifierSet> sortkeys);
 
-    protected static String renderPrefixes(int level, List<CQLPrefix> prefixes) {
+    static void renderPrefixes(XCQLBuilder b,
+        int level, List<CQLPrefix> prefixes) {
        if (prefixes == null || prefixes.size() == 0)
-           return "";
-       String res = indent(level) + "<prefixes>\n";
+           return;
+       b.indent(level).append("<prefixes>\n");
        for (int i = 0; i < prefixes.size(); i++) {
            CQLPrefix p = prefixes.get(i);
-           res += indent(level+1) + "<prefix>\n";
+           b.indent(level+1).append("<prefix>\n");
            if (p.name != null)
-               res += indent(level+2) + "<name>" + p.name + "</name>\n";
-           res += indent(level+2) +
-               "<identifier>" + p.identifier + "</identifier>\n";
-           res += indent(level+1) + "</prefix>\n";
+               b.indent(level + 2).append("<name>").
+                    append(p.name).append("</name>\n");
+           b.indent(level + 2).append("<identifier>").append(p.identifier).
+              append("</identifier>\n");
+           b.indent(level+1).append("</prefix>\n");
        }
-       return res + indent(level) + "</prefixes>\n";
+       b.indent(level).append("</prefixes>\n");
     }
 
-    protected static String renderSortKeys(int level,
+    static void renderSortKeys(XCQLBuilder b, int level,
                                           List<ModifierSet> sortkeys) {
        if (sortkeys == null || sortkeys.size() == 0)
-           return "";
-       String res = indent(level) + "<sortKeys>\n";
+           return;
+       b.indent(level).append("<sortKeys>\n");
        for (int i = 0; i < sortkeys.size(); i++) {
            ModifierSet key = sortkeys.get(i);
-           res += key.sortKeyToXCQL(level+1);
+           b.append(key.sortKeyToXCQL(level+1));
        }
-       return res + indent(level) + "</sortKeys>\n";
+       b.indent(level).append("</sortKeys>\n");
     }
 
     /**
index 7ed9f59..be365de 100644 (file)
@@ -443,7 +443,7 @@ public class CQLParser {
                f.close();
                System.out.println(root.toPQF(config));
            } else {
-               System.out.print(root.toXCQL(0));
+               System.out.print(root.toXCQL());
            }
        } catch (IOException ex) {
            System.err.println("Can't render query: " + ex.getMessage());
index c793d2f..eed3d34 100644 (file)
@@ -42,13 +42,13 @@ public class CQLPrefixNode extends CQLNode {
     }
 
     @Override
-    public String toXCQL(int level, List<CQLPrefix> prefixes,
+    void toXCQLInternal(XCQLBuilder b, int level, List<CQLPrefix> prefixes,
                         List<ModifierSet> sortkeys) {
        List<CQLPrefix> tmp = (prefixes == null ?
                                 new ArrayList<CQLPrefix>() :
                                 new ArrayList<CQLPrefix>(prefixes));
        tmp.add(prefix);
-       return subtree.toXCQL(level, tmp, sortkeys);
+       subtree.toXCQLInternal(b, level, tmp, sortkeys);
     }
 
     @Override
index 44a55e6..351d8d4 100644 (file)
@@ -44,12 +44,11 @@ public class CQLRelation extends CQLNode {
     }
 
     @Override
-    public String toXCQL(int level, List<CQLPrefix> prefixes,
+    void toXCQLInternal(XCQLBuilder b, int level, List<CQLPrefix> prefixes,
       List<ModifierSet> sortkeys) {
        if (sortkeys != null)
            throw new Error("CQLRelation.toXCQL() called with sortkeys");
-
-       return ms.toXCQL(level, "relation");
+       ms.toXCQLInternal(b, level, "relation");
     }
 
     @Override
index 55e69d5..68a4ea9 100644 (file)
@@ -43,11 +43,11 @@ public class CQLSortNode extends CQLNode {
     }
 
     @Override
-    public String toXCQL(int level, List<CQLPrefix> prefixes,
+    void toXCQLInternal(XCQLBuilder b, int level, List<CQLPrefix> prefixes,
                         List<ModifierSet> sortkeys) {
        if (sortkeys != null)
            throw new Error("CQLSortNode.toXCQL() called with sortkeys");
-       return subtree.toXCQL(level, prefixes, keys);
+       subtree.toXCQLInternal(b, level, prefixes, keys);
     }
 
     @Override
index cdb62f7..dfd0e63 100644 (file)
@@ -5,9 +5,6 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Properties;
 
-import static org.z3950.zing.cql.Utils.*;
-
-
 /**
  * Represents a terminal node in a CQL parse-tree.
  * A term node consists of the term String itself, together with,
@@ -55,15 +52,15 @@ public class CQLTermNode extends CQLNode {
     }
 
     @Override
-    public String toXCQL(int level, List<CQLPrefix> prefixes,
+    void toXCQLInternal(XCQLBuilder b, int level, List<CQLPrefix> prefixes,
                         List<ModifierSet> sortkeys) {
-       return (indent(level) + "<searchClause>\n" +
-               renderPrefixes(level+1, prefixes) +
-               indent(level+1) + "<index>" + xq(index) + "</index>\n" +
-               relation.toXCQL(level+1) +
-               indent(level+1) + "<term>" + xq(term) + "</term>\n" +
-               renderSortKeys(level+1, sortkeys) +
-               indent(level) + "</searchClause>\n");
+      b.indent(level).append("<searchClause>\n");
+      renderPrefixes(b, level + 1, prefixes);
+      b.indent(level + 1).append("<index>").xq(index).append("</index>\n");
+      relation.toXCQLInternal(b, level + 1);
+      b.indent(level + 1).append("<term>").xq(term).append("</term>\n");
+      renderSortKeys(b, level + 1, sortkeys);
+      b.indent(level).append("</searchClause>\n");
     }
 
     @Override
index d85c8a1..8c5cef7 100644 (file)
@@ -2,8 +2,6 @@
 
 package org.z3950.zing.cql;
 
-import static org.z3950.zing.cql.Utils.*;
-
 /**
  * Represents a single modifier, consisting of three elements: a type,
  * a comparision and a value.  For example, "distance", "<", "3".  The
@@ -60,22 +58,17 @@ public class Modifier {
        return value;
     }
 
-    public String toXCQL(int level, String relationElement) {
-       StringBuilder buf = new StringBuilder();
-
-       buf.append(indent(level)).append("<modifier>\n").
-            append(indent(level + 1)).append("<type>").
-            append(xq(type)).append("</type>\n");
+    protected XCQLBuilder toXCQLInternal(XCQLBuilder b, int level, String relationElement) {
+       b.indent(level).append("<modifier>\n");
+        b.indent(level + 1).append("<type>");
+        b.xq(type).append("</type>\n");
        if (value != null) {
-           buf.append(indent(level + 1)).append("<").
-              append(relationElement).append(">").
-              append(xq(comparison)).append("</").
-              append(relationElement).append(">\n").
-              append(indent(level + 1)).append("<value>").
-              append(xq(value)).append("</value>\n");
+            b.indent(level + 1).append("<").append(relationElement).append(">");
+            b.xq(comparison).append("</").append(relationElement).append(">\n");
+            b.indent(level + 1).append("<value>");
+            b.xq(value).append("</value>\n");
        }
-       buf.append(indent(level)).append("</modifier>\n");
-       return buf.toString();
+       return b.indent(level).append("</modifier>\n");
     }
 
     public String toCQL() {
index 213f199..c04bb88 100644 (file)
@@ -4,8 +4,6 @@ package org.z3950.zing.cql;
 import java.util.ArrayList;
 import java.util.List;
 
-import static org.z3950.zing.cql.Utils.*;
-
 /**
  * Represents a base String and a set of Modifiers.
  * <P>
@@ -80,30 +78,33 @@ public class ModifierSet {
     }
 
     public String toXCQL(int level, String topLevelElement) {
-       return underlyingToXCQL(level, topLevelElement, "value");
+       return "";//underlyingToXCQL(level, topLevelElement, "value");
     }
 
     public String sortKeyToXCQL(int level) {
-       return underlyingToXCQL(level, "key", "index");
+       return "";//underlyingToXCQL(level, "key", "index");
+    }
+
+    protected XCQLBuilder toXCQLInternal(XCQLBuilder b, int level,
+        String topLevelElement) {
+        return toXCQLInternal(b, level, topLevelElement, "value");
     }
 
-    private String underlyingToXCQL(int level, String topLevelElement,
-                                   String valueElement) {
-       StringBuilder buf = new StringBuilder();
-       buf.append(indent(level)).append("<").append(topLevelElement).
-            append(">\n").append(indent(level + 1)).append("<").
-            append(valueElement).append(">").append(xq(base)).append("</").
+    private XCQLBuilder toXCQLInternal(XCQLBuilder b, int level, 
+        String topLevelElement, String valueElement) {
+       b.indent(level).append("<").append(topLevelElement).
+            append(">\n").indent(level + 1).append("<").
+            append(valueElement).append(">").xq(base).append("</").
             append(valueElement).append(">\n");
        if (modifiers.size() > 0) {
-           buf.append(indent(level + 1)).append("<modifiers>\n");
+           b.indent(level + 1).append("<modifiers>\n");
            for (int i = 0; i < modifiers.size(); i++) {
-               buf.append(modifiers.get(i).toXCQL(level+2, "comparison"));
+              modifiers.get(i).toXCQLInternal(b, level+2, "comparison");
            }
-           buf.append(indent(level + 1)).append("</modifiers>\n");
+           b.indent(level + 1).append("</modifiers>\n");
        }
-       buf.append(indent(level)).append("</").append(topLevelElement).
-            append(">\n");
-       return buf.toString();
+       b.indent(level).append("</").append(topLevelElement).append(">\n");
+        return b;
     }
 
     public String toCQL() {
diff --git a/src/main/java/org/z3950/zing/cql/Utils.java b/src/main/java/org/z3950/zing/cql/Utils.java
deleted file mode 100644 (file)
index 9224d36..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-// $Id: Utils.java,v 1.2 2002-11-06 00:05:58 mike Exp $
-
-package org.z3950.zing.cql;
-
-
-/**
- * Utility functions for the org.z3950.zing.cql package.
- * Not intended for use outside this package.
- *
- * @version    $Id: Utils.java,v 1.2 2002-11-06 00:05:58 mike Exp $
- */
-class Utils {
-    static String indent(int level) {
-       String x = "";
-       while (level-- > 0) {
-           x += "  ";
-       }
-       return x;
-    }
-
-    // XML Quote --
-    // s/&/&amp;/g;
-    // s/</&lt;/g;
-    // s/>/&gt;/g;
-    static String xq(String str) {
-        StringBuilder sb = new StringBuilder();
-        for(int i = 0; i<str.length(); i++) {
-            char c = str.charAt(i);
-            switch (c) {
-                case '<':
-                    sb.append("&lt;");
-                    break;
-                case '>':
-                    sb.append("&gt;");
-                    break;
-                case '&':
-                    sb.append("&amp;");
-                    break;
-                default:
-                    sb.append(c);
-            }
-        }
-       return sb.toString();
-    }
-
-}
diff --git a/src/main/java/org/z3950/zing/cql/XCQLBuilder.java b/src/main/java/org/z3950/zing/cql/XCQLBuilder.java
new file mode 100644 (file)
index 0000000..d59ce89
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995-2011, Index Data
+ * All rights reserved.
+ * See the file LICENSE for details.
+ */
+package org.z3950.zing.cql;
+
+/**
+ *
+ * @author jakub
+ */
+class XCQLBuilder {
+  private StringBuilder sb;
+
+  XCQLBuilder(StringBuilder sb) {
+    this.sb = sb;
+  }
+
+  XCQLBuilder indent(int level) {
+    while (level-- > 0) {
+      sb.append("  ");
+    }
+    return this;
+  }
+
+  XCQLBuilder xq(String str) {
+    for (int i = 0; i < str.length(); i++) {
+      char c = str.charAt(i);
+      switch (c) {
+        case '<':
+          sb.append("&lt;");
+          break;
+        case '>':
+          sb.append("&gt;");
+          break;
+        case '&':
+          sb.append("&amp;");
+          break;
+        default:
+          sb.append(c);
+      }
+    }
+    return this;
+  }
+  
+  XCQLBuilder append(String str) {
+    sb.append(str);
+    return this;
+  }
+
+  public String toString() {
+    return sb.toString();
+  }
+}
\ No newline at end of file