OpenLayers OpenLayers

Changeset 6645

Show
Ignore:
Timestamp:
03/27/08 13:18:05 (5 months ago)
Author:
tschaub
Message:

SLD format rewrite. Adds a versioned parser with read and write support. This does not come with full support for ogc:expression parsing, but makes for easy future enhancements. r=ahocevar (closes #1458)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/openlayers/examples/sld.html

    r6240 r6645  
    77            height: 475px; 
    88            border: 1px solid black; 
     9            background: #ccddff; 
    910        } 
    1011    </style> 
     
    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                             "tasmania/TasmaniaCities.xml", { 
    53                             styleMap: new OpenLayers.StyleMap(styles["Cities"])})]; 
    54   
    55             for (var i=0; i<gmlLayers.length; i++) { 
    56                 map.addLayer(gmlLayers[i]); 
    57             } 
    58              
    59             hover = new OpenLayers.Control.SelectFeature(gmlLayers[2], { 
    60                     hover: true, 
    61                     renderIntent: "Hover Styler" 
    62                 }); 
     84            var hover = new OpenLayers.Control.SelectFeature( 
     85                gmlLayers[2], {hover: true} 
     86            ); 
    6387            map.addControl(hover); 
    6488            hover.activate(); 
     
    6690         
    6791        // set a new style when the radio button changes 
    68         function setStyle(styleName) { 
    69             gmlLayers[2].styleMap.styles["default"] = styles["WaterBodies"][styleName]; 
     92        function setStyle(index) { 
     93            gmlLayers[2].styleMap.styles["default"] = sld.namedLayers["WaterBodies"].userStyles[index]; 
    7094            // change the style of the features of the WaterBodies layer 
    7195            gmlLayers[2].redraw(); 
     
    7397    </script> 
    7498  </head> 
    75   <body onload="load()"> 
     99  <body onload="init()"> 
    76100    <div id="map"></div> 
    77101    <p>This example uses a <a target="_blank" href="tasmania/sld-tasmania.xml">SLD 
    78     file</a> to style the vector features. The style to be used is either 
    79     determined by the NamedLayer and IsDefault properties in the sld file, or 
    80     can directly be applied by addressing a style from the styles 
    81     hash with the UserStyle name from the sld file as key. Select a new style for the WaterBodies layer below:<p> 
     102    file</a> to style the vector features. To construct layers that use styles 
     103    from SLD, create a StyleMap for the layer that uses one of the userStyles in the 
     104    namedLayers object of the return from format.read().</p> 
     105    <p>Select a new style for the WaterBodies layer below:</p> 
    82106    <form> 
    83       <input type="radio" name="style" onclick="setStyle(this.value)" checked="checked" value="default">Default Styler (zoom in to see more features)</input><br/> 
    84       <input type="radio" name="style" onclick="setStyle(this.value)" value="Styler Test PropertyIsEqualTo">Styler Test PropertyIsEqualTo</input><br/> 
    85       <input type="radio" name="style" onclick="setStyle(this.value)" value="Styler Test Not FeatureId">Styler Test Not FeatureId</input><br/> 
    86       <input type="radio" name="style" onclick="setStyle(this.value)" value="Styler Test WATER_TYPE">Styler Test WATER_TYPE</input><br/> 
    87       <input type="radio" name="style" onclick="setStyle(this.value)" value="Styler Test PropertyIsGreaterThanOrEqualTo">Styler Test PropertyIsGreaterThanOrEqualTo</input><br/> 
    88       <input type="radio" name="style" onclick="setStyle(this.value)" value="Styler Test PropertyIsLessThanOrEqualTo">Styler Test PropertyIsLessThanOrEqualTo</input><br/> 
    89       <input type="radio" name="style" onclick="setStyle(this.value)" value="Styler Test PropertyIsGreaterThan">Styler Test PropertyIsGreaterThan</input><br/> 
    90       <input type="radio" name="style" onclick="setStyle(this.value)" value="Styler Test PropertyIsLessThan">Styler Test PropertyIsLessThan</input><br/> 
    91       <input type="radio" name="style" onclick="setStyle(this.value)" value="Styler Test PropertyIsLike">Styler Test PropertyIsLike</input><br/> 
     107      <input type="radio" name="style" onclick="setStyle(this.value)" checked="checked" value="0">Default Styler (zoom in to see more features)</input><br/> 
     108      <input type="radio" name="style" onclick="setStyle(this.value)" value="3">Styler Test PropertyIsEqualTo</input><br/> 
     109      <input type="radio" name="style" onclick="setStyle(this.value)" value="4">Styler Test WATER_TYPE</input><br/> 
     110      <input type="radio" name="style" onclick="setStyle(this.value)" value="5">Styler Test PropertyIsGreaterThanOrEqualTo</input><br/> 
     111      <input type="radio" name="style" onclick="setStyle(this.value)" value="6">Styler Test PropertyIsLessThanOrEqualTo</input><br/> 
     112      <input type="radio" name="style" onclick="setStyle(this.value)" value="7">Styler Test PropertyIsGreaterThan</input><br/> 
     113      <input type="radio" name="style" onclick="setStyle(this.value)" value="8">Styler Test PropertyIsLessThan</input><br/> 
     114      <input type="radio" name="style" onclick="setStyle(this.value)" value="9">Styler Test PropertyIsLike</input><br/> 
     115      <input type="radio" name="style" onclick="setStyle(this.value)" value="10">Styler Test PropertyIsBetween</input><br/> 
     116      <input type="radio" name="style" onclick="setStyle(this.value)" value="11">Styler Test FeatureId</input><br/> 
    92117    </form> 
    93118  </body> 
  • trunk/openlayers/examples/tasmania/sld-tasmania.xml

    r6543 r6645  
    11<?xml version="1.0" encoding="UTF-8"?> 
    2 <sld:StyledLayerDescriptor xmlns:sld="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml" xmlns:xlink="http://www.w3.org/1999/xlink"> 
     2<sld:StyledLayerDescriptor version="1.0.0" 
     3    xmlns:sld="http://www.opengis.net/sld" 
     4    xmlns:ogc="http://www.opengis.net/ogc" 
     5    xmlns:gml="http://www.opengis.net/gml" 
     6    xmlns:xlink="http://www.w3.org/1999/xlink" 
     7    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     8    xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd"> 
    39  <sld:NamedLayer> 
    410    <sld:Name>WaterBodies</sld:Name> 
     
    5662          <sld:Title>title</sld:Title> 
    5763          <sld:Abstract>Abstract</sld:Abstract> 
    58           <ogc:ElseFilter/> 
     64          <sld:ElseFilter/> 
     65          <sld:PolygonSymbolizer> 
     66            <sld:Fill> 
     67              <sld:CssParameter name="fill">#aaaaff</sld:CssParameter> 
     68              <sld:CssParameter name="fill-opacity"> 
     69                <ogc:Literal>0.5</ogc:Literal> 
     70              </sld:CssParameter> 
     71            </sld:Fill> 
     72            <sld:Stroke> 
     73              <sld:CssParameter name="stroke"> 
     74                <ogc:Literal>#C0C0C0</ogc:Literal> 
     75              </sld:CssParameter> 
     76              <sld:CssParameter name="stroke-opacity"> 
     77                <ogc:Literal>1</ogc:Literal> 
     78              </sld:CssParameter> 
     79              <sld:CssParameter name="stroke-width"> 
     80                <ogc:Literal>1</ogc:Literal> 
     81              </sld:CssParameter> 
     82            </sld:Stroke> 
     83          </sld:PolygonSymbolizer> 
    5984        </sld:Rule> 
    6085      </sld:FeatureTypeStyle> 
     
    124149          <sld:Title>title</sld:Title> 
    125150          <sld:Abstract>Abstract</sld:Abstract> 
    126           <ogc:ElseFilter/> 
    127         </sld:Rule> 
    128       </sld:FeatureTypeStyle> 
    129     </sld:UserStyle> 
    130  
    131  
     151          <sld:ElseFilter/> 
     152          <sld:PolygonSymbolizer> 
     153            <sld:Fill> 
     154              <sld:CssParameter name="fill"> 
     155                <ogc:Literal>black</ogc:Literal> 
     156              </sld:CssParameter> 
     157              <sld:CssParameter name="fill-opacity"> 
     158                <ogc:Literal>0.5</ogc:Literal> 
     159              </sld:CssParameter> 
     160            </sld:Fill> 
     161            <sld:Stroke> 
     162              <sld:CssParameter name="stroke"> 
     163                <ogc:Literal>fuchsia</ogc:Literal> 
     164              </sld:CssParameter> 
     165              <sld:CssParameter name="stroke-opacity"> 
     166                <ogc:Literal>0.5</ogc:Literal> 
     167              </sld:CssParameter> 
     168              <sld:CssParameter name="stroke-width"> 
     169                <ogc:Literal>5</ogc:Literal> 
     170              </sld:CssParameter> 
     171              <sld:CssParameter name="stroke-dashoffset"> 
     172                <ogc:Literal>0</ogc:Literal> 
     173              </sld:CssParameter> 
     174            </sld:Stroke> 
     175          </sld:PolygonSymbolizer> 
     176        </sld:Rule> 
     177      </sld:FeatureTypeStyle> 
     178    </sld:UserStyle> 
    132179 
    133180    <sld:UserStyle> 
     
    161208    </sld:UserStyle> 
    162209 
    163  
    164     <sld:UserStyle> 
    165       <sld:Name>Attribute Filter Styler</sld:Name> 
    166       <sld:Title>Attribute Filter Styler</sld:Title> 
    167       <sld:FeatureTypeStyle> 
    168         <sld:Name>attribute filter type</sld:Name> 
    169         <sld:Title>attribute filter type</sld:Title> 
    170         <sld:FeatureTypeName>Feature</sld:FeatureTypeName> 
    171         <sld:SemanticTypeIdentifier>generic:geometry</sld:SemanticTypeIdentifier> 
    172         <!-- Attribute filters --> 
    173         <sld:Rule> 
    174           <sld:Name>rulePropertyIsEqualTo</sld:Name> 
    175           <sld:Title>rulePropertyIsEqualTo</sld:Title> 
    176           <sld:Abstract>rulePropertyIsEqualTo</sld:Abstract> 
    177           <ogc:Filter> 
    178             <ogc:PropertyIsEqualTo> 
    179               <ogc:PropertyName>name</ogc:PropertyName> 
    180               <ogc:Literal>My simple Polygon</ogc:Literal> 
    181             </ogc:PropertyIsEqualTo> 
    182           </ogc:Filter> 
    183           <sld:PolygonSymbolizer> 
    184             <sld:Fill> 
    185               <sld:CssParameter name="fill"> 
    186                 <ogc:Literal>#000033</ogc:Literal> 
    187               </sld:CssParameter> 
    188             </sld:Fill> 
    189           </sld:PolygonSymbolizer> 
    190         </sld:Rule> 
    191       </sld:FeatureTypeStyle> 
    192     </sld:UserStyle> 
    193  
    194210    <sld:UserStyle> 
    195211      <sld:Name>Styler Test PropertyIsEqualTo</sld:Name> 
     
    221237      </sld:FeatureTypeStyle> 
    222238    </sld:UserStyle> 
    223  
    224     <sld:UserStyle> 
    225       <sld:Name>Styler Test Not FeatureId</sld:Name> 
    226       <sld:Title>Styler Test Not FeatureId</sld:Title> 
    227       <sld:FeatureTypeStyle> 
    228         <sld:Name>attribute filter type</sld:Name> 
    229         <sld:Title>attribute filter type</sld:Title> 
    230         <sld:FeatureTypeName>Feature</sld:FeatureTypeName> 
    231         <sld:SemanticTypeIdentifier>generic:geometry</sld:SemanticTypeIdentifier> 
    232         <!-- Attribute filters --> 
    233         <sld:Rule> 
    234           <sld:Name>ruleNotFeatureId</sld:Name> 
    235           <sld:Title>ruleNotFeatureId</sld:Title> 
    236           <sld:Abstract>ruleNotFeatureId</sld:Abstract> 
    237           <ogc:Filter> 
    238             <ogc:Not> 
    239               <ogc:FeatureId fid="tasmania_water_bodies.7" /> 
    240             </ogc:Not> 
    241           </ogc:Filter> 
    242           <sld:PolygonSymbolizer> 
    243             <sld:Fill> 
    244               <sld:CssParameter name="fill"> 
    245                 <ogc:Literal>red</ogc:Literal> 
    246               </sld:CssParameter> 
    247             </sld:Fill> 
    248           </sld:PolygonSymbolizer> 
    249         </sld:Rule> 
    250       </sld:FeatureTypeStyle> 
    251     </sld:UserStyle> 
    252  
    253  
    254  
    255  
     239     
    256240    <sld:UserStyle> 
    257241      <sld:Name>Styler Test WATER_TYPE</sld:Name> 
     
    430414      </sld:FeatureTypeStyle> 
    431415    </sld:UserStyle> 
    432  
     416     
    433417    <sld:UserStyle> 
    434418      <sld:Name>Styler Test PropertyIsLike</sld:Name> 
     
    461445    </sld:UserStyle> 
    462446 
    463  
    464447    <sld:UserStyle> 
    465448      <sld:Name>Styler Test PropertyIsBetween</sld:Name> 
     
    479462              <ogc:PropertyName>AREA</ogc:PropertyName> 
    480463              <ogc:LowerBoundary> 
    481                 <ogc:Literal>1060000000</ogc:Literal> 
     464                <ogc:Literal>1064866676</ogc:Literal> 
    482465              </ogc:LowerBoundary> 
    483466              <ogc:UpperBoundary> 
    484                 <ogc:Literal>1070000000</ogc:Literal> 
     467                <ogc:Literal>1065512599</ogc:Literal> 
    485468              </ogc:UpperBoundary> 
    486469            </ogc:PropertyIsBetween> 
     
    497480    </sld:UserStyle> 
    498481 
     482    <sld:UserStyle> 
     483      <sld:Name>FeatureId</sld:Name> 
     484      <sld:Title>Styler Test FeatureId</sld:Title> 
     485      <sld:FeatureTypeStyle> 
     486        <sld:Rule> 
     487          <ogc:Filter> 
     488            <ogc:FeatureId fid="tasmania_water_bodies.4"/> 
     489          </ogc:Filter> 
     490          <sld:PolygonSymbolizer> 
     491            <sld:Fill> 
     492              <sld:CssParameter name="fill">blue</sld:CssParameter> 
     493            </sld:Fill> 
     494          </sld:PolygonSymbolizer> 
     495        </sld:Rule> 
     496      </sld:FeatureTypeStyle> 
     497    </sld:UserStyle> 
     498 
    499499  </sld:NamedLayer> 
    500500 
     
    504504      <sld:Name>RoadsDefault</sld:Name> 
    505505      <sld:IsDefault>1</sld:IsDefault> 
    506       <sld:Rule> 
    507         <sld:Name>justAStyler</sld:Name> 
    508         <sld:LineSymbolizer> 
    509           <sld:Stroke> 
    510             <sld:CssParameter name="stroke"> 
    511               <ogc:Literal>red</ogc:Literal> 
    512             </sld:CssParameter> 
    513             <sld:CssParameter name="stroke-width"> 
    514               <ogc:Literal>2</ogc:Literal> 
    515             </sld:CssParameter> 
    516           </sld:Stroke> 
    517         </sld:LineSymbolizer> 
    518       </sld:Rule> 
     506      <sld:FeatureTypeStyle> 
     507        <sld:Rule> 
     508          <sld:Name>justAStyler</sld:Name> 
     509          <sld:LineSymbolizer> 
     510            <sld:Stroke> 
     511              <sld:CssParameter name="stroke"> 
     512                <ogc:Literal>red</ogc:Literal> 
     513              </sld:CssParameter> 
     514              <sld:CssParameter name="stroke-width"> 
     515                <ogc:Literal>2</ogc:Literal> 
     516              </sld:CssParameter> 
     517            </sld:Stroke> 
     518          </sld:LineSymbolizer> 
     519        </sld:Rule> 
     520      </sld:FeatureTypeStyle> 
    519521    </sld:UserStyle> 
    520522  </sld:NamedLayer> 
     
    525527      <sld:Name>DefaultCities</sld:Name> 
    526528      <sld:IsDefault>1</sld:IsDefault> 
    527       <sld:Rule> 
    528         <sld:PointSymbolizer> 
    529           <sld:Graphic> 
    530             <sld:ExternalGraphic> 
    531               <sld:OnlineResource xlink:href="../img/marker.png" /> 
    532               <sld:Format>image/png</sld:Format> 
    533             </sld:ExternalGraphic> 
    534             <sld:Size>10</sld:Size> 
    535             <sld:Opacity>0.5</sld:Opacity> 
    536           </sld:Graphic> 
    537         </sld:PointSymbolizer> 
    538       </sld:Rule> 
     529      <sld:FeatureTypeStyle> 
     530        <sld:Rule> 
     531          <sld:PointSymbolizer> 
     532            <sld:Graphic> 
     533              <sld:ExternalGraphic> 
     534                <sld:OnlineResource xlink:href="../img/marker.png" /> 
     535                <sld:Format>image/png</sld:Format> 
     536              </sld:ExternalGraphic> 
     537              <sld:Opacity>0.5</sld:Opacity> 
     538              <sld:Size>10</sld:Size> 
     539            </sld:Graphic> 
     540          </sld:PointSymbolizer> 
     541        </sld:Rule> 
     542      </sld:FeatureTypeStyle> 
    539543    </sld:UserStyle> 
    540544  </sld:NamedLayer> 
    541545 
     546  <sld:NamedLayer> 
     547    <sld:Name>Land</sld:Name> 
     548    <sld:UserStyle> 
     549      <sld:Name>Land Style</sld:Name> 
     550      <sld:IsDefault>1</sld:IsDefault> 
     551      <sld:FeatureTypeStyle> 
     552        <sld:Rule> 
     553          <sld:PolygonSymbolizer> 
     554            <sld:Fill> 
     555              <sld:CssParameter name="fill">#ccffaa</sld:CssParameter> 
     556              <sld:CssParameter name="fill-opacity"> 
     557                <ogc:Literal>0.5</ogc:Literal> 
     558              </sld:CssParameter> 
     559            </sld:Fill> 
     560            <sld:Stroke> 
     561              <sld:CssParameter name="stroke"> 
     562                <ogc:Literal>#C0C0C0</ogc:Literal> 
     563              </sld:CssParameter> 
     564              <sld:CssParameter name="stroke-opacity"> 
     565                <ogc:Literal>1</ogc:Literal> 
     566              </sld:CssParameter> 
     567              <sld:CssParameter name="stroke-width"> 
     568                <ogc:Literal>1</ogc:Literal> 
     569              </sld:CssParameter> 
     570            </sld:Stroke> 
     571          </sld:PolygonSymbolizer> 
     572        </sld:Rule> 
     573      </sld:FeatureTypeStyle> 
     574    </sld:UserStyle> 
     575  </sld:NamedLayer> 
     576   
    542577</sld:StyledLayerDescriptor> 
  • trunk/openlayers/lib/OpenLayers.js

    r6368 r6645  
    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", 
  • trunk/openlayers/lib/OpenLayers/Format/SLD.js

    r6532 r6645  
    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, 
    76  
     40    parser: null, 
    7741 
    7842    /** 
     
    8953 
    9054    /** 
    91      * APIMethod: read 
    92      * Read data from a string, and return a list of features.  
    93      *  
     55     * APIMethod: write 
     56     * Write a SLD document given a list of styles. 
     57     * 
    9458     * 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>. 
     59     * sld - {Object} An object representing the SLD. 
     60     * options - {Object} Optional configuration object. 
    9861     * 
    9962     * 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. 
     63     * {String} An SLD document string. 
    10364     */ 
    104     read: function(data, options) { 
    105         if (typeof data == "string") {  
    106             data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); 
     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; 
     75            } 
     76            this.parser = new format(this.options); 
    10777        } 
    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      *  
    149      * 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. 
    195      * 
    196      * Parameters: 
    197      * xmlNode - {<DOMElement>} 
    198      *  
    199      * Returns: 
    200      * {Object} Hash of rule properties 
    201      */ 
    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; 
    217             } 
    218         } 
    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      *  
     87     * data - {String | DOMElement} Data to read. 
     88     * 
    32489     * Returns: 
    325      * {<OpenLayers.Rule>} rule representing the filter 
     90     * {Object} An object representing the SLD. 
    32691     */ 
    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; 
     92    read: function(data) { 
     93        if(typeof data == "string") { 
     94            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); 
    33695        } 
    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");&n