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