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