| | 1 | /* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license. |
|---|
| | 2 | * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt |
|---|
| | 3 | * for the full text of the license. */ |
|---|
| | 4 | |
|---|
| | 5 | /** |
|---|
| | 6 | * @requires OpenLayers/Format/XML.js |
|---|
| | 7 | * @requires OpenLayers/Style.js |
|---|
| | 8 | * @requires OpenLayers/Rule/FeatureId.js |
|---|
| | 9 | * @requires OpenLayers/Rule/Logical.js |
|---|
| | 10 | * @requires OpenLayers/Rule/Comparison.js |
|---|
| | 11 | * |
|---|
| | 12 | * Class: OpenLayers.Format.SLD |
|---|
| | 13 | * Read/Wite SLD. Create a new instance with the <OpenLayers.Format.SLD> |
|---|
| | 14 | * constructor. |
|---|
| | 15 | * |
|---|
| | 16 | * Inherits from: |
|---|
| | 17 | * - <OpenLayers.Format.XML> |
|---|
| | 18 | */ |
|---|
| | 19 | OpenLayers.Format.SLD = OpenLayers.Class(OpenLayers.Format.XML, { |
|---|
| | 20 | |
|---|
| | 21 | /** |
|---|
| | 22 | * APIProperty: sldns |
|---|
| | 23 | * Namespace used for sld. |
|---|
| | 24 | */ |
|---|
| | 25 | sldns: "http://www.opengis.net/sld", |
|---|
| | 26 | |
|---|
| | 27 | /** |
|---|
| | 28 | * APIProperty: ogcns |
|---|
| | 29 | * Namespace used for ogc. |
|---|
| | 30 | */ |
|---|
| | 31 | ogcns: "http://www.opengis.net/ogc", |
|---|
| | 32 | |
|---|
| | 33 | /** |
|---|
| | 34 | * APIProperty: gmlns |
|---|
| | 35 | * Namespace used for gml. |
|---|
| | 36 | */ |
|---|
| | 37 | gmlns: "http://www.opengis.net/gml", |
|---|
| | 38 | |
|---|
| | 39 | /** |
|---|
| | 40 | * APIProperty: defaultStyle. |
|---|
| | 41 | * {Object} |
|---|
| | 42 | * A simple style, preset with the SLD defaults. |
|---|
| | 43 | */ |
|---|
| | 44 | defaultStyle: { |
|---|
| | 45 | fillColor: "#808080", |
|---|
| | 46 | fillOpacity: 1, |
|---|
| | 47 | strokeColor: "#000000", |
|---|
| | 48 | strokeOpacity: 1, |
|---|
| | 49 | strokeWidth: 1, |
|---|
| | 50 | pointRadius: 6 |
|---|
| | 51 | }, |
|---|
| | 52 | |
|---|
| | 53 | /** |
|---|
| | 54 | * Property: withNamedLayer |
|---|
| | 55 | * {Boolean} Option set during <read>. Default is false. If true, the |
|---|
| | 56 | * return from <read> will be a two item array ([styles, namedLayer]): |
|---|
| | 57 | * - styles - {Array(<OpenLayers.Style>)} |
|---|
| | 58 | * - namedLayer - {Object} hash of userStyles, keyed by |
|---|
| | 59 | * sld:NamedLayer/Name, each again keyed by |
|---|
| | 60 | * sld:UserStyle/Name. Each entry of namedLayer is a |
|---|
| | 61 | * StyleMap for a layer, with the userStyle names as style |
|---|
| | 62 | * keys. |
|---|
| | 63 | */ |
|---|
| | 64 | withNamedLayer: false, |
|---|
| | 65 | |
|---|
| | 66 | /** |
|---|
| | 67 | * APIProperty: overrideDefaultStyleKey |
|---|
| | 68 | * {Boolean} Store styles with key of "default" instead of user style name. |
|---|
| | 69 | * If true, userStyles with sld:IsDefault==1 will be stored with |
|---|
| | 70 | * key "default" instead of the sld:UserStyle/Name in the style map. |
|---|
| | 71 | * Default is true. |
|---|
| | 72 | */ |
|---|
| | 73 | overrideDefaultStyleKey: true, |
|---|
| | 74 | |
|---|
| | 75 | |
|---|
| | 76 | /** |
|---|
| | 77 | * Constructor: OpenLayers.Format.SLD |
|---|
| | 78 | * Create a new parser for SLD. |
|---|
| | 79 | * |
|---|
| | 80 | * Parameters: |
|---|
| | 81 | * options - {Object} An optional object whose properties will be set on |
|---|
| | 82 | * this instance. |
|---|
| | 83 | */ |
|---|
| | 84 | initialize: function(options) { |
|---|
| | 85 | OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); |
|---|
| | 86 | }, |
|---|
| | 87 | |
|---|
| | 88 | /** |
|---|
| | 89 | * APIMethod: read |
|---|
| | 90 | * Read data from a string, and return a list of features. |
|---|
| | 91 | * |
|---|
| | 92 | * Parameters: |
|---|
| | 93 | * data - {String} or {XMLNode} data to read/parse. |
|---|
| | 94 | * options - {Object} Object that sets optional read configuration values. |
|---|
| | 95 | * These include <withNamedLayer>, and <overrideDefaultStyleKey>. |
|---|
| | 96 | * |
|---|
| | 97 | * Returns: |
|---|
| | 98 | * {Array(<OpenLayers.Style>)} List of styles. If <withNamedLayer> is |
|---|
| | 99 | * true, return will be a two item array where the first item is |
|---|
| | 100 | * a list of styles and the second is the namedLayer object. |
|---|
| | 101 | */ |
|---|
| | 102 | read: function(data, options) { |
|---|
| | 103 | if (typeof data == "string") { |
|---|
| | 104 | data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); |
|---|
| | 105 | } |
|---|
| | 106 | |
|---|
| | 107 | OpenLayers.Util.applyDefaults(options, { |
|---|
| | 108 | withNamedLayer: false, |
|---|
| | 109 | overrideDefaultStyleKey: true |
|---|
| | 110 | }); |
|---|
| | 111 | |
|---|
| | 112 | var userStyles = this.getElementsByTagNameNS( |
|---|
| | 113 | data, this.sldns, "UserStyle" |
|---|
| | 114 | ); |
|---|
| | 115 | var result = {}; |
|---|
| | 116 | if (userStyles.length > 0) { |
|---|
| | 117 | var namedLayer = {}; |
|---|
| | 118 | var styles = new Array(userStyles.length); |
|---|
| | 119 | var styleName, userStyle, style; |
|---|
| | 120 | for (var i=0; i<userStyles.length; i++) { |
|---|
| | 121 | userStyle = userStyles[i]; |
|---|
| | 122 | styleName = this.parseProperty( |
|---|
| | 123 | userStyle, this.sldns, "Name" |
|---|
| | 124 | ); |
|---|
| | 125 | style = this.parseUserStyle(userStyle, styleName); |
|---|
| | 126 | |
|---|
| | 127 | if (options.overrideDefaultStyleKey && style.isDefault == true) { |
|---|
| | 128 | styleName = "default"; |
|---|
| | 129 | } |
|---|
| | 130 | |
|---|
| | 131 | if (!namedLayer[style.layerName]) { |
|---|
| | 132 | namedLayer[style.layerName] = {}; |
|---|
| | 133 | } |
|---|
| | 134 | namedLayer[style.layerName][styleName] = style; |
|---|
| | 135 | styles[i] = style; |
|---|
| | 136 | } |
|---|
| | 137 | result = options.withNamedLayer ? [styles, namedLayer] : styles; |
|---|
| | 138 | } |
|---|
| | 139 | return result; |
|---|
| | 140 | }, |
|---|
| | 141 | |
|---|
| | 142 | /** |
|---|
| | 143 | * Method: parseUserStyle |
|---|
| | 144 | * parses a sld userStyle for rules |
|---|
| | 145 | * |
|---|
| | 146 | * Parameters: |
|---|
| | 147 | * xmlNode - {DOMElement} xml node to read the style from |
|---|
| | 148 | * name - {String} name of the style |
|---|
| | 149 | * |
|---|
| | 150 | * Returns: |
|---|
| | 151 | * {<OpenLayers.Style>} |
|---|
| | 152 | */ |
|---|
| | 153 | parseUserStyle: function(xmlNode, name) { |
|---|
| | 154 | var userStyle = new OpenLayers.Style(this.defaultStyle, {name: name}); |
|---|
| | 155 | |
|---|
| | 156 | userStyle.isDefault = ( |
|---|
| | 157 | this.parseProperty(xmlNode, this.sldns, "IsDefault") == 1 |
|---|
| | 158 | ); |
|---|
| | 159 | |
|---|
| | 160 | // get the name of the layer if we have a NamedLayer |
|---|
| | 161 | var namedLayerNode = xmlNode.parentNode; |
|---|
| | 162 | var nameNodes = this.getElementsByTagNameNS( |
|---|
| | 163 | namedLayerNode, this.sldns, "Name" |
|---|
| | 164 | ); |
|---|
| | 165 | if (namedLayerNode.nodeName.indexOf("NamedLayer") != -1 && |
|---|
| | 166 | nameNodes && |
|---|
| | 167 | nameNodes.length > 0 && |
|---|
| | 168 | nameNodes[0].parentNode == namedLayerNode) { |
|---|
| | 169 | userStyle.layerName = this.getChildValue(nameNodes[0]); |
|---|
| | 170 | } |
|---|
| | 171 | |
|---|
| | 172 | var ruleNodes = this.getElementsByTagNameNS( |
|---|
| | 173 | xmlNode, this.sldns, "Rule" |
|---|
| | 174 | ); |
|---|
| | 175 | // I don't think you really want to return [] here |
|---|
| | 176 | if (ruleNodes.length == 0) { return []; } |
|---|
| | 177 | |
|---|
| | 178 | var rules = userStyle.rules; |
|---|
| | 179 | var ruleName; |
|---|
| | 180 | for (var i=0; i<ruleNodes.length; i++) { |
|---|
| | 181 | ruleName = this.parseProperty(ruleNodes[i], this.sldns, "Name"); |
|---|
| | 182 | rules.push(this.parseRule(ruleNodes[i], ruleName)); |
|---|
| | 183 | } |
|---|
| | 184 | |
|---|
| | 185 | return userStyle; |
|---|
| | 186 | }, |
|---|
| | 187 | |
|---|
| | 188 | /** |
|---|
| | 189 | * Method: parseRule |
|---|
| | 190 | * This function is the core of the SLD parsing code in OpenLayers. |
|---|
| | 191 | * It creates the rule with its constraints and symbolizers. |
|---|
| | 192 | * |
|---|
| | 193 | * Parameters: |
|---|
| | 194 | * xmlNode - {<DOMElement>} |
|---|
| | 195 | * |
|---|
| | 196 | * Returns: |
|---|
| | 197 | * {Object} Hash of rule properties |
|---|
| | 198 | */ |
|---|
| | 199 | parseRule: function(xmlNode, name) { |
|---|
| | 200 | |
|---|
| | 201 | // FILTERS |
|---|
| | 202 | |
|---|
| | 203 | var filter = this.getElementsByTagNameNS(xmlNode, this.ogcns, "Filter"); |
|---|
| | 204 | if (filter && filter.length > 0) { |
|---|
| | 205 | var rule = this.parseFilter(filter[0]); |
|---|
| | 206 | } else { |
|---|
| | 207 | // rule applies to all features |
|---|
| | 208 | var rule = new OpenLayers.Rule(); |
|---|
| | 209 | } |
|---|
| | 210 | rule.name = name; |
|---|
| | 211 | |
|---|
| | 212 | // SCALE DENOMINATORS |
|---|
| | 213 | |
|---|
| | 214 | // MinScaleDenominator |
|---|
| | 215 | var minScale = this.getElementsByTagNameNS( |
|---|
| | 216 | xmlNode, this.sldns, "MinScaleDenominator" |
|---|
| | 217 | ); |
|---|
| | 218 | if (minScale && minScale.length > 0) { |
|---|
| | 219 | rule.minScale = parseFloat(this.getChildValue(minScale[0])); |
|---|
| | 220 | } |
|---|
| | 221 | |
|---|
| | 222 | // MaxScaleDenominator |
|---|
| | 223 | var maxScale = this.getElementsByTagNameNS( |
|---|
| | 224 | xmlNode, this.sldns, "MaxScaleDenominator" |
|---|
| | 225 | ); |
|---|
| | 226 | if (maxScale && maxScale.length > 0) { |
|---|
| | 227 | rule.maxScale = parseFloat(this.getChildValue(maxScale[0])); |
|---|
| | 228 | } |
|---|
| | 229 | |
|---|
| | 230 | // STYLES |
|---|
| | 231 | |
|---|
| | 232 | // walk through all symbolizers |
|---|
| | 233 | var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES; |
|---|
| | 234 | for (var s=0; s<prefixes.length; s++) { |
|---|
| | 235 | |
|---|
| | 236 | // symbolizer type |
|---|
| | 237 | var symbolizer = this.getElementsByTagNameNS( |
|---|
| | 238 | xmlNode, this.sldns, prefixes[s]+"Symbolizer" |
|---|
| | 239 | ); |
|---|
| | 240 | |
|---|
| | 241 | if (symbolizer && symbolizer.length > 0) { |
|---|
| | 242 | |
|---|
| | 243 | var style = {}; |
|---|
| | 244 | |
|---|
| | 245 | // externalGraphic |
|---|
| | 246 | var graphic = this.getElementsByTagNameNS( |
|---|
| | 247 | symbolizer[0], this.sldns, "Graphic" |
|---|
| | 248 | ); |
|---|
| | 249 | if (graphic && graphic.length > 0) { |
|---|
| | 250 | style.externalGraphic = this.parseProperty( |
|---|
| | 251 | graphic[0], this.sldns, "OnlineResource", "xlink:href" |
|---|
| | 252 | ); |
|---|
| | 253 | style.pointRadius = this.parseProperty( |
|---|
| | 254 | graphic[0], this.sldns, "Size" |
|---|
| | 255 | ); |
|---|
| | 256 | style.graphicOpacity = this.parseProperty( |
|---|
| | 257 | graphic[0], this.sldns, "Opacity" |
|---|
| | 258 | ); |
|---|
| | 259 | } |
|---|
| | 260 | |
|---|
| | 261 | // fill |
|---|
| | 262 | var fill = this.getElementsByTagNameNS( |
|---|
| | 263 | symbolizer[0], this.sldns, "Fill" |
|---|
| | 264 | ); |
|---|
| | 265 | if (fill && fill.length > 0) { |
|---|
| | 266 | style.fillColor = this.parseProperty( |
|---|
| | 267 | fill[0], this.sldns, "CssParameter", "name", "fill" |
|---|
| | 268 | ); |
|---|
| | 269 | style.fillOpacity = this.parseProperty( |
|---|
| | 270 | fill[0], this.sldns, "CssParameter", |
|---|
| | 271 | "name", "fill-opacity" |
|---|
| | 272 | ) || 1; |
|---|
| | 273 | } |
|---|
| | 274 | |
|---|
| | 275 | // stroke |
|---|
| | 276 | var stroke = this.getElementsByTagNameNS( |
|---|
| | 277 | symbolizer[0], this.sldns, "Stroke" |
|---|
| | 278 | ); |
|---|
| | 279 | if (stroke && stroke.length > 0) { |
|---|
| | 280 | style.strokeColor = this.parseProperty( |
|---|
| | 281 | stroke[0], this.sldns, "CssParameter", "name", "stroke" |
|---|
| | 282 | ); |
|---|
| | 283 | style.strokeOpacity = this.parseProperty( |
|---|
| | 284 | stroke[0], this.sldns, "CssParameter", |
|---|
| | 285 | "name", "stroke-opacity" |
|---|
| | 286 | ) || 1; |
|---|
| | 287 | style.strokeWidth = this.parseProperty( |
|---|
| | 288 | stroke[0], this.sldns, "CssParameter", |
|---|
| | 289 | "name", "stroke-width" |
|---|
| | 290 | ); |
|---|
| | 291 | style.strokeLinecap = this.parseProperty( |
|---|
| | 292 | stroke[0], this.sldns, "CssParameter", |
|---|
| | 293 | "name", "stroke-linecap" |
|---|
| | 294 | ); |
|---|
| | 295 | } |
|---|
| | 296 | |
|---|
| | 297 | // set the [point|line|polygon]Symbolizer property of the rule |
|---|
| | 298 | rule.symbolizer[prefixes[s]] = style; |
|---|
| | 299 | } |
|---|
| | 300 | } |
|---|
| | 301 | |
|---|
| | 302 | return rule; |
|---|
| | 303 | }, |
|---|
| | 304 | |
|---|
| | 305 | /** |
|---|
| | 306 | * Method: parseFilter |
|---|
| | 307 | * Parses ogc fiters. |
|---|
| | 308 | * |
|---|
| | 309 | * Parameters: |
|---|
| | 310 | * xmlNode - {<DOMElement>} |
|---|
| | 311 | * |
|---|
| | 312 | * Returns: |
|---|
| | 313 | * {<OpenLayers.Rule>} rule representing the filter |
|---|
| | 314 | */ |
|---|
| | 315 | parseFilter: function(xmlNode) { |
|---|
| | 316 | // ogc:FeatureId filter |
|---|
| | 317 | var filter = this.getNodeOrChildrenByTagName(xmlNode, "FeatureId"); |
|---|
| | 318 | if (filter) { |
|---|
| | 319 | var rule = new OpenLayers.Rule.FeatureId(); |
|---|
| | 320 | for (var i=0; i<filter.length; i++) { |
|---|
| | 321 | rule.fids.push(filter[i].getAttribute("fid")); |
|---|
| | 322 | } |
|---|
| | 323 | return rule; |
|---|
| | 324 | } |
|---|
| | 325 | |
|---|
| | 326 | // ogc:And filter |
|---|
| | 327 | filter = this.getNodeOrChildrenByTagName(xmlNode, "And"); |
|---|
| | 328 | if (filter) { |
|---|
| | 329 | var rule = new OpenLayers.Rule.Logical( |
|---|
| | 330 | {type: OpenLayers.Rule.Logical.AND}); |
|---|
| | 331 | var filters = filter[0].childNodes; |
|---|
| | 332 | for (var i=0; i<filters.length; i++) { |
|---|
| | 333 | if (filters[i].nodeType == 1) { |
|---|
| | 334 | rule.children.push(this.parseFilter(filters[i])); |
|---|
| | 335 | } |
|---|
| | 336 | } |
|---|
| | 337 | return rule; |
|---|
| | 338 | } |
|---|
| | 339 | |
|---|
| | 340 | // ogc:Or filter |
|---|
| | 341 | filter = this.getNodeOrChildrenByTagName(xmlNode, "Or"); |
|---|
| | 342 | if (filter) { |
|---|
| | 343 | var rule = new OpenLayers.Rule.Logical( |
|---|
| | 344 | {type: OpenLayers.Rule.Logical.OR}) |
|---|
| | 345 | var filters = filter[0].childNodes; |
|---|
| | 346 | for (var i=0; i<filters.length; i++) { |
|---|
| | 347 | if (filters[i].nodeType == 1) { |
|---|
| | 348 | rule.children.push(this.parseFilter(filters[i])); |
|---|
| | 349 | } |
|---|
| | 350 | } |
|---|
| | 351 | return rule; |
|---|
| | 352 | } |
|---|
| | 353 | |
|---|
| | 354 | // ogc:Not filter |
|---|
| | 355 | filter = this.getNodeOrChildrenByTagName(xmlNode, "Not"); |
|---|
| | 356 | if (filter) { |
|---|
| | 357 | var rule = new OpenLayers.Rule.Logical( |
|---|
| | 358 | {type: OpenLayers.Rule.Logical.NOT}); |
|---|
| | 359 | rule.children.push(this.parseFilter(filter[0])); |
|---|
| | 360 | return rule; |
|---|
| | 361 | } |
|---|
| | 362 | |
|---|
| | 363 | // Comparison filters |
|---|
| | 364 | for (var type in this.TYPES) { |
|---|
| | 365 | var filter = this.getNodeOrChildrenByTagName(xmlNode, type); |
|---|
| | 366 | if (filter) { |
|---|
| | 367 | filter = filter[0]; |
|---|
| | 368 | var rule = new OpenLayers.Rule.Comparison({ |
|---|
| | 369 | type: OpenLayers.Rule.Comparison[this.TYPES[type]], |
|---|
| | 370 | property: this.parseProperty( |
|---|
| | 371 | filter, this.ogcns, "PropertyName")}); |
|---|
| | 372 | // ogc:PropertyIsBetween |
|---|
| | 373 | if (this.TYPES[type] == "BETWEEN") { |
|---|
| | 374 | rule.lowerBoundary = this.parseProperty( |
|---|
| | 375 | filter, this.ogcns, "LowerBoundary"); |
|---|
| | 376 | rule.upperBoudary = this.parseProperty( |
|---|
| | 377 | filter, this.ogcns, "UpperBoundary"); |
|---|
| | 378 | } else { |
|---|
| | 379 | rule.value = this.parseProperty( |
|---|
| | 380 | filter, this.ogcns, "Literal"); |
|---|
| | 381 | // ogc:PropertyIsLike |
|---|
| | 382 | if (this.TYPES[type] == "LIKE") { |
|---|
| | 383 | var wildCard = filter.getAttribute("wildCard"); |
|---|
| | 384 | var singleChar = filter.getAttribute("singleChar"); |
|---|
| | 385 | var escape = filter.getAttribute("escape"); |
|---|
| | 386 | rule.value2regex(wildCard, singleChar, escape); |
|---|
| | 387 | } |
|---|
| | 388 | } |
|---|
| | 389 | return rule; |
|---|
| | 390 | } |
|---|
| | 391 | } |
|---|
| | 392 | |
|---|
| | 393 | // if we get here, the filter was empty |
|---|
| | 394 | return new OpenLayers.Rule(); |
|---|
| | 395 | }, |
|---|
| | 396 | |
|---|
| | 397 | /** |
|---|
| | 398 | * Method: getNodeOrChildrenByTagName |
|---|
| | 399 | * Convenience method to get a node or its child nodes, but only |
|---|
| | 400 | * those matching a tag name. |
|---|
| | 401 | * |
|---|
| | 402 | * Returns: |
|---|
| | 403 | * {Array(<DOMElement>)} or null if no matching content is found |
|---|
| | 404 | */ |
|---|
| | 405 | getNodeOrChildrenByTagName: function(xmlNode, tagName) { |
|---|
| | 406 | var nodeName = (xmlNode.prefix) ? |
|---|
| | 407 | xmlNode.nodeName.split(":")[1] : |
|---|
| | 408 | xmlNode.nodeName; |
|---|
| | 409 | |
|---|
| | 410 | if (nodeName == tagName) { |
|---|
| | 411 | return [xmlNode]; |
|---|
| | 412 | } else { |
|---|
| | 413 | var nodelist = this.getElementsByTagNameNS( |
|---|
| | 414 | xmlNode, this.ogcns, tagName); |
|---|
| | 415 | } |
|---|
| | 416 | |
|---|
| | 417 | // make a new list which only contains matching child nodes |
|---|
| | 418 | if (nodelist.length > 0) { |
|---|
| | 419 | var node; |
|---|
| | 420 | var list = []; |
|---|
| | 421 | for (var i=0; i<nodelist.length; i++) { |
|---|
| | 422 | node = nodelist[i]; |
|---|
| | 423 | if (node.parentNode == xmlNode) { |
|---|
| | 424 | list.push(node); |
|---|
| | 425 | } |
|---|
| | 426 | } |
|---|
| | 427 | return list.length > 0 ? list : null; |
|---|
| | 428 | } |
|---|
| | 429 | |
|---|
| | 430 | return null; |
|---|
| | 431 | }, |
|---|
| | 432 | |
|---|
| | 433 | /** |
|---|
| | 434 | * Method: parseProperty |
|---|
| | 435 | * Convenience method to parse the different kinds of properties |
|---|
| | 436 | * found in the sld and ogc namespace. |
|---|
| | 437 | * |
|---|
| | 438 | * Parses an ogc node that can either contain a value directly, |
|---|
| | 439 | * or inside a <Literal> property. The parsing can also be limited |
|---|
| | 440 | * to nodes with certain attribute names and/or values. |
|---|
| | 441 | * |
|---|
| | 442 | * Parameters: |
|---|
| | 443 | * xmlNode - {<DOMElement>} |
|---|
| | 444 | * namespace - {String} namespace of the node to find |
|---|
| | 445 | * propertyName - {String} name of the property to parse |
|---|
| | 446 | * attributeName - {String} optional name of the property to match |
|---|
| | 447 | * attributeValue - {String} optional value of the specified attribute |
|---|
| | 448 | * |
|---|
| | 449 | * Returns: |
|---|
| | 450 | * {String} The value for the requested property. |
|---|
| | 451 | */ |
|---|
| | 452 | parseProperty: function(xmlNode, namespace, propertyName, attributeName, |
|---|
| | 453 | attributeValue) { |
|---|
| | 454 | var result = null; |
|---|
| | 455 | var propertyNodeList = this.getElementsByTagNameNS( |
|---|
| | 456 | xmlNode, namespace, propertyName); |
|---|
| | 457 | |
|---|
| | 458 | if (propertyNodeList && propertyNodeList.length > 0) { |
|---|
| | 459 | var propertyNode = attributeName ? |
|---|
| | 460 | this.getNodeWithAttribute(propertyNodeList, |
|---|
| | 461 | attributeName) : |
|---|
| | 462 | propertyNodeList[0]; |
|---|
| | 463 | |
|---|
| | 464 | // strip namespace from attribute name for Opera browsers |
|---|
| | 465 | if (window.opera && attributeName) { |
|---|
| | 466 | var nsDelimiterPos = attributeName.indexOf(":"); |
|---|
| | 467 | if (nsDelimiterPos != -1) { |
|---|
| | 468 | attributeName = attributeName.substring(++nsDelimiterPos); |
|---|
| | 469 | } |
|---|
| | 470 | } |
|---|
| | 471 | |
|---|
| | 472 | // get the property value from the node matching attributeName |
|---|
| | 473 | // and attributeValue, eg.: |
|---|
| | 474 | // <CssParameter name="stroke"> |
|---|
| | 475 | // <ogc:Literal>red</ogc:Literal> |
|---|
| | 476 | // </CssParameter> |
|---|
| | 477 | // or: |
|---|
| | 478 | // <CssParameter name="stroke">red</CssParameter> |
|---|
| | 479 | if (attributeName && attributeValue) { |
|---|
| | 480 | propertyNode = this.getNodeWithAttribute(propertyNodeList, |
|---|
| | 481 | attributeName, attributeValue); |
|---|
| | 482 | result = this.parseParameter(propertyNode); |
|---|
| | 483 | } |
|---|
| | 484 | |
|---|
| | 485 | // get the attribute value and use it as result, eg.: |
|---|
| | 486 | // <sld:OnlineResource xlink:href="../img/marker.png"/> |
|---|
| | 487 | if (attributeName && !attributeValue) { |
|---|
| | 488 | var propertyNode = this.getNodeWithAttribute(propertyNodeList, |
|---|
| | 489 | attributeName); |
|---|
| | 490 | result = propertyNode.getAttribute(attributeName); |
|---|
| | 491 | } |
|---|
| | 492 | |
|---|
| | 493 | // get the property value directly or from an ogc:propertyName, |
|---|
| | 494 | // ogc:Literal or any other property at the level of the property |
|---|
| | 495 | // node, eg.: |
|---|
| | 496 | // <sld:Opacity>0.5</sld:Opacity> |
|---|
| | 497 | if (!attributeName) { |
|---|
| | 498 | var result = this.parseParameter(propertyNode); |
|---|
| | 499 | } |
|---|
| | 500 | } |
|---|
| | 501 | |
|---|
| | 502 | // adjust the result to be a trimmed string or a number |
|---|
| | 503 | if (result) { |
|---|
| | 504 | result = OpenLayers.String.trim(result); |
|---|
| | 505 | if (!isNaN(result)) { |
|---|
| | 506 | result = parseFloat(result); |
|---|
| | 507 | } |
|---|
| | 508 | } |
|---|
| | 509 | |
|---|
| | 510 | return result; |
|---|
| | 511 | }, |
|---|
| | 512 | |
|---|
| | 513 | /** |
|---|
| | 514 | * Method: parseParameter |
|---|
| | 515 | * parses a property for propertyNames, Literals and textContent and |
|---|
| | 516 | * creates the according value string. |
|---|
| | 517 | * |
|---|
| | 518 | * Parameters: |
|---|
| | 519 | * xmlNode - {<DOMElement>} |
|---|
| | 520 | * |
|---|
| | 521 | * Returns: |
|---|
| | 522 | * {String} a string holding a value suitable for OpenLayers.Style.value |
|---|
| | 523 | */ |
|---|
| | 524 | parseParameter: function(xmlNode) { |
|---|
| | 525 | if (!xmlNode) { |
|---|
| | 526 | return null; |
|---|
| | 527 | } |
|---|
| | 528 | var childNodes = xmlNode.childNodes; |
|---|
| | 529 | if (!childNodes) { |
|---|
| | 530 | return null; |
|---|
| | 531 | } |
|---|
| | 532 | |
|---|
| | 533 | var value = new Array(childNodes.length); |
|---|
| | 534 | for (var i=0; i<childNodes.length; i++) { |
|---|
| | 535 | if (childNodes[i].nodeName.indexOf("Literal") != -1) { |
|---|
| | 536 | value[i] = this.getChildValue(childNodes[i]); |
|---|
| | 537 | } else |
|---|
| | 538 | if (childNodes[i].nodeName.indexOf("propertyName") != -1) { |
|---|
| | 539 | value[i] = "${" + this.getChildValue(childNodes[i]) + "}"; |
|---|
| | 540 | } else |
|---|
| | 541 | if (childNodes[i].nodeType == 3) { |
|---|
| | 542 | value[i] = childNodes[i].text || childNodes[i].textContent; |
|---|
| | 543 | } |
|---|
| | 544 | } |
|---|
| | 545 | return value.join(""); |
|---|
| | 546 | }, |
|---|
| | 547 | |
|---|
| | 548 | /** |
|---|
| | 549 | * Method: getNodeWithAttribute |
|---|
| | 550 | * Walks through a list of xml nodes and returns the fist node that has an |
|---|
| | 551 | * attribute with the name and optional value specified. |
|---|
| | 552 | * |
|---|
| | 553 | * Parameters: |
|---|
| | 554 | * xmlNodeList - {Array(<DOMElement>)} list to search |
|---|
| | 555 | * attributeName - {String} name of the attribute to match |
|---|
| | 556 | * attributeValue - {String} optional value of the attribute |
|---|
| | 557 | */ |
|---|
| | 558 | getNodeWithAttribute: function(xmlNodeList, attributeName, attributeValue) { |
|---|
| | 559 | for (var i=0; i<xmlNodeList.length; i++) { |
|---|
| | 560 | var currentAttributeValue = |
|---|
| | 561 | xmlNodeList[i].getAttribute(attributeName); |
|---|
| | 562 | if (currentAttributeValue) { |
|---|
| | 563 | if (!attributeValue) { |
|---|
| | 564 | return xmlNodeList[i]; |
|---|
| | 565 | } else if (currentAttributeValue == attributeValue) { |
|---|
| | 566 | return xmlNodeList[i]; |
|---|
| | 567 | } |
|---|
| | 568 | } |
|---|
| | 569 | } |
|---|
| | 570 | }, |
|---|
| | 571 | |
|---|
| | 572 | /** |
|---|
| | 573 | * Constant: TYPES |
|---|
| | 574 | * {Object} Mapping between SLD rule names and rule type constants. |
|---|
| | 575 | * |
|---|
| | 576 | */ |
|---|
| | 577 | TYPES: {'PropertyIsEqualTo': 'EQUAL_TO', |
|---|
| | 578 | 'PropertyIsNotEqualTo': 'NOT_EQUAL_TO', |
|---|
| | 579 | 'PropertyIsLessThan': 'LESS_THAN', |
|---|
| | 580 | 'PropertyIsGreaterThan': 'GREATER_THAN', |
|---|
| | 581 | 'PropertyIsLessThanOrEqualTo': 'LESS_THAN_OR_EQUAL_TO', |
|---|
| | 582 | 'PropertyIsGreaterThanOrEqualTo': 'GREATER_THAN_OR_EQUAL_TO', |
|---|
| | 583 | 'PropertyIsBetween': 'BETWEEN', |
|---|
| | 584 | 'PropertyIsLike': 'LIKE'}, |
|---|
| | 585 | |
|---|
| | 586 | CLASS_NAME: "OpenLayers.Format.SLD" |
|---|
| | 587 | }); |