]> dev.renevier.net Git - syp.git/blob - openlayers/lib/OpenLayers/Format/Filter/v1.js
initial commit
[syp.git] / openlayers / lib / OpenLayers / Format / Filter / v1.js
1 /* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
2  * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
3  * full text of the license. */
4
5 /**
6  * @requires OpenLayers/Format/Filter.js
7  * @requires OpenLayers/Format/XML.js
8  */
9
10 /**
11  * Class: OpenLayers.Format.Filter.v1
12  * Superclass for Filter version 1 parsers.
13  *
14  * Inherits from:
15  *  - <OpenLayers.Format.XML>
16  */
17 OpenLayers.Format.Filter.v1 = OpenLayers.Class(OpenLayers.Format.XML, {
18     
19     /**
20      * Property: namespaces
21      * {Object} Mapping of namespace aliases to namespace URIs.
22      */
23     namespaces: {
24         ogc: "http://www.opengis.net/ogc",
25         gml: "http://www.opengis.net/gml",
26         xlink: "http://www.w3.org/1999/xlink",
27         xsi: "http://www.w3.org/2001/XMLSchema-instance"
28     },
29     
30     /**
31      * Property: defaultPrefix
32      */
33     defaultPrefix: "ogc",
34
35     /**
36      * Property: schemaLocation
37      * {String} Schema location for a particular minor version.
38      */
39     schemaLocation: null,
40     
41     /**
42      * Constructor: OpenLayers.Format.Filter.v1
43      * Instances of this class are not created directly.  Use the
44      *     <OpenLayers.Format.Filter> constructor instead.
45      *
46      * Parameters:
47      * options - {Object} An optional object whose properties will be set on
48      *     this instance.
49      */
50     initialize: function(options) {
51         OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
52     },
53     
54     /**
55      * Method: read
56      *
57      * Parameters:
58      * data - {DOMElement} A Filter document element.
59      *
60      * Returns:
61      * {<OpenLayers.Filter>} A filter object.
62      */
63     read: function(data) {
64         var obj = {};
65         this.readers.ogc["Filter"].apply(this, [data, obj]);
66         return obj.filter;
67     },
68     
69     /**
70      * Property: readers
71      * Contains public functions, grouped by namespace prefix, that will
72      *     be applied when a namespaced node is found matching the function
73      *     name.  The function will be applied in the scope of this parser
74      *     with two arguments: the node being read and a context object passed
75      *     from the parent.
76      */
77     readers: {
78         "ogc": {
79             "Filter": function(node, parent) {
80                 // Filters correspond to subclasses of OpenLayers.Filter.
81                 // Since they contain information we don't persist, we
82                 // create a temporary object and then pass on the filter
83                 // (ogc:Filter) to the parent obj.
84                 var obj = {
85                     fids: [],
86                     filters: []
87                 };
88                 this.readChildNodes(node, obj);
89                 if(obj.fids.length > 0) {
90                     parent.filter = new OpenLayers.Filter.FeatureId({
91                         fids: obj.fids
92                     });
93                 } else if(obj.filters.length > 0) {
94                     parent.filter = obj.filters[0];
95                 }
96             },
97             "FeatureId": function(node, obj) {
98                 var fid = node.getAttribute("fid");
99                 if(fid) {
100                     obj.fids.push(fid);
101                 }
102             },
103             "And": function(node, obj) {
104                 var filter = new OpenLayers.Filter.Logical({
105                     type: OpenLayers.Filter.Logical.AND
106                 });
107                 this.readChildNodes(node, filter);
108                 obj.filters.push(filter);
109             },
110             "Or": function(node, obj) {
111                 var filter = new OpenLayers.Filter.Logical({
112                     type: OpenLayers.Filter.Logical.OR
113                 });
114                 this.readChildNodes(node, filter);
115                 obj.filters.push(filter);
116             },
117             "Not": function(node, obj) {
118                 var filter = new OpenLayers.Filter.Logical({
119                     type: OpenLayers.Filter.Logical.NOT
120                 });
121                 this.readChildNodes(node, filter);
122                 obj.filters.push(filter);
123             },
124             "PropertyIsLessThan": function(node, obj) {
125                 var filter = new OpenLayers.Filter.Comparison({
126                     type: OpenLayers.Filter.Comparison.LESS_THAN
127                 });
128                 this.readChildNodes(node, filter);
129                 obj.filters.push(filter);
130             },
131             "PropertyIsGreaterThan": function(node, obj) {
132                 var filter = new OpenLayers.Filter.Comparison({
133                     type: OpenLayers.Filter.Comparison.GREATER_THAN
134                 });
135                 this.readChildNodes(node, filter);
136                 obj.filters.push(filter);
137             },
138             "PropertyIsLessThanOrEqualTo": function(node, obj) {
139                 var filter = new OpenLayers.Filter.Comparison({
140                     type: OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO
141                 });
142                 this.readChildNodes(node, filter);
143                 obj.filters.push(filter);
144             },
145             "PropertyIsGreaterThanOrEqualTo": function(node, obj) {
146                 var filter = new OpenLayers.Filter.Comparison({
147                     type: OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO
148                 });
149                 this.readChildNodes(node, filter);
150                 obj.filters.push(filter);
151             },
152             "PropertyIsBetween": function(node, obj) {
153                 var filter = new OpenLayers.Filter.Comparison({
154                     type: OpenLayers.Filter.Comparison.BETWEEN
155                 });
156                 this.readChildNodes(node, filter);
157                 obj.filters.push(filter);
158             },
159             "PropertyIsLike": function(node, obj) {
160                 var filter = new OpenLayers.Filter.Comparison({
161                     type: OpenLayers.Filter.Comparison.LIKE
162                 });
163                 this.readChildNodes(node, filter);
164                 var wildCard = node.getAttribute("wildCard");
165                 var singleChar = node.getAttribute("singleChar");
166                 var esc = node.getAttribute("escape");
167                 filter.value2regex(wildCard, singleChar, esc);
168                 obj.filters.push(filter);
169             },
170             "Literal": function(node, obj) {
171                 obj.value = OpenLayers.String.numericIf(
172                     this.getChildValue(node));
173             },
174             "PropertyName": function(node, filter) {
175                 filter.property = this.getChildValue(node);
176             },
177             "LowerBoundary": function(node, filter) {
178                 filter.lowerBoundary = OpenLayers.String.numericIf(
179                     this.readOgcExpression(node));
180             },
181             "UpperBoundary": function(node, filter) {
182                 filter.upperBoundary = OpenLayers.String.numericIf(
183                     this.readOgcExpression(node));
184             },
185             "Intersects": function(node, obj) {
186                 this.readSpatial(node, obj, OpenLayers.Filter.Spatial.INTERSECTS);
187             },
188             "Within": function(node, obj) {
189                 this.readSpatial(node, obj, OpenLayers.Filter.Spatial.WITHIN);
190             },
191             "Contains": function(node, obj) {
192                 this.readSpatial(node, obj, OpenLayers.Filter.Spatial.CONTAINS);
193             },
194             "DWithin": function(node, obj) {
195                 this.readSpatial(node, obj, OpenLayers.Filter.Spatial.DWITHIN);
196             },
197             "Distance": function(node, obj) {
198                 obj.distance = parseInt(this.getChildValue(node));
199                 obj.distanceUnits = node.getAttribute("units");
200             }
201         }
202     },
203     
204     /**
205      * Method: readSpatial
206      *
207      * Read a {<OpenLayers.Filter.Spatial>} filter.
208      * 
209      * Parameters:
210      * node - {DOMElement} A DOM element that contains an ogc:expression.
211      * obj - {Object} The target object.
212      * type - {String} One of the OpenLayers.Filter.Spatial.* constants.
213      *
214      * Returns:
215      * {<OpenLayers.Filter.Spatial>} The created filter.
216      */
217     readSpatial: function(node, obj, type) {
218         var filter = new OpenLayers.Filter.Spatial({
219             type: type
220         });
221         this.readChildNodes(node, filter);
222         filter.value = filter.components[0];
223         delete filter.components;
224         obj.filters.push(filter);
225     },
226
227     /**
228      * Method: readOgcExpression
229      * Limited support for OGC expressions.
230      *
231      * Parameters:
232      * node - {DOMElement} A DOM element that contains an ogc:expression.
233      *
234      * Returns:
235      * {String} A value to be used in a symbolizer.
236      */
237     readOgcExpression: function(node) {
238         var obj = {};
239         this.readChildNodes(node, obj);
240         var value = obj.value;
241         if(!value) {
242             value = this.getChildValue(node);
243         }
244         return value;
245     },
246
247     /**
248      * Method: write
249      *
250      * Parameters:
251      * filter - {<OpenLayers.Filter>} A filter object.
252      *
253      * Returns:
254      * {DOMElement} An ogc:Filter element.
255      */
256     write: function(filter) {
257         return this.writers.ogc["Filter"].apply(this, [filter]);
258     },
259     
260     /**
261      * Property: writers
262      * As a compliment to the readers property, this structure contains public
263      *     writing functions grouped by namespace alias and named like the
264      *     node names they produce.
265      */
266     writers: {
267         "ogc": {
268             "Filter": function(filter) {
269                 var node = this.createElementNSPlus("ogc:Filter");
270                 var sub = filter.CLASS_NAME.split(".").pop();
271                 if(sub == "FeatureId") {
272                     for(var i=0; i<filter.fids.length; ++i) {
273                         this.writeNode("FeatureId", filter.fids[i], node);
274                     }
275                 } else {
276                     this.writeNode(this.getFilterType(filter), filter, node);
277                 }
278                 return node;
279             },
280             "FeatureId": function(fid) {
281                 return this.createElementNSPlus("ogc:FeatureId", {
282                     attributes: {fid: fid}
283                 });
284             },
285             "And": function(filter) {
286                 var node = this.createElementNSPlus("ogc:And");
287                 var childFilter;
288                 for(var i=0; i<filter.filters.length; ++i) {
289                     childFilter = filter.filters[i];
290                     this.writeNode(
291                         this.getFilterType(childFilter), childFilter, node
292                     );
293                 }
294                 return node;
295             },
296             "Or": function(filter) {
297                 var node = this.createElementNSPlus("ogc:Or");
298                 var childFilter;
299                 for(var i=0; i<filter.filters.length; ++i) {
300                     childFilter = filter.filters[i];
301                     this.writeNode(
302                         this.getFilterType(childFilter), childFilter, node
303                     );
304                 }
305                 return node;
306             },
307             "Not": function(filter) {
308                 var node = this.createElementNSPlus("ogc:Not");
309                 var childFilter = filter.filters[0];
310                 this.writeNode(
311                     this.getFilterType(childFilter), childFilter, node
312                 );
313                 return node;
314             },
315             "PropertyIsLessThan": function(filter) {
316                 var node = this.createElementNSPlus("ogc:PropertyIsLessThan");
317                 // no ogc:expression handling for now
318                 this.writeNode("PropertyName", filter, node);
319                 this.writeNode("Literal", filter.value, node);                
320                 return node;
321             },
322             "PropertyIsGreaterThan": function(filter) {
323                 var node = this.createElementNSPlus("ogc:PropertyIsGreaterThan");
324                 // no ogc:expression handling for now
325                 this.writeNode("PropertyName", filter, node);
326                 this.writeNode("Literal", filter.value, node);
327                 return node;
328             },
329             "PropertyIsLessThanOrEqualTo": function(filter) {
330                 var node = this.createElementNSPlus("ogc:PropertyIsLessThanOrEqualTo");
331                 // no ogc:expression handling for now
332                 this.writeNode("PropertyName", filter, node);
333                 this.writeNode("Literal", filter.value, node);
334                 return node;
335             },
336             "PropertyIsGreaterThanOrEqualTo": function(filter) {
337                 var node = this.createElementNSPlus("ogc:PropertyIsGreaterThanOrEqualTo");
338                 // no ogc:expression handling for now
339                 this.writeNode("PropertyName", filter, node);
340                 this.writeNode("Literal", filter.value, node);
341                 return node;
342             },
343             "PropertyIsBetween": function(filter) {
344                 var node = this.createElementNSPlus("ogc:PropertyIsBetween");
345                 // no ogc:expression handling for now
346                 this.writeNode("PropertyName", filter, node);
347                 this.writeNode("LowerBoundary", filter, node);
348                 this.writeNode("UpperBoundary", filter, node);
349                 return node;
350             },
351             "PropertyIsLike": function(filter) {
352                 var node = this.createElementNSPlus("ogc:PropertyIsLike", {
353                     attributes: {
354                         wildCard: "*", singleChar: ".", escape: "!"
355                     }
356                 });
357                 // no ogc:expression handling for now
358                 this.writeNode("PropertyName", filter, node);
359                 // convert regex string to ogc string
360                 this.writeNode("Literal", filter.regex2value(), node);
361                 return node;
362             },
363             "PropertyName": function(filter) {
364                 // no ogc:expression handling for now
365                 return this.createElementNSPlus("ogc:PropertyName", {
366                     value: filter.property
367                 });
368             },
369             "Literal": function(value) {
370                 // no ogc:expression handling for now
371                 return this.createElementNSPlus("ogc:Literal", {
372                     value: value
373                 });
374             },
375             "LowerBoundary": function(filter) {
376                 // no ogc:expression handling for now
377                 var node = this.createElementNSPlus("ogc:LowerBoundary");
378                 this.writeNode("Literal", filter.lowerBoundary, node);
379                 return node;
380             },
381             "UpperBoundary": function(filter) {
382                 // no ogc:expression handling for now
383                 var node = this.createElementNSPlus("ogc:UpperBoundary");
384                 this.writeNode("Literal", filter.upperBoundary, node);
385                 return node;
386             },
387             "INTERSECTS": function(filter) {
388                 return this.writeSpatial(filter, "Intersects");
389             },
390             "WITHIN": function(filter) {
391                 return this.writeSpatial(filter, "Within");
392             },
393             "CONTAINS": function(filter) {
394                 return this.writeSpatial(filter, "Contains");
395             },
396             "DWITHIN": function(filter) {
397                 var node = this.writeSpatial(filter, "DWithin");
398                 this.writeNode("Distance", filter, node);
399                 return node;
400             },
401             "Distance": function(filter) {
402                 return this.createElementNSPlus("ogc:Distance", {
403                     attributes: {
404                         units: filter.distanceUnits
405                     },
406                     value: filter.distance
407                 });
408             }
409         }
410     },
411
412     /**
413      * Method: getFilterType
414      */
415     getFilterType: function(filter) {
416         var filterType = this.filterMap[filter.type];
417         if(!filterType) {
418             throw "Filter writing not supported for rule type: " + filter.type;
419         }
420         return filterType;
421     },
422     
423     /**
424      * Property: filterMap
425      * {Object} Contains a member for each filter type.  Values are node names
426      *     for corresponding OGC Filter child elements.
427      */
428     filterMap: {
429         "&&": "And",
430         "||": "Or",
431         "!": "Not",
432         "==": "PropertyIsEqualTo",
433         "!=": "PropertyIsNotEqualTo",
434         "<": "PropertyIsLessThan",
435         ">": "PropertyIsGreaterThan",
436         "<=": "PropertyIsLessThanOrEqualTo",
437         ">=": "PropertyIsGreaterThanOrEqualTo",
438         "..": "PropertyIsBetween",
439         "~": "PropertyIsLike",
440         "BBOX": "BBOX",
441         "DWITHIN": "DWITHIN",
442         "WITHIN": "WITHIN",
443         "CONTAINS": "CONTAINS",
444         "INTERSECTS": "INTERSECTS"
445     },
446
447     CLASS_NAME: "OpenLayers.Format.Filter.v1" 
448
449 });