--- a/labs/openlayers/lib/OpenLayers/Format/Filter/v1.js +++ b/labs/openlayers/lib/OpenLayers/Format/Filter/v1.js @@ -1,1 +1,427 @@ - +/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the Clear BSD license. + * See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ +/** + * @requires OpenLayers/Format/Filter.js + * @requires OpenLayers/Format/XML.js + */ + +/** + * Class: OpenLayers.Format.Filter.v1 + * Superclass for Filter version 1 parsers. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.Filter.v1 = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + ogc: "http://www.opengis.net/ogc", + gml: "http://www.opengis.net/gml", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance" + }, + + /** + * Property: defaultPrefix + */ + defaultPrefix: "ogc", + + /** + * Property: schemaLocation + * {String} Schema location for a particular minor version. + */ + schemaLocation: null, + + /** + * Constructor: OpenLayers.Format.Filter.v1 + * Instances of this class are not created directly. Use the + * <OpenLayers.Format.Filter> constructor instead. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); + }, + + /** + * Method: read + * + * Parameters: + * data - {DOMElement} A Filter document element. + * + * Returns: + * {<OpenLayers.Filter>} A filter object. + */ + read: function(data) { + var obj = {}; + this.readers.ogc["Filter"].apply(this, [data, obj]); + return obj.filter; + }, + + /** + * Property: readers + * Contains public functions, grouped by namespace prefix, that will + * be applied when a namespaced node is found matching the function + * name. The function will be applied in the scope of this parser + * with two arguments: the node being read and a context object passed + * from the parent. + */ + readers: { + "ogc": { + "Filter": function(node, parent) { + // Filters correspond to subclasses of OpenLayers.Filter. + // Since they contain information we don't persist, we + // create a temporary object and then pass on the filter + // (ogc:Filter) to the parent obj. + var obj = { + fids: [], + filters: [] + }; + this.readChildNodes(node, obj); + if(obj.fids.length > 0) { + parent.filter = new OpenLayers.Filter.FeatureId({ + fids: obj.fids + }); + } else if(obj.filters.length > 0) { + parent.filter = obj.filters[0]; + } + }, + "FeatureId": function(node, obj) { + var fid = node.getAttribute("fid"); + if(fid) { + obj.fids.push(fid); + } + }, + "And": function(node, obj) { + var filter = new OpenLayers.Filter.Logical({ + type: OpenLayers.Filter.Logical.AND + }); + this.readChildNodes(node, filter); + obj.filters.push(filter); + }, + "Or": function(node, obj) { + var filter = new OpenLayers.Filter.Logical({ + type: OpenLayers.Filter.Logical.OR + }); + this.readChildNodes(node, filter); + obj.filters.push(filter); + }, + "Not": function(node, obj) { + var filter = new OpenLayers.Filter.Logical({ + type: OpenLayers.Filter.Logical.NOT + }); + this.readChildNodes(node, filter); + obj.filters.push(filter); + }, + "PropertyIsLessThan": function(node, obj) { + var filter = new OpenLayers.Filter.Comparison({ + type: OpenLayers.Filter.Comparison.LESS_THAN + }); + this.readChildNodes(node, filter); + obj.filters.push(filter); + }, + "PropertyIsGreaterThan": function(node, obj) { + var filter = new OpenLayers.Filter.Comparison({ + type: OpenLayers.Filter.Comparison.GREATER_THAN + }); + this.readChildNodes(node, filter); + obj.filters.push(filter); + }, + "PropertyIsLessThanOrEqualTo": function(node, obj) { + var filter = new OpenLayers.Filter.Comparison({ + type: OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO + }); + this.readChildNodes(node, filter); + obj.filters.push(filter); + }, + "PropertyIsGreaterThanOrEqualTo": function(node, obj) { + var filter = new OpenLayers.Filter.Comparison({ + type: OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO + }); + this.readChildNodes(node, filter); + obj.filters.push(filter); + }, + "PropertyIsBetween": function(node, obj) { + var filter = new OpenLayers.Filter.Comparison({ + type: OpenLayers.Filter.Comparison.BETWEEN + }); + this.readChildNodes(node, filter); + obj.filters.push(filter); + }, + "Literal": function(node, obj) { + obj.value = OpenLayers.String.numericIf( + this.getChildValue(node)); + }, + "PropertyName": function(node, filter) { + filter.property = this.getChildValue(node); + }, + "LowerBoundary": function(node, filter) { + filter.lowerBoundary = OpenLayers.String.numericIf( + this.readOgcExpression(node)); + }, + "UpperBoundary": function(node, filter) { + filter.upperBoundary = OpenLayers.String.numericIf( + this.readOgcExpression(node)); + }, + "Intersects": function(node, obj) { + this.readSpatial(node, obj, OpenLayers.Filter.Spatial.INTERSECTS); + }, + "Within": function(node, obj) { + this.readSpatial(node, obj, OpenLayers.Filter.Spatial.WITHIN); + }, + "Contains": function(node, obj) { + this.readSpatial(node, obj, OpenLayers.Filter.Spatial.CONTAINS); + }, + "DWithin": function(node, obj) { + this.readSpatial(node, obj, OpenLayers.Filter.Spatial.DWITHIN); + }, + "Distance": function(node, obj) { + obj.distance = parseInt(this.getChildValue(node)); + obj.distanceUnits = node.getAttribute("units"); + } + } + }, + + /** + * Method: readSpatial + * + * Read a {<OpenLayers.Filter.Spatial>} filter. + * + * Parameters: + * node - {DOMElement} A DOM element that contains an ogc:expression. + * obj - {Object} The target object. + * type - {String} One of the OpenLayers.Filter.Spatial.* constants. + * + * Returns: + * {<OpenLayers.Filter.Spatial>} The created filter. + */ + readSpatial: function(node, obj, type) { + var filter = new OpenLayers.Filter.Spatial({ + type: type + }); + this.readChildNodes(node, filter); + filter.value = filter.components[0]; + delete filter.components; + obj.filters.push(filter); + }, + + /** + * Method: readOgcExpression + * Limited support for OGC expressions. + * + * Parameters: + * node - {DOMElement} A DOM element that contains an ogc:expression. + * + * Returns: + * {String} A value to be used in a symbolizer. + */ + readOgcExpression: function(node) { + var obj = {}; + this.readChildNodes(node, obj); + var value = obj.value; + if(value === undefined) { + value = this.getChildValue(node); + } + return value; + }, + + /** + * Method: write + * + * Parameters: + * filter - {<OpenLayers.Filter>} A filter object. + * + * Returns: + * {DOMElement} An ogc:Filter element. + */ + write: function(filter) { + return this.writers.ogc["Filter"].apply(this, [filter]); + }, + + /** + * Property: writers + * As a compliment to the readers property, this structure contains public + * writing functions grouped by namespace alias and named like the + * node names they produce. + */ + writers: { + "ogc": { + "Filter": function(filter) { + var node = this.createElementNSPlus("ogc:Filter"); + var sub = filter.CLASS_NAME.split(".").pop(); + if(sub == "FeatureId") { + for(var i=0; i<filter.fids.length; ++i) { + this.writeNode("FeatureId", filter.fids[i], node); + } + } else { + this.writeNode(this.getFilterType(filter), filter, node); + } + return node; + }, + "FeatureId": function(fid) { + return this.createElementNSPlus("ogc:FeatureId", { + attributes: {fid: fid} + }); + }, + "And": function(filter) { + var node = this.createElementNSPlus("ogc:And"); + var childFilter; + for(var i=0; i<filter.filters.length; ++i) { + childFilter = filter.filters[i]; + this.writeNode( + this.getFilterType(childFilter), childFilter, node + ); + } + return node; + }, + "Or": function(filter) { + var node = this.createElementNSPlus("ogc:Or"); + var childFilter; + for(var i=0; i<filter.filters.length; ++i) { + childFilter = filter.filters[i]; + this.writeNode( + this.getFilterType(childFilter), childFilter, node + ); + } + return node; + }, + "Not": function(filter) { + var node = this.createElementNSPlus("ogc:Not"); + var childFilter = filter.filters[0]; + this.writeNode( + this.getFilterType(childFilter), childFilter, node + ); + return node; + }, + "PropertyIsLessThan": function(filter) { + var node = this.createElementNSPlus("ogc:PropertyIsLessThan"); + // no ogc:expression handling for now + this.writeNode("PropertyName", filter, node); + this.writeNode("Literal", filter.value, node); + return node; + }, + "PropertyIsGreaterThan": function(filter) { + var node = this.createElementNSPlus("ogc:PropertyIsGreaterThan"); + // no ogc:expression handling for now + this.writeNode("PropertyName", filter, node); + this.writeNode("Literal", filter.value, node); + return node; + }, + "PropertyIsLessThanOrEqualTo": function(filter) { + var node = this.createElementNSPlus("ogc:PropertyIsLessThanOrEqualTo"); + // no ogc:expression handling for now + this.writeNode("PropertyName", filter, node); + this.writeNode("Literal", filter.value, node); + return node; + }, + "PropertyIsGreaterThanOrEqualTo": function(filter) { + var node = this.createElementNSPlus("ogc:PropertyIsGreaterThanOrEqualTo"); + // no ogc:expression handling for now + this.writeNode("PropertyName", filter, node); + this.writeNode("Literal", filter.value, node); + return node; + }, + "PropertyIsBetween": function(filter) { + var node = this.createElementNSPlus("ogc:PropertyIsBetween"); + // no ogc:expression handling for now + this.writeNode("PropertyName", filter, node); + this.writeNode("LowerBoundary", filter, node); + this.writeNode("UpperBoundary", filter, node); + return node; + }, + "PropertyName": function(filter) { + // no ogc:expression handling for now + return this.createElementNSPlus("ogc:PropertyName", { + value: filter.property + }); + }, + "Literal": function(value) { + // no ogc:expression handling for now + return this.createElementNSPlus("ogc:Literal", { + value: value + }); + }, + "LowerBoundary": function(filter) { + // no ogc:expression handling for now + var node = this.createElementNSPlus("ogc:LowerBoundary"); + this.writeNode("Literal", filter.lowerBoundary, node); + return node; + }, + "UpperBoundary": function(filter) { + // no ogc:expression handling for now + var node = this.createElementNSPlus("ogc:UpperBoundary"); + this.writeNode("Literal", filter.upperBoundary, node); + return node; + }, + "INTERSECTS": function(filter) { + return this.writeSpatial(filter, "Intersects"); + }, + "WITHIN": function(filter) { + return this.writeSpatial(filter, "Within"); + }, + "CONTAINS": function(filter) { + return this.writeSpatial(filter, "Contains"); + }, + "DWITHIN": function(filter) { + var node = this.writeSpatial(filter, "DWithin"); + this.writeNode("Distance", filter, node); + return node; + }, + "Distance": function(filter) { + return this.createElementNSPlus("ogc:Distance", { + attributes: { + units: filter.distanceUnits + }, + value: filter.distance + }); + } + } + }, + + /** + * Method: getFilterType + */ + getFilterType: function(filter) { + var filterType = this.filterMap[filter.type]; + if(!filterType) { + throw "Filter writing not supported for rule type: " + filter.type; + } + return filterType; + }, + + /** + * Property: filterMap + * {Object} Contains a member for each filter type. Values are node names + * for corresponding OGC Filter child elements. + */ + filterMap: { + "&&": "And", + "||": "Or", + "!": "Not", + "==": "PropertyIsEqualTo", + "!=": "PropertyIsNotEqualTo", + "<": "PropertyIsLessThan", + ">": "PropertyIsGreaterThan", + "<=": "PropertyIsLessThanOrEqualTo", + ">=": "PropertyIsGreaterThanOrEqualTo", + "..": "PropertyIsBetween", + "~": "PropertyIsLike", + "BBOX": "BBOX", + "DWITHIN": "DWITHIN", + "WITHIN": "WITHIN", + "CONTAINS": "CONTAINS", + "INTERSECTS": "INTERSECTS" + }, + + CLASS_NAME: "OpenLayers.Format.Filter.v1" + +}); +