/* * * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at license/ESCIDOC.LICENSE * or http://www.escidoc.de/license. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at license/ESCIDOC.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006-2007 Fachinformationszentrum Karlsruhe Gesellschaft * für wissenschaftlich-technische Information mbH and Max-Planck- * Gesellschaft zur Förderung der Wissenschaft e.V. * All rights reserved. Use is subject to license terms. */ /** * JavaCC file * * The following grammar is realized: * * searchString = ( expression )+ * expression = searchClause ( booleanClause )? * searchClause = searchToken | "(" searchString ")" * booleanClause = ( AND | OR | NOT ) expression * searchToken = constant | phrase | escaped * escaped = \ special * special = "<" * phrase = QUOT all characters except quot | masked quot QUOT * specialCharacters= "=", WHITESPACE , "<", ">", "/", "(", ")", NEWLINE, QUOT * * TODO NiH: Revise until 31.08.2007; comment this in when finished: Revised by NiH: DD.MM.YYYY */ options{ JDK_VERSION = "1.5"; STATIC = false; UNICODE_INPUT = true; } PARSER_BEGIN(QueryParser) package de.mpg.escidoc.services.search.parser; import java.util.*; import java.io.*; /** * This class is generated by JavaCC. The most important method is * {@link #parse()}. * * Usage example: * QueryParser parser = new QueryParser("my query to parse"); * String cqlQuery = parser.parse(); * * To enrich the cql query with indexes use {@link #addCQLIndex()} before parsing. * * @author Miriam Doelle * */ public class QueryParser{ /** * Creates a new instance with the given string. */ public QueryParser(String query, String operator){ this (new StringReader(query)); this.booleanOperator = operator; } /** * Parses a query string, returning a CQL query string. * * @param query the query string to be parsed. * @throws ParseException if the parsing fails */ public String parse(String query)throws ParseException{ ReInit(new StringReader(query)); try { matchQuery(); return getCQLQuery(); } catch (ParseException tme){ // rethrow to include the original query: throw new ParseException("Cannot parse '"+query+"': "+tme.getMessage()); } catch (TokenMgrError tme){ throw new ParseException("Cannot parse '"+query+"': "+tme.getMessage()); } } /** * Parses a query, returning a CQL query string. * * @param query the query string to be parsed. * @throws ParseException if the parsing fails */ public String parse()throws ParseException{ try { matchQuery(); return getCQLQuery(); } catch (ParseException tme){ // rethrow to include the original query: throw new ParseException("Cannot parse query: "+tme.getMessage()); } catch (TokenMgrError tme){ throw new ParseException("Cannot parse query: "+tme.getMessage()); } } /** * The resulting cql query. */ private String cqlQuery = ""; /** * Boolean operator. */ private String booleanOperator = ""; /** * The list of cql indexes. */ private ListcqlIndexList = new ArrayList(); /** * Returns the created cql query. */ public String getCQLQuery(){ return cqlQuery; } /** * Adds a cql index to the list. */ public void addCQLIndex(String index){ cqlIndexList.add(index); } /** * Returns the list of cql indexes. */ public ListgetCQLIndexList(){ return cqlIndexList; } /** * Escape the special characters in a string. Here you can decide whether a special character * will be used as a logical operator or not. */ private String escapeSpecialCharacters( String escapeMe ) { String result = escapeMe.replace( "<", "\\<" ); result = result.replace( ">", "\\>" ); result = result.replace( "+", "\\+" ); result = result.replace( "-", "\\-" ); result = result.replace( "&", "\\&" ); result = result.replace( "|", "\\|" ); result = result.replace( "(", "\\(" ); result = result.replace( ")", "\\)" ); result = result.replace( "[", "\\[" ); result = result.replace( "]", "\\]" ); result = result.replace( "^", "\\^" ); result = result.replace( "~", "\\~" ); result = result.replace( "!", "\\!" ); result = result.replace( "{", "\\{" ); result = result.replace( "}", "\\}" ); return result; } /** * Helper to add cql indexes to a searchToken. */ private String makeCQLIdexedSearchToken(String searchToken){ searchToken = escapeSpecialCharacters( searchToken ); StringBuffer result = new StringBuffer(); switch (cqlIndexList.size()){ case 0:return searchToken; case 1:return result.append(cqlIndexList.get(0)).append(this.booleanOperator).append(searchToken).toString(); default :// enclose in brackets result.append("("); for (int i = 0; i0){ // add or operation between indexed searchTokens result.append(" or "); } result.append(index).append(booleanOperator).append(searchToken); } result.append(")"); return result.toString(); } } } PARSER_END(QueryParser) SKIP:{ " " | "\r" | "\t" } TOKEN:{ | | | | } void matchQuery():{ String s; } { s = searchString(){ cqlQuery = s; } } String searchString():{ String s; StringBuffer result = new StringBuffer(); } { (s = expression(){ if (result.length()>0){ result.append(" and ").append(s); } else { result.append(s); } } )+{ return result.toString(); } } String expression():{ String e1; String e2 = ""; StringBuffer result = new StringBuffer(); } { e1 = searchClause()[e2 = booleanClause()]{ result.append(e1); if (!e2.equals("")){ result.append(" ").append(e2); } return result.toString(); } } String searchClause():{ String s; } { (s = searchToken(){ return s; } | ("("s = searchString()")"){ return "("+s+")"; } ) } String searchToken():{ Token t; String s; } { (t = phrase()){ t.image = makeCQLIdexedSearchToken( t.image ); return t.image; } | (t = ){ t.image = makeCQLIdexedSearchToken( "\"" + t.image + "\""); return t.image; } } Token phrase():{ Token t; } { t = { return t; } } String booleanClause():{ String s; Token t; } { (t = | t = | t = )s = expression(){ return t.image.toLowerCase()+" "+s; } }