Finish (more or less) to CQL-to-PQF translator.
authormike <mike>
Wed, 6 Nov 2002 20:13:45 +0000 (20:13 +0000)
committermike <mike>
Wed, 6 Nov 2002 20:13:45 +0000 (20:13 +0000)
Add new exceptions arising from PQF translation.
Substantially rework the PQF-translation configuration properties.
Add new javadoc comments for various classes.
Fix visibility of some methods.

18 files changed:
Changes
README
etc/pqf.properties
src/org/z3950/zing/cql/CQLBooleanNode.java
src/org/z3950/zing/cql/CQLNode.java
src/org/z3950/zing/cql/CQLParseException.java
src/org/z3950/zing/cql/CQLParser.java
src/org/z3950/zing/cql/CQLProxNode.java
src/org/z3950/zing/cql/CQLRelation.java
src/org/z3950/zing/cql/CQLTermNode.java
src/org/z3950/zing/cql/Makefile
src/org/z3950/zing/cql/MissingParameterException.java
src/org/z3950/zing/cql/ModifierSet.java
src/org/z3950/zing/cql/PQFTranslationException.java [new file with mode: 0644]
src/org/z3950/zing/cql/UnknownPositionException.java [new file with mode: 0644]
src/org/z3950/zing/cql/UnknownQualifierException.java
src/org/z3950/zing/cql/UnknownRelationException.java
src/org/z3950/zing/cql/UnknownRelationModifierException.java [new file with mode: 0644]

diff --git a/Changes b/Changes
index cc072fe..884403f 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,4 +1,4 @@
-$Id: Changes,v 1.1 2002-11-06 00:05:57 mike Exp $
+$Id: Changes,v 1.2 2002-11-06 20:13:45 mike Exp $
 
 Revision history for "cql-java"
 
@@ -13,14 +13,19 @@ Revision history for "cql-java"
          through parse-trees and so implement its own back-end
          (e.g. to build BER-friendly data structures using whatever
          Z39.50 toolkit is preferred.)
