From: mike Date: Wed, 6 Nov 2002 20:13:45 +0000 (+0000) Subject: Finish (more or less) to CQL-to-PQF translator. X-Git-Tag: v1.5~233 X-Git-Url: http://lists.indexdata.dk/?a=commitdiff_plain;h=fc82b225d39cc66cb85c2557db0c0d4a4c5a6e27;p=cql-java-moved-to-github.git Finish (more or less) to CQL-to-PQF translator. 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. --- diff --git a/Changes b/Changes index cc072fe..884403f 100644 --- 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 " 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 --- 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. diff --git a/etc/pqf.properties b/etc/pqf.properties index 4508572..875d871 100644 --- a/etc/pqf.properties +++ b/etc/pqf.properties @@ -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." 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." 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 diff --git a/src/org/z3950/zing/cql/CQLBooleanNode.java b/src/org/z3950/zing/cql/CQLBooleanNode.java index a3c3749..b0ca761 100644 --- a/src/org/z3950/zing/cql/CQLBooleanNode.java +++ b/src/org/z3950/zing/cql/CQLBooleanNode.java @@ -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) + "\n" + - booleanXQL(level+1) + + opXQL(level+1) + left.toXCQL(level+1) + right.toXCQL(level+1) + indent(level) + "\n"); } // Represents the boolean operation itself: overridden for CQLProxNode - String booleanXQL(int level) { + String opXQL(int level) { return(indent(level) + "\n" + indent(level+1) + "" + op() + "\n" + indent(level) + "\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(); } diff --git a/src/org/z3950/zing/cql/CQLNode.java b/src/org/z3950/zing/cql/CQLNode.java index 24a2d27..eab6db4 100644 --- a/src/org/z3950/zing/cql/CQLNode.java +++ b/src/org/z3950/zing/cql/CQLNode.java @@ -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. *

+ *

+	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'.
+     * 
* @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. diff --git a/src/org/z3950/zing/cql/CQLParseException.java b/src/org/z3950/zing/cql/CQLParseException.java index ed0e0c6..845dfff 100644 --- a/src/org/z3950/zing/cql/CQLParseException.java +++ b/src/org/z3950/zing/cql/CQLParseException.java @@ -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 CQLParseException. + * @param s + * An error message describing the problem with the query, + * usually a syntax error of some kind. + */ + public CQLParseException(String s) { super(s); } } diff --git a/src/org/z3950/zing/cql/CQLParser.java b/src/org/z3950/zing/cql/CQLParser.java index 59cedf8..a365030 100644 --- a/src/org/z3950/zing/cql/CQLParser.java +++ b/src/org/z3950/zing/cql/CQLParser.java @@ -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 http://zing.z3950.org/cql/index.html */ @@ -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"); } } } diff --git a/src/org/z3950/zing/cql/CQLProxNode.java b/src/org/z3950/zing/cql/CQLProxNode.java index 8c69ecc..b3a8dca 100644 --- a/src/org/z3950/zing/cql/CQLProxNode.java +++ b/src/org/z3950/zing/cql/CQLProxNode.java @@ -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 type and * value 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 + * Vector, in which element 0 is the modifier type + * (e.g. distance or ordering) and element 1 is + * the associated value (e.g. 3 or unordered). + */ + 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; + } } diff --git a/src/org/z3950/zing/cql/CQLRelation.java b/src/org/z3950/zing/cql/CQLRelation.java index f82b91e..0d98674 100644 --- a/src/org/z3950/zing/cql/CQLRelation.java +++ b/src/org/z3950/zing/cql/CQLRelation.java @@ -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"); } } diff --git a/src/org/z3950/zing/cql/CQLTermNode.java b/src/org/z3950/zing/cql/CQLTermNode.java index 5889354..9e7a7b9 100644 --- a/src/org/z3950/zing/cql/CQLTermNode.java +++ b/src/org/z3950/zing/cql/CQLTermNode.java @@ -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) { diff --git a/src/org/z3950/zing/cql/Makefile b/src/org/z3950/zing/cql/Makefile index fd3a211..961afbb 100644 --- a/src/org/z3950/zing/cql/Makefile +++ b/src/org/z3950/zing/cql/Makefile @@ -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 diff --git a/src/org/z3950/zing/cql/MissingParameterException.java b/src/org/z3950/zing/cql/MissingParameterException.java index 3d184bd..3b54668 100644 --- a/src/org/z3950/zing/cql/MissingParameterException.java +++ b/src/org/z3950/zing/cql/MissingParameterException.java @@ -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 MissingParameterException. + * @param s + * The name of the property whose value was required but not supplied. + */ + public MissingParameterException(String s) { super(s); } } diff --git a/src/org/z3950/zing/cql/ModifierSet.java b/src/org/z3950/zing/cql/ModifierSet.java index 4f61bed..8b8c245 100644 --- a/src/org/z3950/zing/cql/ModifierSet.java +++ b/src/org/z3950/zing/cql/ModifierSet.java @@ -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 index 0000000..85ec184 --- /dev/null +++ b/src/org/z3950/zing/cql/PQFTranslationException.java @@ -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 index 0000000..39f4927 --- /dev/null +++ b/src/org/z3950/zing/cql/UnknownPositionException.java @@ -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 + * anchored or unanchored, depending on whether it + * begins with the word-anchoring meta-character ^, and its + * classification is looked up as a position 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 UnknownPositionException. + * @param s + * The position for which there was no PQF configuration. + */ + public UnknownPositionException(String s) { + super(s); + } +} diff --git a/src/org/z3950/zing/cql/UnknownQualifierException.java b/src/org/z3950/zing/cql/UnknownQualifierException.java index ba43baf..8bad79e 100644 --- a/src/org/z3950/zing/cql/UnknownQualifierException.java +++ b/src/org/z3950/zing/cql/UnknownQualifierException.java @@ -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 UnknownQualifierException. + * @param s + * The qualifier for which there was no PQF configuration. + */ + public UnknownQualifierException(String s) { super(s); } } diff --git a/src/org/z3950/zing/cql/UnknownRelationException.java b/src/org/z3950/zing/cql/UnknownRelationException.java index 6029bf4..4d65e72 100644 --- a/src/org/z3950/zing/cql/UnknownRelationException.java +++ b/src/org/z3950/zing/cql/UnknownRelationException.java @@ -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 UnknownRelationException. + * @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 index 0000000..9d449b5 --- /dev/null +++ b/src/org/z3950/zing/cql/UnknownRelationModifierException.java @@ -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 UnknownRelationModifierException. + * @param s + * The relation modifier for which there was no PQF configuration. + */ + public UnknownRelationModifierException(String s) { + super(s); + } +}