+++ /dev/null
-// $Id: CQLAndNode.java,v 1.1 2002-12-04 16:54:01 mike Exp $
-
-package org.z3950.zing.cql;
-
-
-/**
- * Represents an AND node in a CQL parse-tree.
- *
- * @version $Id: CQLAndNode.java,v 1.1 2002-12-04 16:54:01 mike Exp $
- */
-public class CQLAndNode extends CQLBooleanNode {
- /**
- * Creates a new AND node with the specified left- and right-hand sides.
- */
- public CQLAndNode(CQLNode left, CQLNode right) {
- this.left = left;
- this.right = right;
- }
-
- String op() {
- return "and";
- }
-
- byte[] opType1() {
- byte[] op=new byte[5];
- putTag(CONTEXT, 46, CONSTRUCTED, op, 0); // Operator
- putLen(2, op, 2);
- putTag(CONTEXT, 0, PRIMITIVE, op, 3); // and
- putLen(0, op, 4);
- return op;
- }
-}
+++ /dev/null
-// $Id: CQLBooleanNode.java,v 1.1 2002-12-04 16:54:01 mike Exp $
-
-package org.z3950.zing.cql;
-import java.util.Properties;
-import java.util.Vector;
-
-
-/**
- * Represents a boolean node in a CQL parse-tree.
- *
- * @version $Id: CQLBooleanNode.java,v 1.1 2002-12-04 16:54:01 mike Exp $
- */
-public abstract class CQLBooleanNode extends CQLNode {
- CQLBooleanNode() {} // prevent javadoc from documenting this
-
- /**
- * The root of a parse-tree representing the left-hand side.
- */
- public CQLNode left;
-
- /**
- * The root of a parse-tree representing the right-hand side.
- */
- public CQLNode right;
-
- public String toXCQL(int level, Vector prefixes) {
- return (indent(level) + "<triple>\n" +
- renderPrefixes(level+1, prefixes) +
- opXCQL(level+1) +
- indent(level+1) + "<leftOperand>\n" +
- left.toXCQL(level+2, new Vector()) +
- indent(level+1) + "</leftOperand>\n" +
- indent(level+1) + "<rightOperand>\n" +
- right.toXCQL(level+2, new Vector()) +
- indent(level+1) + "</rightOperand>\n" +
- indent(level) + "</triple>\n");
- }
-
- // Represents the boolean operation itself: overridden for CQLProxNode
- String opXCQL(int level) {
- return(indent(level) + "<boolean>\n" +
- indent(level+1) + "<value>" + op() + "</value>\n" +
- indent(level) + "</boolean>\n");
- }
-
- public String toCQL() {
- // ### 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));
- }
-
- public byte[] toType1(Properties config) throws PQFTranslationException {
- System.out.println("in CQLBooleanNode.toType101(): PQF="+toPQF(config));
- byte[] rpn1=left.toType1(config);
- byte[] rpn2=right.toType1(config);
- byte[] op=opType1();
- byte[] rpnStructure=new byte[rpn1.length+rpn2.length+op.length+4];
-
- int offset=putTag(CONTEXT, 1, CONSTRUCTED, rpnStructure, 0); // rpnRpnOp
- rpnStructure[offset++]=(byte)(0x80&0xff); // indefinite length
- System.arraycopy(rpn1, 0, rpnStructure, offset, rpn1.length);
- offset+=rpn1.length;
- System.arraycopy(rpn2, 0, rpnStructure, offset, rpn2.length);
- offset+=rpn2.length;
- System.arraycopy(op, 0, rpnStructure, offset, op.length);
- offset+=op.length;
- rpnStructure[offset++]=0x00; // end rpnRpnOp
- rpnStructure[offset++]=0x00;
- return rpnStructure;
- }
-
- // represents the operation for PQF: overridden for CQLProxNode
- String opPQF() { return op(); }
-
- abstract String op();
- abstract byte[] opType1();
-}
+++ /dev/null
-// $Id: CQLNotNode.java,v 1.1 2002-12-04 16:54:01 mike Exp $
-
-package org.z3950.zing.cql;
-
-
-/**
- * Represents a NOT node in a CQL parse-tree.
- *
- * @version $Id: CQLNotNode.java,v 1.1 2002-12-04 16:54:01 mike Exp $
- */
-public class CQLNotNode extends CQLBooleanNode {
- /**
- * Creates a new NOT node with the specified left- and right-hand sides.
- */
- public CQLNotNode(CQLNode left, CQLNode right) {
- this.left = left;
- this.right = right;
- }
-
- String op() {
- return "not";
- }
-
- byte[] opType1() {
- byte[] op=new byte[5];
- putTag(CONTEXT, 46, CONSTRUCTED, op, 0); // Operator
- putLen(2, op, 2);
- putTag(CONTEXT, 2, PRIMITIVE, op, 3); // and-not
- putLen(0, op, 4);
- return op;
- }
-
-}
+++ /dev/null
-// $Id: CQLOrNode.java,v 1.1 2002-12-04 16:54:01 mike Exp $
-
-package org.z3950.zing.cql;
-
-
-/**
- * Represents an OR node in a CQL parse-tree.
- *
- * @version $Id: CQLOrNode.java,v 1.1 2002-12-04 16:54:01 mike Exp $
- */
-public class CQLOrNode extends CQLBooleanNode {
- /**
- * Creates a new OR node with the specified left- and right-hand sides.
- */
- public CQLOrNode(CQLNode left, CQLNode right) {
- this.left = left;
- this.right = right;
- }
-
- String op() {
- return "or";
- }
-
- byte[] opType1() {
- byte[] op=new byte[5];
- putTag(CONTEXT, 46, CONSTRUCTED, op, 0); // Operator
- putLen(2, op, 2);
- putTag(CONTEXT, 1, PRIMITIVE, op, 3); // or
- putLen(0, op, 4);
- return op;
- }
-
-}
+++ /dev/null
-// $Id: CQLPrefix.java,v 1.1 2002-12-04 16:54:01 mike Exp $
-
-package org.z3950.zing.cql;
-import java.lang.String;
-
-/**
- * Represents a CQL prefix mapping from short name to long identifier.
- *
- * @version $Id: CQLPrefix.java,v 1.1 2002-12-04 16:54:01 mike Exp $
- */
-public class CQLPrefix {
- /**
- * The short name of the prefix mapping. That is, the prefix
- * itself, such as <TT>dc</TT>, as it might be used in a qualifier
- * like <TT>dc.title</TT>.
- */
- public String name;
-
- /**
- * The full identifier name of the prefix mapping. That is,
- * typically, a URI permanently allocated to a specific qualifier
- * set, such as <TT>http://zthes.z3950.org/cql/1.0<TT>.
- */
- public String identifier;
-
- /**
- * Creates a new CQLPrefix mapping, which maps the specified name
- * to the specified identifier.
- */
- CQLPrefix(String name, String identifier) {
- this.name = name;
- this.identifier = identifier;
- }
-}
+++ /dev/null
-// $Id: CQLPrefixNode.java,v 1.1 2002-12-04 16:54:01 mike Exp $
-
-package org.z3950.zing.cql;
-import java.lang.String;
-import java.util.Properties;
-import java.util.Vector;
-
-
-/**
- * Represents a prefix node in a CQL parse-tree.
- *
- * @version $Id: CQLPrefixNode.java,v 1.1 2002-12-04 16:54:01 mike Exp $
- */
-public class CQLPrefixNode extends CQLNode {
- /**
- * The prefix definition that governs the subtree.
- */
- public CQLPrefix prefix;
-
- /**
- * The root of a parse-tree representing the part of the query
- * that is governed by this prefix definition.
- */
- public CQLNode subtree;
-
- /**
- * Creates a new CQLPrefixNode inducing a mapping from the
- * specified qualifier-set name to the specified identifier across
- * the specified subtree.
- */
- public CQLPrefixNode(String name, String identifier, CQLNode subtree) {
- this.prefix = new CQLPrefix(name, identifier);
- this.subtree = subtree;
- }
-
- public String toXCQL(int level, Vector prefixes) {
-// String maybeName = "";
-// if (prefix.name != null)
-// maybeName = indent(level+1) + "<name>" + prefix.name + "</name>\n";
-//
-// return (indent(level) + "<prefix>\n" + maybeName +
-// indent(level+1) +
-// "<identifier>" + prefix.identifier + "</identifier>\n" +
-// subtree.toXCQL(level+1, prefixes) +
-// indent(level) + "</prefix>\n");
- Vector tmp = new Vector(prefixes);
- tmp.add(prefix);
- return subtree.toXCQL(level, tmp);
- }
-
- public String toCQL() {
- // ### We don't always need parens around the operand
- return ">" + prefix.name + "=\"" + prefix.identifier + "\" " +
- "(" + subtree.toCQL() + ")";
- }
-
- public String toPQF(Properties config) throws PQFTranslationException {
- // Prefixes and their identifiers don't actually play any role
- // in PQF translation, since the meanings of the qualifiers,
- // including their prefixes if any, are instead wired into
- // `config'.
- return subtree.toPQF(config);
- }
-
- public byte[] toType1(Properties config) throws PQFTranslationException {
- // Prefixes and their identifiers don't actually play any role
- // in PQF translation, since the meanings of the qualifiers,
- // including their prefixes if any, are instead wired into
- // `config'.
- return subtree.toType1(config);
- }
-}
+++ /dev/null
-// $Id: CQLProxNode.java,v 1.1 2002-12-04 16:54:01 mike Exp $
-
-package org.z3950.zing.cql;
-import java.util.Vector;
-
-
-/**
- * Represents a proximity node in a CQL parse-tree.
- * The left- and right-hand-sides must be satisfied by parts of the
- * candidate records which are sufficiently close to each other, as
- * specified by a set of proximity parameters.
- *
- * @version $Id: CQLProxNode.java,v 1.1 2002-12-04 16:54:01 mike Exp $
- */
-public class CQLProxNode extends CQLBooleanNode {
- ModifierSet ms;
-
- /**
- * Creates a new, <I>incomplete</I>, proximity node with the
- * specified left-hand side. No right-hand side is specified at
- * this stage: that must be specified later, using the
- * <TT>addSecondSubterm()</TT> method. (That may seem odd, but
- * it's just easier to write the parser that way.)
- * <P>
- * Proximity paramaters may be added at any time, before or after
- * the right-hand-side sub-tree is added.
- */
- public CQLProxNode(CQLNode left) {
- ms = new ModifierSet("prox");
- this.left = left;
- // this.right left unresolved for now ...
- }
-
- /**
- * Sets the right-hand side of the proximity node whose
- * left-hand-side was specified at creation time.
- */
- public void addSecondSubterm(CQLNode right) {
- this.right = right;
- }
-
- /**
- * Adds a modifier of the specified <TT>type</TT> and
- * <TT>value</TT> to a proximity node. Valid types are
- * <TT>relation</TT>, <TT>distance</TT>, <TT>unit</TT> and
- * <TT>ordering</TT>.
- * <P>
- * For information on the semantics of these paramaters, see
- * <A href="http://zing.z3950.org/cql/intro.html#3.1"
- * >section 3.1 (Proximity)</A> of
- * <I>A Gentle Introduction to CQL</I></A>.
- */
- public void addModifier(String type, String value) {
- ms.addModifier(type, value);
- }
-
- /**
- * 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 opXCQL(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() {
- int relCode = getRelCode();
-
- int unitCode = getProxUnitCode();
-
- String res = "prox " +
- "0 " +
- ms.modifier("distance") + " " +
- (ms.modifier("ordering").equals("ordered") ? 1 : 0) + " " +
- relCode + " " +
- "1 " +
- unitCode;
-
- return res;
- }
-
- private int getRelCode() {
- String rel = ms.modifier("relation");
- if (rel.equals("<")) {
- return 1;
- } else if (rel.equals("<=")) {
- return 2;
- } else if (rel.equals("=")) {
- return 3;
- } else if (rel.equals(">=")) {
- return 4;
- } else if (rel.equals(">")) {
- return 5;
- } else if (rel.equals("<>")) {
- return 6;
- }
- return 0;
- }
-
- private int getProxUnitCode() {
- String unit = ms.modifier("unit");
- if (unit.equals("word")) {
- return 2;
- } else if (unit.equals("sentence")) {
- return 3;
- } else if (unit.equals("paragraph")) {
- return 4;
- } else if (unit.equals("element")) {
- return 8;
- }
- return 0;
- }
-
-
- byte[] opType1() {
- byte[] op=new byte[100];
- int offset, value;
- offset=putTag(CONTEXT, 46, CONSTRUCTED, op, 0); // Operator
- op[offset++]=(byte)(0x80&0xff); // indefinite length
-
- offset=putTag(CONTEXT, 3, CONSTRUCTED, op, offset); // prox
- op[offset++]=(byte)(0x80&0xff); // indefinite length
-
- offset=putTag(CONTEXT, 1, PRIMITIVE, op, offset); // exclusion
- value=0; // value=0=false
- offset=putLen(numLen(value), op, offset);
- offset=putNum(value, op, offset);
-
- offset=putTag(CONTEXT, 2, PRIMITIVE, op, offset); // distance
- value=Integer.parseInt(ms.modifier("distance"));
- offset=putLen(numLen(value), op, offset);
- offset=putNum(value, op, offset);
-
- offset=putTag(CONTEXT, 3, PRIMITIVE, op, offset); // ordered
- value=ms.modifier("ordering").equals("ordered") ? 1 : 0;
- offset=putLen(numLen(value), op, offset);
- offset=putNum(value, op, offset);
-
- offset=putTag(CONTEXT, 4, PRIMITIVE, op, offset); // relationType
- value=getRelCode();
- offset=putLen(numLen(value), op, offset);
- offset=putNum(value, op, offset);
-
- offset=putTag(CONTEXT, 5, CONSTRUCTED, op, offset); // proximityUnitCode
- op[offset++]=(byte)(0x80&0xff); // indefinite length
- offset=putTag(CONTEXT, 1, PRIMITIVE, op, offset); // known
- value=getProxUnitCode();
- offset=putLen(numLen(value), op, offset);
- offset=putNum(value, op, offset);
- op[offset++]=0x00; // end of proximityUnitCode
- op[offset++]=0x00;
-
- op[offset++]=0x00; // end of prox
- op[offset++]=0x00;
- op[offset++]=0x00; // end of Operator
- op[offset++]=0x00;
-
- byte[] o=new byte[offset];
- System.arraycopy(op, 0, o, 0, offset);
- return o;
- }
-
-}
+++ /dev/null
-// $Id: CQLTermNode.java,v 1.1 2002-12-04 16:54:01 mike Exp $
-
-package org.z3950.zing.cql;
-import java.util.Properties;
-import java.util.Vector;
-
-
-/**
- * Represents a terminal node in a CQL parse-tree.
- * A term node consists of the term String itself, together with,
- * optionally, a qualifier string and a relation. Neither or both of
- * these must be provided - you can't have a qualifier without a
- * relation or vice versa.
- *
- * @version $Id: CQLTermNode.java,v 1.1 2002-12-04 16:54:01 mike Exp $
- */
-public class CQLTermNode extends CQLNode {
- private String qualifier;
- private CQLRelation relation;
- private String term;
-
- /**
- * Creates a new term node with the specified <TT>qualifier</TT>,
- * <TT>relation</TT> and <TT>term</TT>. The first two may be
- * <TT>null</TT>, but the <TT>term</TT> may not.
- */
- public CQLTermNode(String qualifier, CQLRelation relation, String term) {
- this.qualifier = qualifier;
- this.relation = relation;
- this.term = term;
- }
-
- public String getQualifier() { return qualifier; }
- public CQLRelation getRelation() { return relation; }
- public String getTerm() { return term; }
-
- public String toXCQL(int level, Vector prefixes) {
- return (indent(level) + "<searchClause>\n" +
- renderPrefixes(level+1, prefixes) +
- indent(level+1) + "<index>" + xq(qualifier) + "</index>\n" +
- relation.toXCQL(level+1, new Vector()) +
- indent(level+1) + "<term>" + xq(term) + "</term>\n" +
- indent(level) + "</searchClause>\n");
- }
-
- public String toCQL() {
- String quotedQualifier = maybeQuote(qualifier);
- String quotedTerm = maybeQuote(term);
- String res = quotedTerm;
-
- if (!qualifier.equalsIgnoreCase("srw.serverChoice")) {
- // ### We don't always need spaces around `relation'.
- res = quotedQualifier + " " + relation.toCQL() + " " + quotedTerm;
- }
-
- return res;
- }
-
-
- private Vector getAttrs(Properties config) throws PQFTranslationException {
- Vector attrs = new Vector();
-
- 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);
- }
-
- 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);
-
- attr = config.getProperty("always");
- if (attr != null)
- attrs.add(attr);
- return attrs;
- }
-
- public String toPQF(Properties config) throws PQFTranslationException {
- Vector attrs=getAttrs(config);
-
- String attr, s = "";
- for (int i = 0; i < attrs.size(); i++) {
- attr = (String) attrs.get(i);
- s += "@attr " + Utils.replaceString(attr, " ", " @attr ") + " ";
- }
-
- String text = term;
- if (text.length() > 0 && text.substring(0, 1).equals("^"))
- text = text.substring(1);
- return s + maybeQuote(text);
- }
-
- static String maybeQuote(String str) {
- // There _must_ be a better way to make this test ...
- if (str.length() == 0 ||
- str.indexOf('"') != -1 ||
- str.indexOf(' ') != -1 ||
- str.indexOf('\t') != -1 ||
- str.indexOf('=') != -1 ||
- str.indexOf('<') != -1 ||
- str.indexOf('>') != -1 ||
- str.indexOf('/') != -1 ||
- str.indexOf('(') != -1 ||
- str.indexOf(')') != -1) {
- str = '"' + Utils.replaceString(str, "\"", "\\\"") + '"';
- }
-
- return str;
- }
-
- /** Renders a parse-tree into a Yaz-style PQF string.
- * PQF, or Prefix Query Format, is a cryptic but powerful notation
- * that can be trivially mapped, one-to-one, int Z39.50 Type-1 and
- * Type-101 queries. A specification for the format can be found
- * in
- * <A href="http://indexdata.dk/yaz/doc/tools.php#PQF"
- * >Chapter 7 (Supporting Tools)</A> of the
- * <A href="http://indexdata.dk/yaz/">YAZ</A> manual.
- * <P>
- * @param config
- * A <TT>Properties</TT> object containing configuration
- * information that specifies the mapping from CQL qualifiers,
- * relations, etc. to Type-1 attributes. The mapping
- * specification is described in the cql-java distribution's
- * sample PQF-mapping configuration file,
- * <TT>etc/pqf.properties</TT>, which see.
- * @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.
- */
- public byte[] toType1(Properties config) throws PQFTranslationException {
- String text = term;
- if (text.length() > 0 && text.substring(0, 1).equals("^"))
- text = text.substring(1);
- String attr, attrList, term=maybeQuote(text);
- System.out.println("in CQLTermNode.toType101(): PQF="+toPQF(config));
- byte[] operand=new byte[text.length()+100];
- int i, j, offset, type, value;
- offset=putTag(CONTEXT, 0, CONSTRUCTED, operand, 0); // op
- operand[offset++]=(byte)(0x80&0xff); // indefinite length
- offset=putTag(CONTEXT, 102, CONSTRUCTED, operand, offset); // AttributesPlusTerm
- operand[offset++]=(byte)(0x80&0xff); // indefinite length
- offset=putTag(CONTEXT, 44, CONSTRUCTED, operand, offset); // AttributeList
- operand[offset++]=(byte)(0x80&0xff); // indefinite length
- offset=putTag(UNIVERSAL, SEQUENCE, CONSTRUCTED, operand, offset);
- operand[offset++]=(byte)(0x80&0xff);
-
- Vector attrs=getAttrs(config);
- for(i = 0; i < attrs.size(); i++) {
- attrList = (String) attrs.get(i);
- java.util.StringTokenizer st=new java.util.StringTokenizer(attrList);
- while(st.hasMoreTokens()) {
- attr=st.nextToken();
- j=attr.indexOf('=');
- offset=putTag(CONTEXT, 120, PRIMITIVE, operand, offset);
- type=Integer.parseInt(attr.substring(0, j));
- offset=putLen(numLen(type), operand, offset);
- offset=putNum(type, operand, offset);
-
- offset=putTag(CONTEXT, 121, PRIMITIVE, operand, offset);
- value=Integer.parseInt(attr.substring(j+1));
- offset=putLen(numLen(value), operand, offset);
- offset=putNum(value, operand, offset);
- }
- }
- operand[offset++]=0x00; // end of SEQUENCE
- operand[offset++]=0x00;
- operand[offset++]=0x00; // end of AttributeList
- operand[offset++]=0x00;
-
- offset=putTag(CONTEXT, 45, PRIMITIVE, operand, offset); // general Term
- byte[] t=term.getBytes();
- offset=putLen(t.length, operand, offset);
- System.arraycopy(t, 0, operand, offset, t.length);
- offset+=t.length;
-
- operand[offset++]=0x00; // end of AttributesPlusTerm
- operand[offset++]=0x00;
- operand[offset++]=0x00; // end of Operand
- operand[offset++]=0x00;
- byte[] o=new byte[offset];
- System.arraycopy(operand, 0, o, 0, offset);
- return o;
- }
-
-}