-       - Add javadoc comments for CQLNode and subclasses.
-       - Add the toPQF(Properties p) method to CQLNode and subclasses.
-               (### NOT YET FINISHED)
-       - Add UnknownQualifierException and UnknownRelationException.
+       - Add the toPQF(Properties p) method to CQLNode and
+         subclasses.  This produces a query in YAZ-style Prefix Query
+         Format, which can be trivially translated into a Z39.50
+         Type-1 query (see, for example, JZKit's code to do so).
+       - Add etc/pqf.properties to configure to toPQF() method.
        - Add "-p <props-file>" option to the CQLParser test-harness,
          indicating that the parsed tree is to be rendered to PQF.
-       - Add etc/pqf.properties to configure to toPQF() method.
+       - Add PQFTranslationException and its subclasses
+         UnknownQualifierException, UnknownRelationException,
+         UnknownRelationModifierException and
+         UnknownPositionException.
        - Rename ParameterMissingException to MissingParameterException.
+       - Add javadoc comments for CQLNode and its subclasses.
 
 0.1  Sun Nov  3 20:58:27 2002
        - First public release.
diff --git a/README b/README
index ee96d8a..a508b3d 100644 (file)
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-$Id: README,v 1.14 2002-11-06 00:05:58 mike Exp $
+$Id: README,v 1.15 2002-11-06 20:13:45 mike Exp $
 
 cql-java - a free CQL compiler, and other CQL tools, for Java
 
@@ -15,7 +15,7 @@ cql-java is a Free Software project that provides:
 * A selection of compiler back-ends to render out the parse tree as:
        * XCQL (the standard XML representation)
        * CQL (i.e. decompiling the parse-tree)
-       * PQF (Yaz-style Prefix Query Format) [### NOT YET]
+       * PQF (Yaz-style Prefix Query Format)
 * A random query generator, useful for testing.
 
 CQL is "Common Query Language", a new query language designed under
@@ -73,15 +73,15 @@ Using the library in your own applications:
        CQLNode root = parser.parse("title=dinosaur");
        System.out.print(root.toXCQL(0));
        System.out.println(root.toCQL());
-       System.out.println(root.toPQF(qualSet));
-       // ... where `qualSet' specifies CQL-qualfier => Z-attr mapping
+       System.out.println(root.toPQF(config));
+       // ... where `config' specifies CQL-qualfier => Z-attr mapping
 
 
 DESCRIPTION
 -----------
 
 See the automatically generated class documentation in the "doc"
-subdirectory.  (It's not all there yet, but it's coming.)
+subdirectory.
 
 
 AUTHOR
@@ -119,8 +119,9 @@ THINGS TO DO
   possible to fix this without throwing out StreakTokenizer and
   rolling our own, which we absolutely _don't_ want to do.
 
-* Write javadoc comments for CQLRelation, ModifierSet and the
-  Exception classes.
+* Write javadoc comments for CQLRelation and ModifierSet.
+
+* Write "overview" file for the javadoc documentation.
 
 * Allow keywords to be used unquoted as search terms.
 
@@ -128,12 +129,6 @@ THINGS TO DO
        * don't emit redundant parentheses.
        * don't put spaces around relations that don't need them.
 
-* Write the PQN-generating back-end.  This will need to be driven from
-  a configuation file specifying how to represent the qualifiers,
-  relations, relation modifiers and wildcard characters as z39.50
-  attributes.  I think Ray has such a thing, though perhaps not yet in
-  a form sufficiently rigorous to be computer-readable.
-
 * Consider the utility of yet another back-end that translates a
   CQLNode tree into a Type-1 query tree using the JZKit data
   structures.  That would be nice so that CQL could become a JZKit
@@ -149,4 +144,3 @@ THINGS TO DO
        * Introduce wildcard characters into generated terms
        * Generate multi-word terms
 
-* Write fuller "javadoc" comments.
index 4508572..875d871 100644 (file)
@@ -1,67 +1,95 @@
-# $Id: pqf.properties,v 1.2 2002-11-06 10:37:06 mike Exp $
+# $Id: pqf.properties,v 1.3 2002-11-06 20:13:45 mike Exp $
 #
 # Propeties file to drive org.z3950.zing.cql.CQLNode's toPQF()
 # back-end.  This specifies the interpretation of various CQL
-# qualifiers in terms of Type-1 query attributes.
+# qualifiers, relations, etc. in terms of Type-1 query attributes.
 #
 # See http://www.loc.gov/z3950/agency/zing/srwu/dc-indexes.html
 # for the Maintenance Agency's work-in-progress mapping of Dublic Core
 # qualifiers to Attribute Architecture (util, XD and BIB-2)
 # attributes.
+
+# The default access point:
 #
-dc.title                       = 1=4
-dc.subject                     = 1=21
-dc.creator                     = 1=1003
-dc.editor                      = 1=1020
-dc.publisher                   = 1=1018
-dc.description                 = 1=62  # "abstract"
-dc.date                                = 1=30
-dc.resourceType                        = 1=1031        # guesswork: "Material-type"
-dc.format                      = 1=1034        # guesswork: "Content-type"
-dc.resourceIdentifier          = 1=12  # "Local number"
-dc.source                      = 1=1019        # "Record-source"
-dc.language                    = 1=54  # "Code--language"
-dc.relation                    = 1=?   ###
-dc.coverage                    = 1=?   ###
-dc.rights                      = 1=?   ###
-#
-# Aside from the mainstream qualifiers -- the Dublin Core stuff, Bath
-# Profile stuff and suchlike -- this file may also specific a few
-# special qualifiers in the "cql-java" pseudo-qualifier-set, and these
-# affect the translation of qualifiers into Type-1 attributes as
-# follows:
-#
+qualifier.srw.serverChoice             = 1=1016
+       # "any"
+
+qualifier.dc.title                     = 1=4
+qualifier.dc.subject                   = 1=21
+qualifier.dc.creator                   = 1=1003
+qualifier.dc.author                    = 1=1003
+       ### Unofficial synonym for "creator"
+qualifier.dc.editor                    = 1=1020
+qualifier.dc.publisher                 = 1=1018
+qualifier.dc.description               = 1=62
+       # "abstract"
+qualifier.dc.date                      = 1=30
+qualifier.dc.resourceType              = 1=1031
+       # guesswork: "Material-type"
+qualifier.dc.format                    = 1=1034
+       # guesswork: "Content-type"
+qualifier.dc.resourceIdentifier                = 1=12
+       # "Local number"
+qualifier.dc.source                    = 1=1019
+       # "Record-source"
+qualifier.dc.language                  = 1=54
+       # "Code--language"
+qualifier.dc.relation                  = 1=?
+       ### No idea how to represent this
+qualifier.dc.coverage                  = 1=?
+       ### No idea how to represent this
+qualifier.dc.rights                    = 1=?
+       ### No idea how to represent this
+
+### These aren't right: I've just put them here for the Generator
+qualifier.bath.subject                 = 1=21
+qualifier.bath.author                  = 1=1003
+qualifier.foo>bar                      = 1=2000
+
 # Relation attributes are selected according to the CQL relation by
-# looking up the "cql-java.relation.<relation>" property:
-#
-cql-java.relation.<            = 2=1
-cql-java.relation.<=           = 2=2
-cql-java.relation.=            = 2=3
-cql-java.relation.exact                = 2=3
-cql-java.relation.>=           = 2=4
-cql-java.relation.>            = 2=5
-cql-java.relation.<>           = 2=6
+# looking up the "relation.<relation>" property:
 #
-#      ### Should add support for relation modifiers
+relation.<                             = 2=1
+relation.le                            = 2=2
+relation.eq                            = 2=3
+relation.exact                         = 2=3
+relation.ge                            = 2=4
+relation.>                             = 2=5
+relation.<>                            = 2=6
+
+### These two are not really right:
+relation.all                           = 2=3
+relation.any                           = 2=3
+
+# Relation modifiers.
 #
+relationModifier.relevant              = 2=102
+relationModifier.fuzzy                 = 2=100
+       ### 100 is "phonetic", which is not quite the same thing
+relationModifier.stem                  = 2=101
+
 # Position attributes may be specified for anchored terms (those
 # beginning with "^", which is stripped) and unanchored (those not
 # beginning with "^").  This may change when we get a BIB-1 truncation
 # attribute that says "do what CQL does".
 #
-cql-java.position.anchored     = 3=1   # "first in field"
-cql-java.position.unanchored   = 3=3   # "any position in field"
-#
+position.anchored                      = 3=1
+       # "first in field"
+position.unanchored                    = 3=3
+       # "any position in field"
+
 # Structure attributes may be specified for individual relations; a
 # default structure attribute my be specified by the pseudo-relation
 # "*", to be used whenever a relation not listed here occurs.
 #
-cql-java.structure.exact       = 4=108 # phrase
-cql-java.structure.*           = 4=1   # phrase
-#
+structure.exact                                = 4=108
+       # phrase
+structure.*                            = 4=1
+       # phrase
+
 # Finally, any additional attributes that should always be included
-# with each term can be specified in the "cql-java.always" property.
+# with each term can be specified in the "always" property.
 #
-cql-java.always                        = 5=104 6=1
+always                                 = 5=104 6=1
 # 5=104: some kind of vaguely CQL-like masking, IIRC.
 # 6=1: completeness = incomplete subfield
index a3c3749..b0ca761 100644 (file)
@@ -1,12 +1,13 @@
-// $Id: CQLBooleanNode.java,v 1.7 2002-11-06 00:05:58 mike Exp $
+// $Id: CQLBooleanNode.java,v 1.8 2002-11-06 20:13:45 mike Exp $
 
 package org.z3950.zing.cql;
+import java.util.Properties;
 
 
 /**
  * Represents a boolean node in a CQL parse-tree.
  *
- * @version    $Id: CQLBooleanNode.java,v 1.7 2002-11-06 00:05:58 mike Exp $
+ * @version    $Id: CQLBooleanNode.java,v 1.8 2002-11-06 20:13:45 mike Exp $
  */
 public abstract class CQLBooleanNode extends CQLNode {
     CQLBooleanNode() {}                // prevent javadoc from documenting this
@@ -21,18 +22,16 @@ public abstract class CQLBooleanNode extends CQLNode {
      */ 
     public CQLNode right;
 
-    abstract String op();
-
     public String toXCQL(int level) {
        return (indent(level) + "<triple>\n" +
-               booleanXQL(level+1) +
+               opXQL(level+1) +
                left.toXCQL(level+1) +
                right.toXCQL(level+1) +
                indent(level) + "</triple>\n");
     }
 
     // Represents the boolean operation itself: overridden for CQLProxNode
-    String booleanXQL(int level) {
+    String opXQL(int level) {
        return(indent(level) + "<boolean>\n" +
               indent(level+1) + "<value>" + op() + "</value>\n" +
               indent(level) + "</boolean>\n");
@@ -42,4 +41,15 @@ public abstract class CQLBooleanNode extends CQLNode {
        // ### We don't always need parens around the operands
        return "(" + left.toCQL() + ") " + op() + " (" + right.toCQL() + ")";
     }
+
+    public String toPQF(Properties config) throws PQFTranslationException {
+       return ("@" + opPQF() +
+               " " + left.toPQF(config) +
+               " " + right.toPQF(config));
+    }
+
+    // represents the operation for PQF: overridden for CQLProxNode
+    String opPQF() { return op(); }
+
+    abstract String op();
 }
index 24a2d27..eab6db4 100644 (file)
@@ -1,4 +1,4 @@
-// $Id: CQLNode.java,v 1.11 2002-11-06 00:05:58 mike Exp $
+// $Id: CQLNode.java,v 1.12 2002-11-06 20:13:45 mike Exp $
 
 package org.z3950.zing.cql;
 import java.util.Properties;
@@ -7,7 +7,7 @@ import java.util.Properties;
 /**
  * Represents a node in a CQL parse-tree.
  *
- * @version    $Id: CQLNode.java,v 1.11 2002-11-06 00:05:58 mike Exp $
+ * @version    $Id: CQLNode.java,v 1.12 2002-11-06 20:13:45 mike Exp $
  */
 public abstract class CQLNode {
     CQLNode() {}               // prevent javadoc from documenting this
@@ -39,13 +39,32 @@ public abstract class CQLNode {
     /**
      * Renders a parse-tree into a Yaz-style PQF string.
      * <P>
+     * <PRE>
+       query ::= top-set query-struct.
+       top-set ::= [ '@attrset' string ]
+       query-struct ::= attr-spec | simple | complex | '@term' term-type
+       attr-spec ::= '@attr' [ string ] string query-struct
+       complex ::= operator query-struct query-struct.
+       operator ::= '@and' | '@or' | '@not' | '@prox' proximity.
+       simple ::= result-set | term.
+       result-set ::= '@set' string.
+       term ::= string.
+       proximity ::= exclusion distance ordered relation which-code unit-code.
+       exclusion ::= '1' | '0' | 'void'.
+       distance ::= integer.
+       ordered ::= '1' | '0'.
+       relation ::= integer.
+       which-code ::= 'known' | 'private' | integer.
+       unit-code ::= integer.
+       term-type ::= 'general' | 'numeric' | 'string' | 'oid' | 'datetime' | 'null'.
+     * </PRE>
      * @return
      * A String containing a PQF query equivalent to the parse-tree
      * whose root is this node.  This may be fed into the tool of
      * your choice to obtain a BER-encoded packet.
      */
     abstract public String toPQF(Properties config)
-       throws UnknownQualifierException, UnknownRelationException;
+       throws PQFTranslationException;
 
     /**
      * Returns a String of spaces for indenting to the specified level.
index ed0e0c6..845dfff 100644 (file)
@@ -1,4 +1,4 @@
-// $Id: CQLParseException.java,v 1.1 2002-10-30 09:19:26 mike Exp $
+// $Id: CQLParseException.java,v 1.2 2002-11-06 20:13:45 mike Exp $
 
 package org.z3950.zing.cql;
 import java.lang.Exception;
@@ -7,10 +7,16 @@ import java.lang.Exception;
 /**
  * Exception indicating that an error ocurred parsing CQL.
  *
- * @version    $Id: CQLParseException.java,v 1.1 2002-10-30 09:19:26 mike Exp $
+ * @version    $Id: CQLParseException.java,v 1.2 2002-11-06 20:13:45 mike Exp $
  */
 public class CQLParseException extends Exception {
-    CQLParseException(String s) {
+    /**
+     * Creates a new <TT>CQLParseException</TT>.
+     * @param s
+     * An error message describing the problem with the query,
+     * usually a syntax error of some kind.
+     */
+    public CQLParseException(String s) {
        super(s);
     }
 }
index 59cedf8..a365030 100644 (file)
@@ -1,4 +1,4 @@
-// $Id: CQLParser.java,v 1.15 2002-11-06 00:05:58 mike Exp $
+// $Id: CQLParser.java,v 1.16 2002-11-06 20:13:45 mike Exp $
 
 package org.z3950.zing.cql;
 import java.io.IOException;
@@ -12,7 +12,7 @@ import java.io.FileNotFoundException;
 /**
  * Compiles CQL strings into parse trees of CQLNode subtypes.
  *
- * @version    $Id: CQLParser.java,v 1.15 2002-11-06 00:05:58 mike Exp $
+ * @version    $Id: CQLParser.java,v 1.16 2002-11-06 20:13:45 mike Exp $
  * @see                <A href="http://zing.z3950.org/cql/index.html"
  *                     >http://zing.z3950.org/cql/index.html</A>
  */
@@ -328,7 +328,7 @@ public class CQLParser {
            try {
                // Read in the whole of standard input in one go
                int nbytes = System.in.read(bytes);
-           } catch (java.io.IOException ex) {
+           } catch (IOException ex) {
                System.err.println("Can't read query: " + ex.getMessage());
                System.exit(2);
            }
@@ -342,7 +342,7 @@ public class CQLParser {
        } catch (CQLParseException ex) {
            System.err.println("Syntax error: " + ex.getMessage());
            System.exit(3);
-       } catch (java.io.IOException ex) {
+       } catch (IOException ex) {
            System.err.println("Can't compile query: " + ex.getMessage());
            System.exit(4);
        }
@@ -362,9 +362,25 @@ public class CQLParser {
            } else {
                System.out.print(root.toXCQL(0));
            }
-       } catch (java.io.IOException ex) {
+       } catch (IOException ex) {
            System.err.println("Can't render query: " + ex.getMessage());
            System.exit(5);
+       } catch (UnknownQualifierException ex) {
+           System.err.println("Unknown qualifier: " + ex.getMessage());
+           System.exit(6);
+       } catch (UnknownRelationException ex) {
+           System.err.println("Unknown relation: " + ex.getMessage());
+           System.exit(7);
+       } catch (UnknownRelationModifierException ex) {
+           System.err.println("Unknown relation modifier: " +
+                              ex.getMessage());
+           System.exit(8);
+       } catch (UnknownPositionException ex) {
+           System.err.println("Unknown position: " + ex.getMessage());
+           System.exit(9);
+       } catch (PQFTranslationException ex) {
+           // We catch all of this class's subclasses, so --
+           throw new Error("can't get a PQFTranslationException");
        }
     }
 }
index 8c69ecc..b3a8dca 100644 (file)
@@ -1,6 +1,7 @@
-// $Id: CQLProxNode.java,v 1.2 2002-11-06 00:05:58 mike Exp $
+// $Id: CQLProxNode.java,v 1.3 2002-11-06 20:13:45 mike Exp $
 
 package org.z3950.zing.cql;
+import java.util.Vector;
 
 
 /**
@@ -9,7 +10,7 @@ package org.z3950.zing.cql;
  * candidate records which are sufficiently close to each other, as
  * specified by a set of proximity parameters.
  *
- * @version    $Id: CQLProxNode.java,v 1.2 2002-11-06 00:05:58 mike Exp $
+ * @version    $Id: CQLProxNode.java,v 1.3 2002-11-06 20:13:45 mike Exp $
  */
 public class CQLProxNode extends CQLBooleanNode {
     ModifierSet ms;
@@ -38,10 +39,6 @@ public class CQLProxNode extends CQLBooleanNode {
        this.right = right;
     }
 
-    String op() {
-       return ms.toCQL();
-    }
-
     /**
      * Adds a modifier of the specified <TT>type</TT> and
      * <TT>value</TT> to a proximity node.  Valid types are
@@ -57,9 +54,73 @@ public class CQLProxNode extends CQLBooleanNode {
        ms.addModifier(type, value);
     }
 
-    // ### should have a public method to retrieve all modifiers
+    /**
+     * Returns an array of the modifiers associated with a proximity
+     * node.
+     * @return
+     * An array of modifiers, each represented by a two-element
+     * <TT>Vector</TT>, in which element 0 is the modifier type
+     * (e.g. <TT>distance</TT> or <TT>ordering</TT>) and element 1 is
+     * the associated value (e.g. <TT>3</TT> or <TT>unordered</TT>).
+     */
+    public Vector[] getModifiers() {
+       return ms.getModifiers();
+    }
+
+    String op() {
+       return ms.toCQL();
+    }
 
-    String booleanXQL(int level) {
+    String opXQL(int level) {
        return ms.toXCQL(level, "boolean");
     }
+
+    /*
+     * proximity ::= exclusion distance ordered relation which-code unit-code.
+     * exclusion ::= '1' | '0' | 'void'.
+     * distance ::= integer.
+     * ordered ::= '1' | '0'.
+     * relation ::= integer.
+     * which-code ::= 'known' | 'private' | integer.
+     * unit-code ::= integer.
+     */
+    String opPQF() {
+       String rel = ms.modifier("relation");
+       int relCode = 0;
+       if (rel.equals("<")) {
+           relCode = 1;
+       } else if (rel.equals("<=")) {
+           relCode = 2;
+       } else if (rel.equals("=")) {
+           relCode = 3;
+       } else if (rel.equals(">=")) {
+           relCode = 4;
+       } else if (rel.equals(">")) {
+           relCode = 5;
+       } else if (rel.equals("<>")) {
+           relCode = 6;
+       }
+
+       String unit = ms.modifier("unit");
+       int unitCode = 0;
+       if (unit.equals("word")) {
+           unitCode = 2;
+       } else if (unit.equals("sentence")) {
+           unitCode = 3;
+       } else if (unit.equals("paragraph")) {
+           unitCode = 4;
+       } else if (unit.equals("element")) {
+           unitCode = 8;
+       }
+
+       String res = "prox " +
+           "0 " +
+           ms.modifier("distance") + " " +
+           (ms.modifier("ordering").equals("ordered") ? 1 : 0) + " " +
+           relCode + " " +
+           "1 " +
+           unitCode;
+       
+       return res;
+    }
 }
index f82b91e..0d98674 100644 (file)
@@ -1,4 +1,4 @@
-// $Id: CQLRelation.java,v 1.4 2002-11-06 00:14:32 mike Exp $
+// $Id: CQLRelation.java,v 1.5 2002-11-06 20:13:45 mike Exp $
 
 package org.z3950.zing.cql;
 import java.util.Vector;
@@ -7,9 +7,8 @@ import java.lang.StringBuffer;
 
 /**
  * Represents a relation between a CQL qualifier and term.
- * ##
  *
- * @version    $Id: CQLRelation.java,v 1.4 2002-11-06 00:14:32 mike Exp $
+ * @version    $Id: CQLRelation.java,v 1.5 2002-11-06 20:13:45 mike Exp $
  */
 public class CQLRelation extends CQLNode {
     ModifierSet ms;
@@ -26,7 +25,15 @@ public class CQLRelation extends CQLNode {
        ms.addModifier(null, modifier);
     }
 
-    // ### should have a public method to retrieve all modifiers
+    public String[] getModifiers() {
+       Vector[] v = ms.getModifiers();
+       int n = v.length;
+       String[] s = new String[n];
+       for (int i = 0; i < n; i++) {
+           s[i] = (String) v[i].get(1);
+       }
+       return s;
+    }
 
     public String toXCQL(int level) {
        return ms.toXCQL(level, "relation");
@@ -36,8 +43,7 @@ public class CQLRelation extends CQLNode {
        return ms.toCQL();
     }
 
-    public String toPQF(Properties config)
-       throws UnknownQualifierException, UnknownRelationException {
-       throw Error("CQLRelation.toPQF() can never be called");
+    public String toPQF(Properties config) throws PQFTranslationException {
+       throw new Error("CQLRelation.toPQF() can never be called");
     }
 }
index 5889354..9e7a7b9 100644 (file)
@@ -1,4 +1,4 @@
-// $Id: CQLTermNode.java,v 1.7 2002-11-06 00:05:58 mike Exp $
+// $Id: CQLTermNode.java,v 1.8 2002-11-06 20:13:45 mike Exp $
 
 package org.z3950.zing.cql;
 import java.util.Properties;
@@ -12,7 +12,7 @@ import java.util.Vector;
  * these must be provided - you can't have a qualifier without a
  * relation or vice versa.
  *
- * @version    $Id: CQLTermNode.java,v 1.7 2002-11-06 00:05:58 mike Exp $
+ * @version    $Id: CQLTermNode.java,v 1.8 2002-11-06 20:13:45 mike Exp $
  */
 public class CQLTermNode extends CQLNode {
     private String qualifier;
@@ -55,41 +55,66 @@ public class CQLTermNode extends CQLNode {
        return res;
     }
 
-    public String toPQF(Properties config)
-       throws UnknownQualifierException, UnknownRelationException {
+    public String toPQF(Properties config) throws PQFTranslationException {
        Vector attrs = new Vector();
 
-       if (qualifier != null) {
-           String s = config.getProperty(qualifier);
-           if (s == null)
-               throw new UnknownQualifierException(qualifier);
-           attrs.add(s);
-       } else {
-           // ### get a default access point from properties?
+       String attr;
+       attr = config.getProperty("qualifier." + qualifier);
+       if (attr == null)
+           throw new UnknownQualifierException(qualifier);
+       attrs.add(attr);
+
+       String rel = relation.getBase();
+       if (rel.equals("=")) {
+           rel = "eq";
+       } else if (rel.equals("<=")) {
+           rel = "le";
+       } else if (rel.equals(">=")) {
+           rel = "ge";
+       }
+       // ### Handling "any" and "all" properly would involve breaking
+       // the string down into a bunch of individual words and ORring
+       // or ANDing them together.  Another day.
+       attr = config.getProperty("relation." + rel);
+       if (attr == null)
+           throw new UnknownRelationException(rel);
+       attrs.add(attr);
+
+       String[] mods = relation.getModifiers();
+       for (int i = 0; i < mods.length; i++) {
+           attr = config.getProperty("relationModifier." + mods[i]);
+           if (attr == null)
+               throw new UnknownRelationModifierException(mods[i]);
+           attrs.add(attr);
        }
 
-       if (relation != null) {
-           String rel = relation.getBase();
-           // ### handle "any" and "all"
-           String s = config.getProperty("cql-java.relation." + rel);
-           if (s == null)
-               throw new UnknownRelationException(rel);
-           attrs.add(s);
-       } else {
-           // ### get a default relation from properties?
+       String pos = "unanchored";
+       String text = term;
+       if (text.length() > 0 && text.substring(0, 1).equals("^")) {
+           text = text.substring(1);
+           pos = "anchored";
        }
+       attr = config.getProperty("position." + pos);
+       if (attr == null)
+           throw new UnknownPositionException(pos);
+       attrs.add(attr);
+
+       attr = config.getProperty("structure." + rel);
+       if (attr == null)
+           attr = config.getProperty("structure.*");
+       attrs.add(attr);
 
-       // ### handle position attributes
-       // ### handle structure attributes
-       // ### handle "always" attributes
+       attr = config.getProperty("always");
+       if (attr != null)
+           attrs.add(attr);
 
-       // ### should split Vector elements on spaces
        String s = "";
        for (int i = 0; i < attrs.size(); i++) {
-           s += "@attr " + (String) attrs.get(i) + " ";
+           attr = (String) attrs.get(i);
+           s += "@attr " + Utils.replaceString(attr, " ", " @attr ") + " ";
        }
 
-       return s + maybeQuote(term);
+       return s + maybeQuote(text);
     }
 
     static String maybeQuote(String str) {
index fd3a211..961afbb 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.7 2002-11-06 00:05:58 mike Exp $
+# $Id: Makefile,v 1.8 2002-11-06 20:13:45 mike Exp $
 
 DOCDIR = ../../../../../docs
 
@@ -8,7 +8,9 @@ OBJ = Utils.class \
        CQLRelation.class CQLProxNode.class ModifierSet.class \
        CQLParser.class CQLLexer.class CQLParseException.class \
        CQLGenerator.class MissingParameterException.class \
-       UnknownQualifierException.class UnknownRelationException.class
+       PQFTranslationException.class \
+       UnknownQualifierException.class UnknownRelationException.class \
+       UnknownRelationModifierException.class UnknownPositionException.class
 
 ../../../../../lib/cql-java.jar: $(OBJ)
        cd ../../../..; jar cf ../lib/cql-java.jar org/z3950/zing/cql/*.class
index 3d184bd..3b54668 100644 (file)
@@ -1,4 +1,4 @@
-// $Id: MissingParameterException.java,v 1.1 2002-11-06 00:05:58 mike Exp $
+// $Id: MissingParameterException.java,v 1.2 2002-11-06 20:13:45 mike Exp $
 
 package org.z3950.zing.cql;
 import java.lang.Exception;
@@ -7,10 +7,15 @@ import java.lang.Exception;
 /**
  * Exception indicating that a required property was not specified.
  *
- * @version    $Id: MissingParameterException.java,v 1.1 2002-11-06 00:05:58 mike Exp $
+ * @version    $Id: MissingParameterException.java,v 1.2 2002-11-06 20:13:45 mike Exp $
  */
 public class MissingParameterException extends Exception {
-    MissingParameterException(String s) {
+    /**
+     * Creates a new <TT>MissingParameterException</TT>.
+     * @param s
+     * The name of the property whose value was required but not supplied.
+     */
+    public MissingParameterException(String s) {
        super(s);
     }
 }
index 4f61bed..8b8c245 100644 (file)
@@ -1,4 +1,4 @@
-// $Id: ModifierSet.java,v 1.3 2002-11-06 00:05:58 mike Exp $
+// $Id: ModifierSet.java,v 1.4 2002-11-06 20:13:45 mike Exp $
 
 package org.z3950.zing.cql;
 import java.util.Vector;
@@ -11,7 +11,7 @@ import java.lang.StringBuffer;
  * CQLProxNode - two functionally very separate classes that happen to
  * require the same data structures and functionality.
  *
- * @version $Id: ModifierSet.java,v 1.3 2002-11-06 00:05:58 mike Exp $
+ * @version $Id: ModifierSet.java,v 1.4 2002-11-06 20:13:45 mike Exp $
  */
 public class ModifierSet {
     String base;
@@ -33,6 +33,16 @@ public class ModifierSet {
        modifiers.add(modifier);
     }
 
+    public String modifier(String type) {
+       int n = modifiers.size();
+       for (int i = 0; i < n; i++) {
+           Vector pair = (Vector) modifiers.get(i);
+           if (pair.get(0).equals(type))
+               return (String) pair.get(1);
+       }
+       return null;
+    }
+
     public Vector[] getModifiers() {
        int n = modifiers.size();
        Vector[] res = new Vector[n];
diff --git a/src/org/z3950/zing/cql/PQFTranslationException.java b/src/org/z3950/zing/cql/PQFTranslationException.java
new file mode 100644 (file)
index 0000000..85ec184
--- /dev/null
@@ -0,0 +1,16 @@
+// $Id: PQFTranslationException.java,v 1.1 2002-11-06 20:13:45 mike Exp $
+
+package org.z3950.zing.cql;
+import java.lang.Exception;
+
+
+/**
+ * Base class for exceptions occurring when translating parse trees to PQF.
+ *
+ * @version $Id: PQFTranslationException.java,v 1.1 2002-11-06 20:13:45 mike Exp $
+ */
+public class PQFTranslationException extends Exception {
+    PQFTranslationException(String s) {
+       super(s);
+    }
+}
diff --git a/src/org/z3950/zing/cql/UnknownPositionException.java b/src/org/z3950/zing/cql/UnknownPositionException.java
new file mode 100644 (file)
index 0000000..39f4927
--- /dev/null
@@ -0,0 +1,27 @@
+// $Id: UnknownPositionException.java,v 1.1 2002-11-06 20:13:45 mike Exp $
+
+package org.z3950.zing.cql;
+import java.lang.Exception;
+
+
+/**
+ * Exception indicating that a position was not recognised.
+ * When rendering a tree out as PQF, each term is classified either as
+ * <TT>anchored</TT> or <TT>unanchored</TT>, depending on whether it
+ * begins with the word-anchoring meta-character <TT>^</TT>, and its
+ * classification is looked up as a <TT>position</TT> in the PQF
+ * configuration.  If the position is not configured, we throw one of
+ * these babies.
+ *
+ * @version $Id: UnknownPositionException.java,v 1.1 2002-11-06 20:13:45 mike Exp $
+ */
+public class UnknownPositionException extends PQFTranslationException {
+    /**
+     * Creates a new <TT>UnknownPositionException</TT>.
+     * @param s
+     * The position for which there was no PQF configuration.
+     */
+    public UnknownPositionException(String s) {
+       super(s);
+    }
+}
index ba43baf..8bad79e 100644 (file)
@@ -1,4 +1,4 @@
-// $Id: UnknownQualifierException.java,v 1.1 2002-11-06 00:05:58 mike Exp $
+// $Id: UnknownQualifierException.java,v 1.2 2002-11-06 20:13:45 mike Exp $
 
 package org.z3950.zing.cql;
 import java.lang.Exception;
@@ -9,12 +9,18 @@ import java.lang.Exception;
  * At compilation time, we accept any syntactically valid qualifier;
  * but when rendering a tree out as PQF, we need to translate the
  * qualifiers into sets of Type-1 query attributes.  If we can't do
- * that, we throw one of these babies.
+ * that, because the PQF configuration doesn't know about a relation,
+ * we throw one of these babies.
  *
- * @version $Id: UnknownQualifierException.java,v 1.1 2002-11-06 00:05:58 mike Exp $
+ * @version $Id: UnknownQualifierException.java,v 1.2 2002-11-06 20:13:45 mike Exp $
  */
-public class UnknownQualifierException extends Exception {
-    UnknownQualifierException(String s) {
+public class UnknownQualifierException extends PQFTranslationException {
+    /**
+     * Creates a new <TT>UnknownQualifierException</TT>.
+     * @param s
+     * The qualifier for which there was no PQF configuration.
+     */
+    public UnknownQualifierException(String s) {
        super(s);
     }
 }
index 6029bf4..4d65e72 100644 (file)
@@ -1,4 +1,4 @@
-// $Id: UnknownRelationException.java,v 1.1 2002-11-06 00:05:58 mike Exp $
+// $Id: UnknownRelationException.java,v 1.2 2002-11-06 20:13:45 mike Exp $
 
 package org.z3950.zing.cql;
 import java.lang.Exception;
@@ -9,12 +9,18 @@ import java.lang.Exception;
  * At compilation time, we accept any syntactically valid relation;
  * but when rendering a tree out as PQF, we need to translate the
  * relations into sets of Type-1 query attributes.  If we can't do
- * that, we throw one of these babies.
+ * that, because the PQF configuration doesn't know about a relation,
+ * we throw one of these babies.
  *
- * @version $Id: UnknownRelationException.java,v 1.1 2002-11-06 00:05:58 mike Exp $
+ * @version $Id: UnknownRelationException.java,v 1.2 2002-11-06 20:13:45 mike Exp $
  */
-public class UnknownRelationException extends Exception {
-    UnknownRelationException(String s) {
+public class UnknownRelationException extends PQFTranslationException {
+    /**
+     * Creates a new <TT>UnknownRelationException</TT>.
+     * @param s
+     * The relation for which there was no PQF configuration.
+     */
+    public UnknownRelationException(String s) {
        super(s);
     }
 }
diff --git a/src/org/z3950/zing/cql/UnknownRelationModifierException.java b/src/org/z3950/zing/cql/UnknownRelationModifierException.java
new file mode 100644 (file)
index 0000000..9d449b5
--- /dev/null
@@ -0,0 +1,26 @@
+// $Id: UnknownRelationModifierException.java,v 1.1 2002-11-06 20:13:45 mike Exp $
+
+package org.z3950.zing.cql;
+import java.lang.Exception;
+
+
+/**
+ * Exception indicating that a relation modifier was not recognised.
+ * At compilation time, we accept any syntactically valid relation modifier;
+ * but when rendering a tree out as PQF, we need to translate the
+ * relation modifiers into sets of Type-1 query attributes.  If we can't do
+ * that, because the PQF configuration doesn't know about a relation modifier,
+ * we throw one of these babies.
+ *
+ * @version $Id: UnknownRelationModifierException.java,v 1.1 2002-11-06 20:13:45 mike Exp $
+ */
+public class UnknownRelationModifierException extends PQFTranslationException {
+    /**
+     * Creates a new <TT>UnknownRelationModifierException</TT>.
+     * @param s
+     * The relation modifier for which there was no PQF configuration.
+     */
+    public UnknownRelationModifierException(String s) {
+       super(s);
+    }
+}