OpenLayers OpenLayers

Ticket #1458: 1458.patch

File 1458.patch, 84.5 kB (added by crschmidt, 8 months ago)

same as above, with html preview available, hopefully

  • tests/Format/test_SLD.html

    old new  
    1717    } 
    1818 
    1919    function test_Format_SLD_read(t) { 
    20         t.plan(5); 
    21         var styles = new OpenLayers.Format.SLD().read(this.test_content, 
    22                 {withNamedLayer: true}); 
     20        t.plan(4); 
     21        var sld = new OpenLayers.Format.SLD().read(this.test_content); 
    2322         
    24         var testLayer = styles[1].TestLayer; 
     23        var testLayer = sld.namedLayers["TestLayer"]; 
     24        var userStyles = testLayer.userStyles; 
    2525         
    26         t.ok(testLayer.foo != undefined, "SLD correctly reads a UserStyle named \"foo\""); 
    27         t.eq(testLayer.foo.rules.length, 1, "The number of rules for the UserStyle is correct"); 
    28         t.eq(testLayer.foo.rules[0].name, "bar", "The first rule's name is \"bar\""); 
    29         t.eq(testLayer.foo.rules[0].symbolizer.Polygon.fillColor, "blue", "The fillColor for the Polygon symbolizer is correct"); 
    30         t.eq(testLayer.foo.name, styles[0][0].name, "The content hash of the Format contains the correct rules."); 
     26        t.eq(userStyles[0].name, "foo", "SLD correctly reads a UserStyle named 'foo'"); 
     27        t.eq(userStyles[0].rules.length, 1, "The number of rules for the UserStyle is correct"); 
     28        t.eq(userStyles[0].rules[0].name, "bar", "The first rule's name is 'bar'"); 
     29        t.eq(userStyles[0].rules[0].symbolizer.Polygon.fillColor, "blue", "The fillColor for the Polygon symbolizer is correct"); 
    3130    } 
    3231 
    3332    </script>  
  • tests/Rule/test_Comparison.html

    old new  
    3737        t.eq(rule.value, ".*b.r\\%\\..*", "Regular expression with different wildcard and escape chars generated correctly."); 
    3838    } 
    3939     
     40    function test_regex2value(t) { 
     41        t.plan(8); 
     42         
     43        function r2v(regex) { 
     44            return OpenLayers.Rule.Comparison.prototype.regex2value.call( 
     45                {value: regex} 
     46            ); 
     47        } 
     48         
     49        t.eq(r2v("foo"), "foo", "doesn't change string without special chars"); 
     50        t.eq(r2v("foo.*foo"), "foo*foo", "wildCard replaced"); 
     51        t.eq(r2v("foo.foo"), "foo.foo", "singleChar replaced"); 
     52        t.eq(r2v("foo\\\\foo"), "foo\\foo", "escape removed"); 
     53        t.eq(r2v("foo!foo"), "foo!!foo", "escapes !"); 
     54        t.eq(r2v("foo\\*foo"), "foo!*foo", "replaces escape on *"); 
     55        t.eq(r2v("foo\\.foo"), "foo!.foo", "replaces escape on ."); 
     56        t.eq(r2v("foo\\\\.foo"), "foo\\.foo", "unescapes only \\ before ."); 
     57         
     58    } 
     59     
    4060    function test_Comparison_evaluate(t) { 
    41         t.plan(4); 
     61        t.plan(5); 
    4262         
    4363        var rule = new OpenLayers.Rule.Comparison({ 
    4464                property: "area", 
    4565                lowerBoundary: 1000, 
    46                 upperBoundary: 5000
     66                upperBoundary: 4999
    4767                type: OpenLayers.Rule.Comparison.BETWEEN}); 
    4868 
    4969        var features = [ 
    5070                new OpenLayers.Feature.Vector(null, { 
    51                         area: 2000}), 
     71                        area: 999}), 
    5272                new OpenLayers.Feature.Vector(null, { 
    53                         area: 6000}), 
     73                        area: 1000}), 
    5474                new OpenLayers.Feature.Vector(null, { 
    55                         area: 4999})]; 
     75                        area: 4999}), 
     76                new OpenLayers.Feature.Vector(null, { 
     77                        area: 5000})]; 
     78        // PropertyIsBetween filter: lower and upper boundary are inclusive 
    5679        var ruleResults = { 
    57                 0: true, 
    58                 1: false, 
    59                 2: true}; 
     80                0: false, 
     81                1: true, 
     82                2: true, 
     83                3: false}; 
    6084        for (var i in ruleResults) { 
    6185            var result = rule.evaluate(features[i]); 
    6286            t.eq(result, ruleResults[i], "feature "+i+ 
  • lib/OpenLayers/Format/SLD.js

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

    old new  
    107107             
    108108            case OpenLayers.Rule.Comparison.BETWEEN: 
    109109                var result = 
    110                         context[this.property] > this.lowerBoundary; 
     110                        context[this.property] >= this.lowerBoundary; 
    111111                result = result && 
    112                         context[this.property] < this.upperBoundary; 
     112                        context[this.property] <= this.upperBoundary; 
    113113                return result; 
    114114            case OpenLayers.Rule.Comparison.LIKE: 
    115115                var regexp = new RegExp(this.value, 
     
    164164    }, 
    165165     
    166166    /** 
     167     * Method: regex2value 
     168     * Convert the value of this rule from a regular expression string into an 
     169     *     ogc literal string using a wildCard of *, a singleChar of ., and an 
     170     *     escape of !.  Leaves the <value> property unmodified. 
     171     *  
     172     * Returns: 
     173     * {String} A string value. 
     174     */ 
     175    regex2value: function() { 
     176         
     177        var value = this.value; 
     178         
     179        // replace ! with !! 
     180        value = value.replace(/!/g, "!!"); 
     181 
     182        // replace \. with !. (watching out for \\.) 
     183        value = value.replace(/(\\)?\\\./g, function($0, $1) { 
     184            return $1 ? $0 : "!."; 
     185        }); 
     186         
     187        // replace \* with #* (watching out for \\*) 
     188        value = value.replace(/(\\)?\\\*/g, function($0, $1) { 
     189            return $1 ? $0 : "!*"; 
     190        }); 
     191         
     192        // replace \\ with \ 
     193        value = value.replace(/\\\\/g, "\\"); 
     194 
     195        // convert .* to * (the sequence #.* is not allowed) 
     196        value = value.replace(/\.\*/g, "*"); 
     197         
     198        return value; 
     199    }, 
     200 
     201    /** 
    167202     * Function: binaryCompare 
    168203     * Compares a feature property to a rule value 
    169204     *  
  • lib/OpenLayers/Rule.js

    old new  
    1515OpenLayers.Rule = OpenLayers.Class({ 
    1616     
    1717    /** 
     18     * Property: id 
     19     * {String} A unique id for this session. 
     20     */ 
     21    id: null, 
     22     
     23    /** 
    1824     * APIProperty: name 
    1925     * {String} name of this rule 
    2026     */ 
    2127    name: 'default', 
    2228     
    2329    /** 
     30     * Property: title 
     31     * {String} Title of this rule (set if included in SLD) 
     32     */ 
     33    title: null, 
     34     
     35    /** 
     36     * Property: description 
     37     * {String} Description of this rule (set if abstract is included in SLD) 
     38     */ 
     39    description: null, 
     40 
     41    /** 
    2442     * Property: context 
    2543     * {Object} An optional object with properties that the rule should be 
    2644     * evaluatad against. If no context is specified, feature.attributes will 
     
    7391     * {<OpenLayers.Rule>} 
    7492     */ 
    7593    initialize: function(options) { 
     94        this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); 
    7695        this.symbolizer = {}; 
    7796 
    7897        OpenLayers.Util.extend(this, options); 
  • lib/OpenLayers/Style.js

    old new  
    2222    name: null, 
    2323     
    2424    /** 
     25     * Property: title 
     26     * {String} Title of this style (set if included in SLD) 
     27     */ 
     28    title: null, 
     29     
     30    /** 
     31     * Property: description 
     32     * {String} Description of this style (set if abstract is included in SLD) 
     33     */ 
     34    description: null, 
     35 
     36    /** 
    2537     * APIProperty: layerName 
    2638     * {<String>} name of the layer that this style belongs to, usually 
    2739     * according to the NamedLayer attribute of an SLD document. 
  • lib/OpenLayers.js

    old new  
    193193            "OpenLayers/Format/WKT.js", 
    194194            "OpenLayers/Format/OSM.js", 
    195195            "OpenLayers/Format/SLD.js", 
     196            "OpenLayers/Format/SLD/v1.js", 
     197            "OpenLayers/Format/SLD/v1_0_0.js", 
    196198            "OpenLayers/Format/Text.js", 
    197199            "OpenLayers/Format/JSON.js", 
    198200            "OpenLayers/Format/GeoJSON.js", 
  • examples/sld.html

    old new  
    66            width: 800px; 
    77            height: 475px; 
    88            border: 1px solid black; 
     9            background: #ccddff; 
    910        } 
    1011    </style> 
    1112    <script src="../lib/Firebug/firebug.js"></script> 
    1213    <script src="../lib/OpenLayers.js"></script> 
    1314    <script type="text/javascript"> 
    14         var lon = 5; 
    15         var lat = 40
    16         var zoom = 5
    17         var map, layer, gmlLayers, styles, waterStyle, hover; 
     15         
     16        var map, sld, gmlLayers
     17        var format = new OpenLayers.Format.SLD()
     18        function init() { 
    1819 
    19         function load(){ 
    20            OpenLayers.loadURL("tasmania/sld-tasmania.xml", "", null, init); 
     20            map = new OpenLayers.Map('map'); 
     21            map.addControl(new OpenLayers.Control.LayerSwitcher()); 
     22 
     23            OpenLayers.loadURL("tasmania/sld-tasmania.xml", null, null, complete); 
     24 
    2125        } 
    2226         
    23         function init(req){ 
    24             map = new OpenLayers.Map('map'); 
    25             layer = new OpenLayers.Layer.WMS( "OpenLayers WMS",  
    26                     "http://labs.metacarta.com/wms/vmap0", {layers: 'basic'} ); 
    27             map.addLayer(layer);            
    28                   map.zoomToExtent(new OpenLayers.Bounds(143,-39,150,-45)); 
     27        function getDefaultStyle(sld, layerName) { 
     28            var styles = sld.namedLayers[layerName].userStyles; 
     29            var style; 
     30            for(var i=0; i<styles.length; ++i) { 
     31                style = styles[i]; 
     32                if(style.isDefault) { 
     33                    break; 
     34                } 
     35            } 
     36            return style; 
     37        } 
    2938 
    30             sld = new OpenLayers.Format.SLD().read(req.responseText, 
    31                     {withNamedLayer: true}); 
     39        function complete(req) { 
     40 
     41            sld = format.read(req.responseXML || req.responseText); 
     42            var hoverStyle = sld.namedLayers["WaterBodies"].userStyles[1]; 
     43            hoverStyle.defaultStyle = OpenLayers.Util.extend( 
     44                {}, OpenLayers.Feature.Vector.style["select"] 
     45            ); 
     46 
     47            gmlLayers = [ 
     48                // use the sld UserStyle named "Default Styler" 
     49                new OpenLayers.Layer.GML( 
     50                    "StateBoundaries", 
     51                    "tasmania/TasmaniaStateBoundaries.xml", 
     52                    { 
     53                        styleMap: new OpenLayers.StyleMap( 
     54                            getDefaultStyle(sld, "Land") 
     55                        ), 
     56                        isBaseLayer: true 
     57                    } 
     58                ), 
     59                new OpenLayers.Layer.GML( 
     60                    "Roads", 
     61                    "tasmania/TasmaniaRoads.xml", 
     62                    {styleMap: new OpenLayers.StyleMap(getDefaultStyle(sld, "Roads"))} 
     63                ), 
     64                new OpenLayers.Layer.GML( 
     65                    "WaterBodies", 
     66                    "tasmania/TasmaniaWaterBodies.xml", 
     67                    { 
     68                        styleMap: new OpenLayers.StyleMap({ 
     69                            "default": getDefaultStyle(sld, "WaterBodies"), 
     70                            "select": hoverStyle 
     71                        }) 
     72                    } 
     73                ), 
     74                new OpenLayers.Layer.GML( 
     75                    "Cities", 
     76                    "tasmania/TasmaniaCities.xml", 
     77                    {styleMap: new OpenLayers.StyleMap(getDefaultStyle(sld, "Cities"))} 
     78                ) 
     79            ]; 
    3280             
    33             styles = sld[1]; 
     81            map.addLayers(gmlLayers); 
     82            map.zoomToExtent(new OpenLayers.Bounds(143,-39,150,-45)); 
    3483             
    35             // for the hover style, we do not want to use the SLD default as 
    36             // base style 
    37             styles["WaterBodies"]["Hover Styler"].defaultStyle = OpenLayers.Util.extend({}, 
    38                 OpenLayers.Feature.Vector.style["select"]); 
    39              
    40             gmlLayers = [ 
    41                     // use the sld UserStyle named "Default Styler" 
    42                     new OpenLayers.Layer.GML("StateBoundaries", 
    43                             "tasmania/TasmaniaStateBoundaries.xml", { 
    44                             styleMap: new OpenLayers.StyleMap(styles["WaterBodies"])}), 
    45                     new OpenLayers.Layer.GML("Roads", 
    46                             "tasmania/TasmaniaRoads.xml", { 
    47                             styleMap: new OpenLayers.StyleMap(styles["Roads"])}), 
    48                     new OpenLayers.Layer.GML("WaterBodies", 
    49                             "tasmania/TasmaniaWaterBodies.xml", { 
    50                             styleMap: new OpenLayers.StyleMap(styles["WaterBodies"])}), 
    51                     new OpenLayers.Layer.GML("Cities", 
    52                             &#