3 for (var i = 0; i < n; i++)
8 var CQLModifier = function () {
14 CQLModifier.prototype = {
15 toXCQL: function (n) {
16 var s = indent(n+1) + "<modifier>\n";
17 s = s + indent(n+2) + "<name>" + this.name + "</name>\n";
18 if (this.relation != null)
20 + "<relation>" + this.relation + "</relation>\n";
21 if (this.value != null)
23 + "<value>" + this.value +"</value>\n";
24 s = s + indent(n+1) + "</modifier>\n";
29 //we ignore modifier relation symbol, for value-less modifiers
31 var value = this.value.length > 0 ? this.value : "true";
32 var s = '"'+this.name+'": "'+value+'"';
38 var CQLSearchClause = function (field, fielduri, relation, relationuri,
41 this.fielduri = fielduri;
42 this.relation = relation;
43 this.relationuri = relationuri;
44 this.modifiers = modifiers;
48 CQLSearchClause.prototype = {
49 toXCQL: function (n) {
50 var s = indent(n) + "<searchClause>\n";
51 if (this.fielduri.length > 0)
53 s = s + indent(n+1) + "<prefixes>\n" +
54 indent(n+2) + "<prefix>\n" +
55 indent(n+3) + "<identifier>" + this.fielduri +
57 indent(n+2) + "</prefix>\n" +
58 indent(n+1) + "</prefixes>\n";
60 s = s + indent(n+1) + "<index>" + this.field + "</index>\n";
61 s = s + indent(n+1) + "<relation>\n";
62 if (this.relationuri.length > 0) {
64 "<identifier>" + this.relationuri + "</identifier>\n";
66 s = s + indent(n+2) + "<value>" + this.relation + "</value>\n";
67 if (this.modifiers.length > 0) {
68 s = s + indent(n+2) + "<modifiers>\n";
69 for (var i = 0; i < this.modifiers.length; i++)
70 s = s + this.modifiers[i].toXCQL(n+2);
71 s = s + indent(n+2) + "</modifiers>\n";
73 s = s + indent(n+1) + "</relation>\n";
74 s = s + indent(n+1) + "<term>" + this.term + "</term>\n";
75 s = s + indent(n) + "</searchClause>\n";
80 var s = '{ "term": "'+this.term+'"';
81 if (this.field.length > 0 && this.field != 'cql.serverChoice')
82 s+= ', "field": "'+this.field+'"';
83 if (this.relation.length > 0 && this.relation != 'scr')
84 s+= ', "relation": "'+this._mapRelation(this.relation)+'"';
85 for (var i = 0; i < this.modifiers.length; i++) {
86 //since modifiers are mapped to keys, ignore the reserved ones
87 if (this.modifiers[i].name == "term"
88 ||this.modifiers[i].name == "field"
89 ||this.modifiers[i].name == "relation")
91 s += ', ' + this.modifiers[i].toFQ();
97 _mapRelation: function (rel) {
99 case "<" : return "lt";
100 case ">" : return "gt";
101 case "=" : return "eq";
102 case "<>" : return "ne";
103 case ">=" : return "ge";
104 case "<=" : return "le";
111 var CQLBoolean = function() {
113 this.modifiers = null;
118 CQLBoolean.prototype = {
119 toXCQL: function (n) {
120 var s = indent(n) + "<triple>\n";
121 s = s + indent(n+1) + "<boolean>\n" +
122 indent(n+2) + "<value>" + this.op + "</value>\n";
123 if (this.modifiers.length > 0) {
124 s = s + indent(n+2) + "<modifiers>\n";
125 for (var i = 0; i < this.modifiers.length; i++)
126 s = s + this.modifiers[i].toXCQL(n+2);
127 s = s + indent(n+2) + "</modifiers>\n";
129 s = s + indent(n+1) + "</boolean>\n";
130 s = s + indent(n+1) + "<leftOperand>\n" +
131 this.left.toXCQL(n+2) + indent(n+1) + "</leftOperand>\n";
133 s = s + indent(n+1) + "<rightOperand>\n" +
134 this.right.toXCQL(n+2) + indent(n+1) + "</rightOperand>\n";
135 s = s + indent(n) + "</triple>\n";
140 var s = ' { "op": "'+this.op+'"';
141 //proximity modifiers
142 for (var i = 0; i < this.modifiers.length; i++)
143 s += ', ' + this.modifiers[i].toFQ();
144 s += ', "s1": '+this.left.toFQ();
145 s += ', "s2": '+this.right.toFQ();
152 var CQLParser = function () {
159 this.prefixes = new Object();
163 CQLParser.prototype = {
164 parse: function (query) {
166 throw new Error("The query to be parsed cannot be empty");
169 this.ql = this.qs.length;
172 this.tree = this._parseQuery("cql.serverChoice", "scr", new Array());
174 throw new Error("EOF expected");
176 toXCQL: function () {
177 return this.tree.toXCQL();
180 return this.tree.toFQ();
182 _parseQuery: function(field, relation, modifiers) {
183 var left = this._parseSearchClause(field, relation, modifiers);
184 while (this.look == "s" && (
185 this.lval == "and" ||
187 this.lval == "not" ||
188 this.lval == "prox")) {
189 var b = new CQLBoolean();
192 b.modifiers = this._parseModifiers();
194 b.right = this._parseSearchClause(field, relation, modifiers);
199 _parseModifiers: function() {
200 var ar = new Array();
201 while (this.look == "/") {
203 if (this.look != "s" && this.look != "q")
204 throw new Error("Invalid modifier.")
206 var name = this.lval;
208 if (this.look.length > 0
209 && this._strchr("<>=", this.look.charAt(0))) {
212 if (this.look != "s" && this.look != "q")
213 throw new Error("Invalid relation within the modifier.");
215 var m = new CQLModifier();
222 var m = new CQLModifier();
231 _parseSearchClause: function(field, relation, modifiers) {
232 if (this.look == "(") {
234 var b = this._parseQuery(field, relation, modifiers);
235 if (this.look == ")")
238 throw new Error("Missing closing parenthesis.");
241 } else if (this.look == "s" || this.look == "q") {
242 var first = this.val; // dont know if field or term yet
244 if (this.look == "q" ||
246 this.lval != "and" &&
248 this.lval != "not" &&
249 this.lval != "prox")) {
250 var rel = this.val; // string relation
252 return this._parseSearchClause(first, rel,
253 this._parseModifiers());
254 } else if (this.look.length > 0
255 && this._strchr("<>=", this.look.charAt(0))) {
256 var rel = this.look; // other relation <, = ,etc
258 return this._parseSearchClause(first, rel,
259 this._parseModifiers());
261 // it's a search term
262 var pos = field.indexOf('.');
265 pre = field.substring(0, pos);
267 var uri = this._lookupPrefix(pre);
269 field = field.substring(pos+1);
271 pos = relation.indexOf('.');
275 pre = relation.substring(0, pos);
277 var reluri = this._lookupPrefix(pre);
278 if (reluri.Length > 0)
279 relation = relation.Substring(pos+1);
281 var sc = new CQLSearchClause(field,
290 } else if (this.look == ">") {
292 if (this.look != "s" && this.look != "q")
293 throw new Error("Expecting string or a quoted expression.");
295 var first = this.lval;
297 if (this.look == "=")
300 if (this.look != "s" && this.look != "q")
301 throw new Error("Expecting string or a quoted expression.");
303 this._addPrefix(first, this.lval);
305 return this._parseQuery(field, relation, modifiers);
307 this._addPrefix("default", first);
308 return this._parseQuery(field, relation, modifiers);
311 throw new Error("Invalid search clause.");
316 while (this.qi < this.ql
317 && this._strchr(" \t\r\n", this.qs.charAt(this.qi)))
319 if (this.qi == this.ql) {
323 var c = this.qs.charAt(this.qi);
324 if (this._strchr("()/", c)) {
327 } else if (this._strchr("<>=", c)) {
330 while (this.qi < this.ql
331 && this._strchr("<>=", this.qs.charAt(this.qi))) {
332 this.look = this.look + this.qs.charAt(this.qi);
335 } else if (this._strchr("\"'", c)) {
340 while (this.qi < this.ql
341 && this.qs.charAt(this.qi) != mark) {
342 if (this.qs.charAt(this.qi) == '\\'
343 && this.qi < this.ql-1)
345 this.val = this.val + this.qs.charAt(this.qi);
348 this.lval = this.val.toLowerCase();
349 if (this.qi < this.ql)
354 while (this.qi < this.ql
355 && !this._strchr("()/<>= \t\r\n", this.qs.charAt(this.qi))) {
356 this.val = this.val + this.qs.charAt(this.qi);
359 this.lval = this.val.toLowerCase();
362 _strchr: function (s, ch) {
363 return s.indexOf(ch) >= 0
365 _lookupPrefix: function(name) {
366 return this.prefixes[name] ? this.prefixes[name] : "";
368 _addPrefix: function(name, value) {
369 //overwrite existing items
370 this.prefixes[name] = value;