]> dev.renevier.net Git - syp.git/blob - openlayers/lib/OpenLayers/Format/WMSGetFeatureInfo.js
initial commit
[syp.git] / openlayers / lib / OpenLayers / Format / WMSGetFeatureInfo.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/XML.js
7  */
8
9 /**
10  * Class: OpenLayers.Format.WMSGetFeatureInfo
11  * Class to read GetFeatureInfo responses from Web Mapping Services
12  *
13  * Inherits from:
14  *  - <OpenLayers.Format.XML>
15  */
16 OpenLayers.Format.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Format.XML, {
17
18     /**
19      * APIProperty: layerIdentifier
20      * {String} All xml nodes containing this search criteria will populate an
21      *     internal array of layer nodes.
22      */ 
23     layerIdentifier: '_layer',
24
25     /**
26      * APIProperty: featureIdentifier
27      * {String} All xml nodes containing this search criteria will populate an 
28      *     internal array of feature nodes for each layer node found.
29      */
30     featureIdentifier: '_feature',
31
32     /**
33      * Property: regExes
34      * Compiled regular expressions for manipulating strings.
35      */
36     regExes: {
37         trimSpace: (/^\s*|\s*$/g),
38         removeSpace: (/\s*/g),
39         splitSpace: (/\s+/),
40         trimComma: (/\s*,\s*/g)
41     },
42
43     /**
44      * Property: gmlFormat
45      * {<OpenLayers.Format.GML>} internal GML format for parsing geometries
46      *     in msGMLOutput
47      */
48     gmlFormat: null,
49
50     /**
51      * Constructor: OpenLayers.Format.WMSGetFeatureInfo
52      * Create a new parser for WMS GetFeatureInfo responses
53      *
54      * Parameters:
55      * options - {Object} An optional object whose properties will be set on
56      *     this instance.
57      */
58     initialize: function(options) {
59         OpenLayers.Format.XML.prototype.initialize.apply(this, arguments);
60         OpenLayers.Util.extend(this, options);
61         this.options = options;
62     },
63
64     /**
65      * APIMethod: read
66      * Read WMS GetFeatureInfo data from a string, and return an array of features
67      *
68      * Parameters:
69      * data - {String} or {DOMElement} data to read/parse.
70      *
71      * Returns:
72      * {Array(<OpenLayers.Feature.Vector>)} An array of features.
73      */
74     read: function(data) {
75         var result;
76         if(typeof data == "string") {
77             data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
78         }
79         var root = data.documentElement;
80         if(root) {
81             var scope = this;
82             var read = this["read_" + root.nodeName];
83             if(read) {
84                 result = read.call(this, root);
85             } else {
86                 // fall-back to GML since this is a common output format for WMS
87                 // GetFeatureInfo responses
88                 result = new OpenLayers.Format.GML((this.options ? this.options : {})).read(data);
89             }
90         } else {
91             result = data;
92         }
93         return result;
94     },
95     
96     
97     /**
98      * Method: read_msGMLOutput
99      * Parse msGMLOutput nodes.
100      *
101      * Parameters:
102      * data - {DOMElement}
103      *
104      * Returns:
105      * {Array}
106      */
107     read_msGMLOutput: function(data) {
108         var response = [];
109         var layerNodes = this.getSiblingNodesByTagCriteria(data,
110             this.layerIdentifier);
111         if (layerNodes) {
112             for (var i=0, len=layerNodes.length; i<len; ++i) {
113                 var node = layerNodes[i];
114                 var layerName = node.nodeName;
115                 if (node.prefix) {
116                     layerName = layerName.split(':')[1];
117                 }
118                 var layerName = layerName.replace(this.layerIdentifier, '');
119                 var featureNodes = this.getSiblingNodesByTagCriteria(node, 
120                     this.featureIdentifier);
121                 if (featureNodes) {
122                     for (var j = 0; j < featureNodes.length; j++) {
123                         var featureNode = featureNodes[j];
124                         var geom = this.parseGeometry(featureNode);
125                         var attributes = this.parseAttributes(featureNode);
126                         var feature = new OpenLayers.Feature.Vector(geom, 
127                             attributes, null);
128                         feature.type = layerName;
129                         response.push(feature);
130                     }
131                 }
132             }
133         }
134         return response;
135     },
136     
137     /**
138      * Method: read_FeatureInfoResponse
139      * Parse FeatureInfoResponse nodes.
140      *
141      * Parameters:
142      * data - {DOMElement}
143      *
144      * Returns:
145      * {Array}
146      */
147     read_FeatureInfoResponse: function(data) {
148         var response = [];
149         var featureNodes = this.getElementsByTagNameNS(data, '*',
150             'FIELDS');
151
152         for(var i=0, len=featureNodes.length;i<len;i++) {
153             var featureNode = featureNodes[i];
154             var geom = null;
155
156             var attributes = {};
157             for(var j=0, jlen=featureNode.attributes.length; j<jlen; j++) {
158                 var attribute = featureNode.attributes[j];
159                 attributes[attribute.nodeName] = attribute.nodeValue;
160             }
161
162             response.push(
163                 new OpenLayers.Feature.Vector(geom, attributes, null)
164             );
165         }
166         return response;
167     },
168
169     /**
170      * Method: getSiblingNodesByTagCriteria
171      * Recursively searches passed xml node and all it's descendant levels for 
172      *     nodes whose tagName contains the passed search string. This returns an 
173      *     array of all sibling nodes which match the criteria from the highest 
174      *     hierarchial level from which a match is found.
175      * 
176      * Parameters:
177      * node - {DOMElement} An xml node
178      * criteria - {String} Search string which will match some part of a tagName 
179      *                                       
180      * Returns:
181      * Array({DOMElement)) An array of sibling xml nodes
182      */                
183     getSiblingNodesByTagCriteria: function(node, criteria){
184         var nodes = [];
185         var children, tagName, n, matchNodes, child;
186         if (node && node.hasChildNodes()) {
187             children = node.childNodes;
188             n = children.length;
189
190             for(var k=0; k<n; k++){
191                 child = children[k];
192                 while (child && child.nodeType != 1) {
193                     child = child.nextSibling;
194                     k++;
195                 }
196                 tagName = (child ? child.nodeName : '');
197                 if (tagName.length > 0 && tagName.indexOf(criteria) > -1) {
198                     nodes.push(child);
199                 } else {
200                     matchNodes = this.getSiblingNodesByTagCriteria(
201                         child, criteria);
202
203                     if(matchNodes.length > 0){
204                         (nodes.length == 0) ? 
205                             nodes = matchNodes : nodes.push(matchNodes);
206                     }
207                 }
208             }
209
210         }
211         return nodes;
212     },
213
214     /**
215      * Method: parseAttributes
216      *
217      * Parameters:
218      * node - {<DOMElement>}
219      *
220      * Returns:
221      * {Object} An attributes object.
222      * 
223      * Notes:
224      * Assumes that attributes are direct child xml nodes of the passed node
225      * and contain only a single text node. 
226      */    
227     parseAttributes: function(node){
228         var attributes = {};
229         if (node.nodeType == 1) {
230             var children = node.childNodes;
231             n = children.length;
232             for (var i = 0; i < n; ++i) {
233                 var child = children[i];
234                 if (child.nodeType == 1) {
235                     var grandchildren = child.childNodes;
236                     if (grandchildren.length == 1) {
237                         var grandchild = grandchildren[0];
238                         if (grandchild.nodeType == 3 ||
239                             grandchild.nodeType == 4) {
240                             var name = (child.prefix) ? 
241                                 child.nodeName.split(":")[1] : child.nodeName;
242                             var value = grandchild.nodeValue.replace(
243                                 this.regExes.trimSpace, "");
244                             attributes[name] = value;
245                         }
246                     }
247                 }
248             }
249         }
250         return attributes;
251     },
252
253     /**
254      * Method: parseGeometry
255      * Parse the geometry out of the node using Format.GML
256      *
257      * Parameters:
258      * node - {<DOMElement>}
259      *
260      * Returns:
261      * {<OpenLayers.Geometry>} the geometry object
262     */
263     parseGeometry: function(node) {
264         // we need to use the old Format.GML parser since we do not know the 
265         // geometry name
266         if (!this.gmlFormat) {
267             this.gmlFormat = new OpenLayers.Format.GML();
268         }
269         var feature = this.gmlFormat.parseFeature(node);
270         var geometry = null;
271         if (feature && feature.geometry) {
272             geometry = feature.geometry.clone();
273             feature.destroy();
274         }
275         return geometry;
276     },
277
278     CLASS_NAME: "OpenLayers.Format.WMSGetFeatureInfo"
279     
280 });