From: jakub Date: Wed, 14 May 2008 20:54:23 +0000 (+0200) Subject: Initial commit. Things seem to work fine. X-Git-Url: http://git.indexdata.com/?p=cql-js-moved-to-github.git;a=commitdiff_plain;h=0b0b8b4fae0f58ab263e03c1cffe2dd819a6d891 Initial commit. Things seem to work fine. --- 0b0b8b4fae0f58ab263e03c1cffe2dd819a6d891 diff --git a/cql.js b/cql.js new file mode 100644 index 0000000..ebd5e76 --- /dev/null +++ b/cql.js @@ -0,0 +1,318 @@ +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; + } +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..a456092 --- /dev/null +++ b/index.html @@ -0,0 +1,31 @@ + + + + + CQL parser + + +
+
+ Query: + +
+
+ XCQL: +
+
+ +
+ +