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. */
6 * @requires OpenLayers/Format/XML.js
10 * Class: OpenLayers.Format.WMSGetFeatureInfo
11 * Class to read GetFeatureInfo responses from Web Mapping Services
14 * - <OpenLayers.Format.XML>
16 OpenLayers.Format.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Format.XML, {
19 * APIProperty: layerIdentifier
20 * {String} All xml nodes containing this search criteria will populate an
21 * internal array of layer nodes.
23 layerIdentifier: '_layer',
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.
30 featureIdentifier: '_feature',
34 * Compiled regular expressions for manipulating strings.
37 trimSpace: (/^\s*|\s*$/g),
38 removeSpace: (/\s*/g),
40 trimComma: (/\s*,\s*/g)
45 * {<OpenLayers.Format.GML>} internal GML format for parsing geometries
51 * Constructor: OpenLayers.Format.WMSGetFeatureInfo
52 * Create a new parser for WMS GetFeatureInfo responses
55 * options - {Object} An optional object whose properties will be set on
58 initialize: function(options) {
59 OpenLayers.Format.XML.prototype.initialize.apply(this, arguments);
60 OpenLayers.Util.extend(this, options);
61 this.options = options;
66 * Read WMS GetFeatureInfo data from a string, and return an array of features
69 * data - {String} or {DOMElement} data to read/parse.
72 * {Array(<OpenLayers.Feature.Vector>)} An array of features.
74 read: function(data) {
76 if(typeof data == "string") {
77 data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
79 var root = data.documentElement;
82 var read = this["read_" + root.nodeName];
84 result = read.call(this, root);
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);
98 * Method: read_msGMLOutput
99 * Parse msGMLOutput nodes.
102 * data - {DOMElement}
107 read_msGMLOutput: function(data) {
109 var layerNodes = this.getSiblingNodesByTagCriteria(data,
110 this.layerIdentifier);
112 for (var i=0, len=layerNodes.length; i<len; ++i) {
113 var node = layerNodes[i];
114 var layerName = node.nodeName;
116 layerName = layerName.split(':')[1];
118 var layerName = layerName.replace(this.layerIdentifier, '');
119 var featureNodes = this.getSiblingNodesByTagCriteria(node,
120 this.featureIdentifier);
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,
128 feature.type = layerName;
129 response.push(feature);
138 * Method: read_FeatureInfoResponse
139 * Parse FeatureInfoResponse nodes.
142 * data - {DOMElement}
147 read_FeatureInfoResponse: function(data) {
149 var featureNodes = this.getElementsByTagNameNS(data, '*',
152 for(var i=0, len=featureNodes.length;i<len;i++) {
153 var featureNode = featureNodes[i];
157 for(var j=0, jlen=featureNode.attributes.length; j<jlen; j++) {
158 var attribute = featureNode.attributes[j];
159 attributes[attribute.nodeName] = attribute.nodeValue;
163 new OpenLayers.Feature.Vector(geom, attributes, null)
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.
177 * node - {DOMElement} An xml node
178 * criteria - {String} Search string which will match some part of a tagName
181 * Array({DOMElement)) An array of sibling xml nodes
183 getSiblingNodesByTagCriteria: function(node, criteria){
185 var children, tagName, n, matchNodes, child;
186 if (node && node.hasChildNodes()) {
187 children = node.childNodes;
190 for(var k=0; k<n; k++){
192 while (child && child.nodeType != 1) {
193 child = child.nextSibling;
196 tagName = (child ? child.nodeName : '');
197 if (tagName.length > 0 && tagName.indexOf(criteria) > -1) {
200 matchNodes = this.getSiblingNodesByTagCriteria(
203 if(matchNodes.length > 0){
204 (nodes.length == 0) ?
205 nodes = matchNodes : nodes.push(matchNodes);
215 * Method: parseAttributes
218 * node - {<DOMElement>}
221 * {Object} An attributes object.
224 * Assumes that attributes are direct child xml nodes of the passed node
225 * and contain only a single text node.
227 parseAttributes: function(node){
229 if (node.nodeType == 1) {
230 var children = node.childNodes;
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;
254 * Method: parseGeometry
255 * Parse the geometry out of the node using Format.GML
258 * node - {<DOMElement>}
261 * {<OpenLayers.Geometry>} the geometry object
263 parseGeometry: function(node) {
264 // we need to use the old Format.GML parser since we do not know the
266 if (!this.gmlFormat) {
267 this.gmlFormat = new OpenLayers.Format.GML();
269 var feature = this.gmlFormat.parseFeature(node);
271 if (feature && feature.geometry) {
272 geometry = feature.geometry.clone();
278 CLASS_NAME: "OpenLayers.Format.WMSGetFeatureInfo"