def query_struct(self): self.fetch_token() if (self.currentToken == '@attr'): attrs = [] while self.currentToken == '@attr': attrs.append(self.attr_spec()) self.fetch_token() t = self.term() # Now we have attrs + term clause = z3950.AttributesPlusTerm() clause.attributes = [make_attr(*e) for e in attrs] clause.term = t return ('op', ('attrTerm', clause)) elif (self.is_boolean()): # @operator query query return self.complex() elif (self.currentToken == '@set'): return self.result_set() elif (self.currentToken == "{"): # Parens s = self.query_struct() if (self.nextToken <> "}"): raise (ValueError) else: self.fetch_token() return s else: t = self.term() return self.defaultClause(t)
def tree_to_q (ast): if ast.type == 'op': myrpnRpnOp = z3950.RpnRpnOp () myrpnRpnOp.rpn1 = tree_to_q(ast.children[0]) myrpnRpnOp.rpn2 = tree_to_q(ast.children[1]) op = ast.leaf.lower () if op == 'not': op = 'and-not' # CCL spec of 'not' vs. Z39.50 spec of 'and-not' myrpnRpnOp.op = (op, None) return ('rpnRpnOp', myrpnRpnOp) elif ast.type == 'relop': # XXX but e.g. LC (http://lcweb.loc.gov/z3950/lcserver.html) # doesn't support other relation attributes, either. try: relattr = relop_to_attrib [ast.leaf] except(KeyError): # should never happen, how could we have lexed it? raise UnimplError (ast.leaf) def make_aelt (qual): val = ('numeric', qual [1]) return z3950.AttributeElement (attributeType = qual[0], attributeValue = val) apt = z3950.AttributesPlusTerm () quallist = ast.children.quallist if ast.leaf != '=': quallist.append ((2,relattr)) # 2 is relation attribute # see http://www.loc.gov/z3950/agency/markup/13.html ATR.1.1 apt.attributes = map (make_aelt, quallist) apt.term = ('general', ast.children.val) # XXX update for V3? return ('op', ('attrTerm', apt)) elif ast.type == 'set': return ('op', ('resultSet', ast.leaf)) raise UnimplError("Bad ast type " + str(ast.type))
def defaultClause(self, t): # Assign a default clause: anywhere = clause = z3950.AttributesPlusTerm() attrs = [(oids.Z3950_ATTRS_BIB1, 1, 1016), (oids.Z3950_ATTRS_BIB1, 2, 3)] clause.attributes = [make_attr(*e) for e in attrs] clause.term = t return ('op', ('attrTerm', clause))
def toRPN(self, top=None): if not top: top = self if (self.relation.value in ['any', 'all']): # Need to split this into and/or tree if (self.relation.value == 'any'): bool = " or " else: bool = " and " words = self.term.value.split() self.relation.value = '=' # Add 'word' relationModifier self.relation.modifiers.append(CModifierClause('cql.word')) # Create CQL, parse it, walk new tree idxrel = "%s %s" % (self.index.toCQL(), self.relation.toCQL()) text = [] for w in words: text.append('%s "%s"' % (idxrel, w)) cql = bool.join(text) tree = parse(cql) tree.prefixes = self.prefixes tree.parent = self.parent tree.config = self.config return tree.toRPN(top) else: # attributes, term # AttributeElement: attributeType, attributeValue # attributeValue ('numeric', n) or ('complex', struct) if (self.index.value == 'resultsetid'): return ('op', ('resultSet', self.term.value)) clause = z3950.AttributesPlusTerm() attrs = self.index.toRPN(top) if (self.term.value.isdigit()): self.relation.modifiers.append(CModifierClause('cql.number')) relattrs = self.relation.toRPN(top) attrs.update(relattrs) butes = [] for e in attrs.iteritems(): butes.append((e[0][0], e[0][1], e[1])) clause.attributes = [make_attr(*e) for e in butes] clause.term = self.term.toRPN(top) return ('op', ('attrTerm', clause))
def clause(self): if (self.is_boolean(self.nextToken) or not self.nextToken or self.nextToken.lower() == 'resultsetid' or self.nextToken == ")"): # Must be a resultset tok = self.currentToken self.fetch_token() return ('op', ('resultSet', tok)) elif (self.currentToken == '['): # List of attributes attrs = [] oidHash = oids.oids['Z3950']['ATTRS'] while (1): self.fetch_token() if (self.currentToken == ']'): break if (self.currentToken in oidHash): attrSet = oidHash[self.currentToken]['ov'] self.fetch_token() elif (self.currentToken[:8] == '1.2.840.'): attrSet = asn1.OidVal( list(map(int, self.currentToken.split('.')))) self.fetch_token() else: attrSet = None if (self.currentToken[-1] == ','): tok = self.currentToken[:-1] else: tok = self.currentToken if (tok.isdigit()): # 1 = foo atype = int(tok) self.fetch_token() if (self.currentToken == '='): # = foo self.fetch_token() if (self.currentToken[0] == '='): # =foo tok = self.currentToken[1:] else: tok = self.currentToken if (tok[-1] == ','): tok = tok[:-1] if (tok.isdigit()): val = int(tok) else: val = tok if (val[0] == "'" and val[-1] == "'"): val = val[1:-1] elif (tok[-1] == '='): #1= foo tok = tok[:-1] if (tok.isdigit()): atype = int(tok) self.fetch_token() if (self.currentToken[-1] == ","): tok = self.currentToken[:-1] else: tok = self.currentToken if (tok.isdigit()): val = int(self.currentToken) else: val = tok if (val[0] == "'" and val[-1] == "'"): val = val[1:-1] elif (tok.find('=') > -1): # 1=foo (atype, val) = self.currentToken.split('=') atype = int(atype) if (val[-1] == ","): val = val[:-1] if (val.isdigit()): val = int(val) elif (val[0] == "'" and val[-1] == "'"): val = val[1:-1] else: # ??? raise ValueError attrs.append([attrSet, atype, val]) else: # Check for named index if (self.currentToken.lower() in zconfig.bib1): attrs = [[ oids.Z3950_ATTRS_BIB1_ov, 1, zconfig.bib1[self.currentToken.lower()] ]] else: # Just pass through the name attrs = [[oids.Z3950_ATTRS_BIB1_ov, 1, self.currentToken]] self.fetch_token() # Check for relation tok = self.currentToken.upper() if (tok in relations): val = relations[tok] found = 0 for a in attrs: if (a[0] in [oids.Z3950_ATTRS_BIB1, None] and a[1] == 2): found = 1 a[2] = val break if (not found): attrs.append([None, 2, val]) self.fetch_token() elif (tok in geoRelations): val = geoRelations[tok] found = 0 for a in attrs: if (a[0] in [oids.Z3950_ATTRS_BIB1, oids.Z3950_ATTRS_GEO, None] and a[1] == 2): found = 1 a[2] = val break if (not found): attrs.append([oids.Z3950_ATTRS_GEO, 2, val]) self.fetch_token() if (self.currentToken.find(' ')): # Already quoted term = self.currentToken else: # Accumulate term = [] while (self.currentToken and not self.is_boolean(self.currentToken) and self.currentToken.lower() != 'resultsetid'): term.append(self.currenToken) term = ' '.join(term) self.fetch_token() # Phew. Now build AttributesPlusTerm clause = z3950.AttributesPlusTerm() clause.attributes = [make_attr(*e) for e in attrs] clause.term = ('general', term) return ('op', ('attrTerm', clause))