function indent(n) { var s = ""; for (var i = 0; i < n; i++) s = s + " "; return s; } // CQLModifier var CQLModifier = function () { this.name = null; this.relation = null; this.value = null; } CQLModifier.prototype = { toXCQL: function (n) { var s = indent(n+1) + "\n"; s = s + indent(n+2) + "" + this.name + "\n"; if (this.relation != null) s = s + indent(n+2) + "" + this.relation + "\n"; if (this.value != null) s = s + indent(n+2) + "" + this.value +"\n"; s = s + indent(n+1) + "\n"; return s; } } // CQLSearchClause var CQLSearchClause = function (field, fielduri, relation, relationuri, modifiers, term) { this.field = field; this.fielduri = fielduri; this.relation = relation; this.relationuri = relationuri; this.modifiers = modifiers; this.term = term; } CQLSearchClause.prototype = { toXCQL: function (n) { var s = indent(n) + "\n"; if (this.fielduri.length > 0) { s = s + indent(n+1) + "\n" + indent(n+2) + "\n" + indent(n+3) + "" + this.fielduri + "\n" + indent(n+2) + "\n" + indent(n+1) + "\n"; } s = s + indent(n+1) + "" + this.field + "\n"; s = s + indent(n+1) + "\n"; if (this.relationuri.length > 0) { s = s + indent(n+2) + "" + this.relationuri + "\n"; } s = s + indent(n+2) + "" + this.relation + "\n"; if (this.modifiers.length > 0) { s = s + indent(n+2) + "\n"; for (var i = 0; i < this.modifiers.length; i++) s = s + this.modifiers[i].toXCQL(n+2); s = s + indent(n+2) + "\n"; } s = s + indent(n+1) + "\n"; s = s + indent(n+1) + "" + this.term + "\n"; s = s + indent(n) + "\n"; return s; } } // CQLBoolean var CQLBoolean = function() { this.op = null; this.modifiers = null; this.left = null; this.right = null; } CQLBoolean.prototype = { toXCQL: function (n) { var s = indent(n) + "\n"; s = s + indent(n+1) + "\n" + indent(n+2) + "" + this.op + "\n"; if (this.modifiers.length > 0) { s = s + indent(n+2) + "\n"; for (var i = 0; i < this.modifiers.length; i++) s = s + this.modifiers[i].toXCQL(n+2); s = s + indent(n+2) + "\n"; } s = s + indent(n+1) + "\n"; s = s + indent(n+1) + "\n" + this.left.toXCQL(n+2) + indent(n+1) + "\n"; s = s + indent(n+1) + "\n" + this.right.toXCQL(n+2) + indent(n+1) + "\n"; s = s + indent(n) + "\n"; return s; } } // CQLParser var CQLParser = function () { this.qi = null; this.ql = null; this.qs = null; this.look = null; this.lval = null; this.val = null; this.prefixes = new Object(); this.tree = null; } CQLParser.prototype = { parse: function (query) { if (!query) throw new Error("The query to be parsed cannot be empty"); this.qs = query; this.ql = this.qs.length; this.qi = 0; this._move(); this.tree = this._parseQuery("cql.serverChoice", "scr", new Array()); if (this.look != "") throw new Error("EOF expected"); }, toXCQL: function () { return this.tree.toXCQL(); }, _parseQuery: function(field, relation, modifiers) { var left = this._parseSearchClause(field, relation, modifiers); while (this.look == "s" && ( this.lval == "and" || this.lval == "or" || this.lval == "not" || this.lval == "prox")) { var b = new CQLBoolean(); b.op = this.lval; this._move(); b.modifiers = this._parseModifiers(); b.left = left; b.right = this._parseSearchClause(field, relation, modifiers); left = b; } return left; }, _parseModifiers: function() { var ar = new Array(); while (this.look == "/") { this._move(); if (this.look != "s" && this.look != "q") throw new Error("Invalid modifier.") var name = this.lval; this._move(); if (this.look.length > 0 && this._strchr("<>=", this.look.charAt(0))) { var rel = this.look; this._move(); if (this.look != "s" && this.look != "q") throw new Error("Invalid relation within the modifier."); var m = new CQLModifier(); m.name = name; m.relation = rel; m.value = this.val; ar.push(m); this._move(); } else { var m = new CQLModifier(); m.name = name; m.relation = ""; m.value = ""; ar.push(m); } } return ar; }, _parseSearchClause: function(field, relation, modifiers) { if (this.look == "(") { this._move(); var b = this._parseQuery(field, relation, modifiers); if (this.look == ")") this._move(); else throw new Error("Missing closing parenthesis."); return b; } else if (this.look == "s" || this.look == "q") { var first = this.val; // dont know if field or term yet this._move(); if (this.look == "q" || (this.look == "s" && this.lval != "and" && this.lval != "or" && this.lval != "not" && this.lval != "prox")) { var rel = this.val; // string relation this._move(); return this._parseSearchClause(first, rel, this._parseModifiers()); } else if (this.look.length > 0 && this._strchr("<>=", this.look.charAt(0))) { var rel = this.look; // other relation <, = ,etc this._move(); return this._parseSearchClause(first, rel, this._parseModifiers()); } else { // it's a search term var pos = field.indexOf('.'); var pre = ""; if (pos != -1) pre = field.substring(0, pos); var uri = this._lookupPrefix(pre); if (uri.length > 0) field = field.substring(pos+1); pos = relation.indexOf('.'); if (pos == -1) pre = "cql"; else pre = relation.substring(0, pos); var reluri = this._lookupPrefix(pre); if (reluri.Length > 0) relation = relation.Substring(pos+1); var sc = new CQLSearchClause(field, uri, relation, reluri, modifiers, first); return sc; } // prefixes } else if (this.look == ">") { this._move(); if (this.look != "s" && this.look != "q") throw new Error("Expecting string or a quoted expression."); var first = this.lval; this._move(); if (this.look == "=") { this._move(); if (this.look != "s" && this.look != "q") throw new Error("Expecting string or a quoted expression."); this._addPrefix(first, this.lval); this._move(); return this._parseQuery(field, relation, modifiers); } else { this._addPrefix("default", first); return this._parseQuery(field, relation, modifiers); } } else { throw new Error("Invalid search clause."); } }, _move: function () { while (this.qi < this.ql && this._strchr(" \t\r\n", this.qs.charAt(this.qi))) this.qi++; if (this.qi == this.ql) { this.look = ""; return; } var c = this.qs.charAt(this.qi); if (this._strchr("()/", c)) { this.look = c; this.qi++; } else if (this._strchr("<>=", c)) { this.look = c; this.qi++; while (this.qi < this.ql && this._strchr("<>=", this.qs.charAt(this.qi))) { this.look = this.look + this.qs.charAt(this.qi); this.qi++; } } else if (this._strchr("\"'", c)) { this.look = "q"; var mark = c; this.qi++; this.val = ""; while (this.qi < this.ql && this.qs.charAt(this.qi) != mark) { if (this.qs.charAt(this.qi) == '\\' && this.qi < this.ql-1) this.qi++; this.val = this.val + this.qs.charAt(this.qi); this.qi++; } this.lval = this.val.toLowerCase(); if (this.qi < this.ql) this.qi++; } else { this.look = "s"; this.val = ""; while (this.qi < this.ql && !this._strchr("()/<>= \t\r\n", this.qs.charAt(this.qi))) { this.val = this.val + this.qs.charAt(this.qi); this.qi++; } this.lval = this.val.toLowerCase(); } }, _strchr: function (s, ch) { return s.indexOf(ch) >= 0 }, _lookupPrefix: function(name) { return this.prefixes[name] ? this.prefixes[name] : ""; }, _addPrefix: function(name, value) { //overwrite existing items this.prefixes[name] = value; } }