OpenLayers OpenLayers

Ticket #533: sld.patch

File sld.patch, 98.4 kB (added by tschaub, 10 months ago)

different style patch (very minor differences)

  • tests/Format/test_SLD.html

    old new  
     1<html>  
     2<head>  
     3    <script src="../../lib/OpenLayers.js"></script>  
     4    <script type="text/javascript"> 
     5 
     6    var test_content = '<sld:StyledLayerDescriptor xmlns:sld="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml"><sld:NamedLayer><sld:Name>TestLayer</sld:Name><sld:UserStyle><sld:Name>foo</sld:Name><sld:FeatureTypeStyle><sld:Rule><sld:Name>bar</sld:Name><ogc:Filter></ogc:Filter><sld:PolygonSymbolizer><sld:Fill><sld:CssParameter name="fill"><ogc:Literal>blue</ogc:Literal></sld:CssParameter></sld:Fill></sld:PolygonSymbolizer></sld:Rule></sld:FeatureTypeStyle></sld:UserStyle></sld:NamedLayer></sld:StyledLayerDescriptor>'; 
     7 
     8    function test_Format_SLD_constructor(t) {  
     9        t.plan(3);  
     10          
     11        var options = {'foo': 'bar'};  
     12        var format = new OpenLayers.Format.SLD(options);  
     13        t.ok(format instanceof OpenLayers.Format.SLD,  
     14             "new OpenLayers.Format.SLD returns object" );  
     15        t.eq(format.foo, "bar", "constructor sets options correctly");  
     16        t.eq(typeof format.read, "function", "format has a read function");  
     17    } 
     18 
     19    function test_Format_SLD_read(t) { 
     20        t.plan(5); 
     21        var styles = new OpenLayers.Format.SLD().read(this.test_content, 
     22                {withNamedLayer: true}); 
     23         
     24        var testLayer = styles[1].TestLayer; 
     25         
     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."); 
     31    } 
     32 
     33    </script>  
     34</head>  
     35<body>  
     36</body>  
     37</html>  
  • tests/list-tests.html

    old new  
    2222    <li>test_Format.html</li> 
    2323    <li>Format/test_XML.html</li> 
    2424    <li>Format/test_KML.html</li> 
     25    <li>Format/test_SLD.html</li> 
    2526    <li>Format/test_GeoRSS.html</li> 
    2627    <li>Format/test_JSON.html</li> 
    2728    <li>Format/test_GeoJSON.html</li> 
  • lib/OpenLayers/Format/SLD.js

    old new  
     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 */ 
     19OpenLayers.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}); 
  • lib/OpenLayers.js

    old new  
    177177            "OpenLayers/Format/GeoRSS.js", 
    178178            "OpenLayers/Format/WFS.js", 
    179179            "OpenLayers/Format/WKT.js", 
     180            "OpenLayers/Format/SLD.js", 
    180181            "OpenLayers/Format/Text.js", 
    181182            "OpenLayers/Format/JSON.js", 
    182183            "OpenLayers/Format/GeoJSON.js", 
  • examples/sld.html

    old new  
     1<html xmlns="http://www.w3.org/1999/xhtml"> 
     2  <head> 
     3    <style type="text/css"> 
     4        #map { 
     5            width: 800px; 
     6            height: 475px; 
     7            border: 1px solid black; 
     8        } 
     9    </style> 
     10    <script src="../lib/Firebug/firebug.js"></script> 
     11    <script src="../lib/OpenLayers.js"></script> 
     12    <script type="text/javascript"> 
     13        var lon = 5; 
     14        var lat = 40; 
     15        var zoom = 5; 
     16        var map, layer, gmlLayers, styles, waterStyle, hover; 
     17 
     18        function load(){ 
     19           OpenLayers.loadURL("tasmania/sld-tasmania.xml", "", null, init); 
     20        } 
     21         
     22        function init(req){ 
     23            map = new OpenLayers.Map('map'); 
     24            layer = new OpenLayers.Layer.WMS( "OpenLayers WMS",  
     25                    "http://labs.metacarta.com/wms/vmap0", {layers: 'basic'} ); 
     26            map.addLayer(layer);            
     27                  map.zoomToExtent(new OpenLayers.Bounds(143,-39,150,-45)); 
     28 
     29            sld = new OpenLayers.Format.SLD().read(req.responseText, 
     30                    {withNamedLayer: true}); 
     31             
     32            styles = sld[1]; 
     33             
     34            waterStyle = styles["WaterBodies"]; 
     35             
     36            gmlLayers = [ 
     37                    // use the sld UserStyle named "Default Styler" 
     38                    new OpenLayers.Layer.GML("StateBoundaries", 
     39                            "tasmania/TasmaniaStateBoundaries.xml", { 
     40                            style: waterStyle["default"]}), 
     41                    new OpenLayers.Layer.GML("Roads", 
     42                            "tasmania/TasmaniaRoads.xml", { 
     43                            style: waterStyle["default"]}), 
     44                    new OpenLayers.Layer.GML("WaterBodies", 
     45                            "tasmania/TasmaniaWaterBodies.xml", { 
     46                            style: waterStyle["default"]}), 
     47                    new OpenLayers.Layer.GML("Cities", 
     48                            "tasmania/TasmaniaCities.xml", { 
     49                            style: waterStyle["default"]})]; 
     50  
     51            // add the first layer with the style passed to the constructor 
     52            map.addLayer(gmlLayers[0]); 
     53            // add the other layers after setting the style using the 
     54            // setStyle() method, which will pick the correct default style 
     55            // from the styles hash we got back from 
     56            // OpenLayers.Format.SLD.read() 
     57            for (var i=1; i<gmlLayers.length; i++) { 
     58                gmlLayers[i].style = styles[gmlLayers[i].name]["default"]; 
     59                      map.addLayer(gmlLayers[i]); 
     60                gmlLayers[i].redraw(); 
     61            } 
     62             
     63            // SLD can also be used for the SelectFeature control 
     64            waterStyle["Hover Styler"].defaultStyle = 
     65                    OpenLayers.Feature.Vector.style["select"]; 
     66            hover = new OpenLayers.Control.SelectFeature(gmlLayers[2], { 
     67                    selectStyle: waterStyle["Hover Styler"], 
     68                    hover: true, 
     69                    select: select 
     70                }); 
     71            map.addControl(hover); 
     72            hover.activate(); 
     73        } 
     74 
     75        // replaces OpenLayers.Control.Select.select 
     76        var select = function(feature) { 
     77            // store layer style 
     78            var style = feature.layer.style; 
     79            // set temporary layer style for hover rendering 
     80            feature.layer.style = hover.selectStyle; 
     81            OpenLayers.Control.SelectFeature.prototype.select.apply(hover, arguments); 
     82            // restore layer style 
     83            feature.layer.style = style; 
     84        } 
     85         
     86        // set a new style when the radio button changes 
     87        function setStyle(styleName) { 
     88            // change the style of the features of the WaterBodies layer 
     89            var features = gmlLayers[2].features; 
     90            for (var i=0; i<features.length; i++) { 
     91                features[i].style = waterStyle[styleName]; 
     92            } 
     93            gmlLayers[2].redraw(); 
     94        } 
     95    </script> 
     96  </head> 
     97  <body onload="load()"> 
     98    <div id="map"></div> 
     99    <p>This example uses a <a target="_blank" href="xml/sld-tasmania.xml">SLD 
     100    file</a> to style the vector features. The style to be used is either 
     101    determined by the NamedLayer and IsDefault properties in the sld file, or 
     102    can directly be applied by addressing a style from the styles 
     103    hash with the UserStyle name from the sld file as key. Select a new style for the WaterBodies layer below:<p> 
     104    <form> 
     105      <input type="radio" name="style" onclick="setStyle(this.value)" checked="checked" value="default">Default Styler (zoom in to see more features)</input><br/> 
     106      <input type="radio" name="style" onclick="setStyle(this.value)" value="Styler Test PropertyIsEqualTo">Styler Test PropertyIsEqualTo</input><br/> 
     107      <input type="radio" name="style" onclick="setStyle(this.value)" value="Styler Test Not FeatureId">Styler Test Not FeatureId</input><br/> 
     108      <input type="radio" name="style" onclick="setStyle(this.value)" value="Styler Test WATER_TYPE">Styler Test WATER_TYPE</input><br/> 
     109      <input type="radio" name="style" onclick="setStyle(this.value)" value="Styler Test PropertyIsGreaterThanOrEqualTo">Styler Test PropertyIsGreaterThanOrEqualTo</input><br/> 
     110      <input type="radio" name="style" onclick="setStyle(this.value)" value="Styler Test PropertyIsLessThanOrEqualTo">Styler Test PropertyIsLessThanOrEqualTo</input><br/> 
     111      <input type="radio" name="style" onclick="setStyle(this.value)" value="Styler Test PropertyIsGreaterThan">Styler Test PropertyIsGreaterThan</input><br/> 
     112      <input type="radio" name="style" onclick="setStyle(this.value)" value="Styler Test PropertyIsLessThan">Styler Test PropertyIsLessThan</input><br/> 
     113      <input type="radio" name="style" onclick="setStyle(this.value)" value="Styler Test PropertyIsLike">Styler Test PropertyIsLike</input><br/> 
     114    </form> 
     115  </body> 
     116</html> 
  • examples/tasmania/TasmaniaRoads.xml

    old new  
     1<?xml version="1.0" encoding="UTF-8"?> 
     2<wfs:FeatureCollection xmlns:wfs="http://www.opengis.net/wfs" xmlns:topp="http://www.openplans.org/topp" xmlns:gml="http://www.opengis.net/gml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.openplans.org/topp http://192.168.0.100:8080/geoserver-1.4.0-RC3/wfs/DescribeFeatureType?typeName=topp:tasmania_roads http://www.opengis.net/wfs http://192.168.0.100:8080/geoserver-1.4.0-RC3/schemas/wfs/1.0.0/WFS-basic.xsd"> 
     3  <gml:boundedBy> 
     4    <gml:Box srsName="http://www.opengis.net/gml/srs/epsg.xml#4326"> 
     5      <gml:coordinates xmlns:gml="http://www.opengis.net/gml" decimal="." cs="," ts=" ">145.19754,-43.423512 148.27298,-40.852802</gml:coordinates> 
     6    </gml:Box> 
     7  </gml:boundedBy> 
     8  <gml:featureMember> 
     9    <topp:tasmania_roads fid="tasmania_roads.1"> 
     10      <topp:the_geom> 
     11        <gml:MultiLineString srsName="http://www.opengis.net/gml/srs/epsg.xml#4326"> 
     12          <gml:lineStringMember> 
     13            <gml:LineString> 
     14              <gml:coordinates xmlns:gml="http://www.opengis.net/gml" decimal="." cs="," ts=" ">146.468582,-41.241478 146.574768,-41.251186 146.640411,-41.255154 146.766129,-41.332348 146.794189,-41.34417 146.822174,-41.362988 146.863434,-41.380234 146.899521,-41.379452 146.929504,-41.378227 147.008041,-41.356079 147.098343,-41.362919</gml:coordinates> 
     15            </gml:LineString> 
     16          </gml:lineStringMember> 
     17        </gml:MultiLineString> 
     18      </topp:the_geom> 
     19      <topp:TYPE>alley</topp:TYPE> 
     20    </topp:tasmania_roads> 
     21  </gml:featureMember> 
     22  <gml:featureMember> 
     23    <topp:tasmania_roads fid="tasmania_roads.2"> 
     24      <topp:the_geom> 
     25        <gml:MultiLineString srsName="http://www.opengis.net/gml/srs/epsg.xml#4326"> 
     26          <gml:lineStringMember> 
     27            <gml:LineString> 
     28              <gml:coordinates xmlns:gml="http://www.opengis.net/gml" decimal="." cs="," ts=" ">147.098343,-41.362919 147.17305,-41.452778 147.213867,-41.503773 147.234894,-41.546661 147.251129,-41.573826 147.264664,-41.602474 147.284485,-41.617554 147.300583,-41.637878</gml:coordinates> 
     29            </gml:LineString> 
     30          </gml:lineStringMember> 
     31        </gml:MultiLineString> 
     32      </topp:the_geom> 
     33      <topp:TYPE>highway</topp:TYPE> 
     34    </topp:tasmania_roads> 
     35  </gml:featureMember> 
     36  <gml:featureMember> 
     37    <topp:tasmania_roads fid="tasmania_roads.3"> 
     38      <topp:the_geom> 
     39        <gml:MultiLineString srsName="http://www.opengis.net/gml/srs/epsg.xml#4326"> 
     40          <gml:lineStringMember> 
     41            <gml:LineString> 
     42              <gml:coordinates xmlns:gml="http://www.opengis.net/gml" decimal="." cs="," ts=" ">147.300583,-41.637878 147.225815,-41.626938 147.183319,-41.619236 147.082367,-41.577755 147.031326,-41.565205 146.961487,-41.564186 146.924545,-41.568565 146.876328,-41.569614 146.783722,-41.56073 146.684937,-41.536232 146.614258,-41.478153 146.619995,-41.423958 146.582581,-41.365482 146.52478,-41.29541 146.477493,-41.277622 146.468582,-41.241478</gml:coordinates> 
     43            </gml:LineString> 
     44          </gml:lineStringMember> 
     45        </gml:MultiLineString> 
     46      </topp:the_geom> 
     47      <topp:TYPE>lane</topp:TYPE> 
     48    </topp:tasmania_roads> 
     49  </gml:featureMember> 
     50  <gml:featureMember> 
     51    <topp:tasmania_roads fid="tasmania_roads.4"> 
     52      <topp:the_geom> 
     53        <gml:MultiLineString srsName="http://www.opengis.net/gml/srs/epsg.xml#4326"> 
     54          <gml:lineStringMember> 
     55            <gml:LineString> 
     56              <gml:coordinates xmlns:gml="http://www.opengis.net/gml" decimal="." cs="," ts=" ">147.522247,-41.859921 147.551865,-41.927834 147.597321,-42.017418 147.578644,-42.113216 147.541656,-42.217743 147.468674,-42.22662</gml:coordinates> 
     57            </gml:LineString> 
     58          </gml:lineStringMember> 
     59        </gml:MultiLineString> 
     60      </topp:the_geom> 
     61      <topp:TYPE>highway</topp:TYPE> 
     62    </topp:tasmania_roads> 
     63  </gml:featureMember> 
     64  <gml:featureMember> 
     65    <topp:tasmania_roads fid="tasmania_roads.5"> 
     66      <topp:the_geom> 
     67        <gml:MultiLineString srsName="http://www.opengis.net/gml/srs/epsg.xml#4326"> 
     68          <gml:lineStringMember> 
     69            <gml:LineString> 
     70              <gml:coordinates xmlns:gml="http://www.opengis.net/gml" decimal="." cs="," ts=" ">146.103699,-41.171677 146.303619,-41.237202 146.362228,-41.236279 146.39418,-41.245384 146.443726,-41.244308 146.468582,-41.241478</gml:coordinates> 
     71            </gml:LineString> 
     72          </gml:lineStringMember> 
     73        </gml:MultiLineString> 
     74      </topp:the_geom> 
     75      <topp:TYPE>gravel</topp:TYPE> 
     76    </topp:tasmania_roads> 
     77  </gml:featureMember> 
     78  <gml:featureMember> 
     79    <topp:tasmania_roads fid="tasmania_roads.6"> 
     80      <topp:the_geom> 
     81        <gml:MultiLineString srsName="http://www.opengis.net/gml/srs/epsg.xml#4326"> 
     82          <gml:lineStringMember> 
     83            <gml:LineString> 
     84              <gml:coordinates xmlns:gml="http://www.opengis.net/gml" decimal="." cs="," ts=" ">145.856018,-41.08007 145.944839,-41.119896 146.037994,-41.150059 146.103699,-41.171677</gml:coordinates> 
     85            </gml:LineString> 
     86          </gml:lineStringMember> 
     87        </gml:MultiLineString> 
     88      </topp:the_geom> 
     89      <topp:TYPE>road</topp:TYPE> 
     90    </topp:tasmania_roads> 
     91  </gml:featureMember> 
     92  <gml:featureMember> 
     93    <topp:tasmania_roads fid="tasmania_roads.7"> 
     94      <topp:the_geom> 
     95        <gml:MultiLineString srsName="http://www.opengis.net/gml/srs/epsg.xml#4326"> 
     96          <gml:lineStringMember> 
     97            <gml:LineString> 
     98              <gml:coordinates xmlns:gml="http://www.opengis.net/gml" decimal="." cs="," ts=" ">147.468674,-42.22662 147.474945,-42.292259 147.467697,-42.301292 147.451828,-42.341656 147.424545,-42.378723 147.366013,-42.412552 147.345779,-42.432449 147.289322,-42.476475 147.264511,-42.503899 147.259918,-42.547539 147.249405,-42.614006 147.278351,-42.693249 147.284271,-42.757759 147.256744,-42.778393</gml:coordinates> 
     99            </gml:LineString> 
     100          </gml:lineStringMember> 
     101        </gml:MultiLineString> 
     102      </topp:the_geom> 
     103      <topp:TYPE>highway</topp:TYPE> 
     104    </topp:tasmania_roads> 
     105  </gml:featureMember> 
     106  <gml:featureMember> 
     107    <topp:tasmania_roads fid="tasmania_roads.8"> 
     108      <topp:the_geom> 
     109        <gml:MultiLineString srsName="http://www.opengis.net/gml/srs/epsg.xml#4326"> 
     110          <gml:lineStringMember> 
     111            <gml:LineString> 
     112              <gml:coordinates xmlns:gml="http://www.opengis.net/gml" decimal="." cs="," ts=" ">148.249252,-41.860851 148.234436,-41.901783 148.192123,-41.93721 148.155762,-41.953667 148.127731,-41.994537 148.053131,-42.100563</gml:coordinates> 
     113            </gml:LineString> 
     114          </gml:lineStringMember> 
     115        </gml:MultiLineString> 
     116      </topp:the_geom> 
     117      <topp:TYPE>road</topp:TYPE> 
     118    </topp:tasmania_roads> 
     119  </gml:featureMember> 
     120  <gml:featureMember> 
     121    <topp:tasmania_roads fid="tasmania_roads.9"> 
     122      <topp:the_geom> 
     123        <gml:MultiLineString srsName="http://www.opengis.net/gml/srs/epsg.xml#4326"> 
     124          <gml:lineStringMember> 
     125            <gml:LineString> 
     126              <gml:coordinates xmlns:gml="http://www.opengis.net/gml" decimal="." cs="," ts=" ">145.19754,-40.878323 145.246674,-40.86021 145.293289,-40.852802 145.465225,-40.897865 145.538498,-40.936264 145.554062,-40.939201 145.602112,-40.962936 145.646362,-40.98243 145.683838,-40.989883 145.710587,-40.996201 145.744293,-41.007545 145.801956,-41.041782 145.856018,-41.08007</gml:coordinates> 
     127            </gml:LineString> 
     128          </gml:lineStringMember> 
     129        </gml:MultiLineString> 
     130      </topp:the_geom> 
     131      <topp:TYPE>logging</topp:TYPE> 
     132    </topp:tasmania_roads> 
     133  </gml:featureMember> 
     134  <gml:featureMember> 
     135    <to