We fixed a significant performance issue in the previous lesson by switching from WFS to WMS, the world-administrative-boundaries, and world-rivers layers. However, we introduced a new problem as these layers now use geoserver server-side default styles. In this lesson, we will reproduce the styles in OpenLayers for these two vector layers, but server-side in geoserver. The default way of styling layers in geoserver is using SLD (Styled Layer Descriptor), which is an Open Geospatial Consortium specification based on XML.
- First, let's have a look at the Javascript function we had to style the world-rivers WFS layer a few lessons ago:
worldRiversStyleFunction(feature, resolution) {
let text;
let width = 2;
if (resolution < 0.002) {
text = new Text({
font: "20px serif",
text: feature.get("river_map"),
fill: new Fill({
color: "rgba(0, 0, 255, 1)",
}),
});
width = 4;
}
return new Style({
stroke: new Stroke({
color: "rgba(0, 0, 255, 1)",
width: width,
}),
text: text,
});
},
- It's a bit complex because we have two symbols depending on the map's resolution. Let's do it step by step and first only translate the simple style with a 2px blue line at all resolutions (in SLD, we will not be talking in resolution but in scale, which is much more appropriate for mapping in general).
- To create a new style in geoserver, go to http://localhost:8080/geoserver, log in as admin and click on Styles in the Data menu on the left-hand side of the page, then click on the "Add new style" link on the upper part of the page:
- Give the style the name of world-rivers and select the laravelgis workspace. Geoserver has a basic SLD editor, paste the following snippet in it and click "Save":
<?xml version="1.0" encoding="UTF-8"?>
<StyledLayerDescriptor version="1.0.0"
xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd"
xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- a named layer is the basic building block of an sld document -->
<NamedLayer>
<Name>World Rivers</Name>
<UserStyle>
<!-- they have names, titles and abstracts -->
<Title>World Rivers</Title>
<!-- FeatureTypeStyles describe how to render different features -->
<!-- a feature type for lines -->
<FeatureTypeStyle>
<!--FeatureTypeName>Feature</FeatureTypeName-->
<Rule>
<Name>World Rivers</Name>
<Title>World Rivers</Title>
<LineSymbolizer>
<Stroke>
<!--Here is the blue line stroke with the width of 2 pixels-->
<CssParameter name="stroke">#0000FF</CssParameter>
<CssParameter name="stroke-width">2</CssParameter>
</Stroke>
</LineSymbolizer>
</Rule>
</FeatureTypeStyle>
</UserStyle>
</NamedLayer>
</StyledLayerDescriptor>
- As you can see, we have a lot of boilerplates, but the stroke of the LineSymbolizer is easy to find. Now let's go to the word-rivers definitions to assign it this default style. Click on "Layers" in the "Data" menu on the left and click on the laravelgis:world-rivers. In the Edit Layer page, go to the "Publishing" tab and select laravelgis:world-rivers as the "Default Style" and click save at the bottom of the page:
- You can now refresh the map and see that the world-rivers layer symbol has been updated, great!
- Let's try to reproduce what we had for the WFS layer; having a more significant stroke and label when the map is zoomed in to an arbitrary level. In the geoserver console, go back to "Styles", click on the world-rivers style and replace the SLD code with the following snippet:
<?xml version="1.0" encoding="UTF-8"?>
<StyledLayerDescriptor version="1.0.0"
xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd"
xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- a named layer is the basic building block of an sld document -->
<NamedLayer>
<Name>World Rivers</Name>
<UserStyle>
<!-- they have names, titles and abstracts -->
<Title>World Rivers</Title>
<!-- FeatureTypeStyles describe how to render different features -->
<!-- a feature type for lines -->
<FeatureTypeStyle>
<!--With SLD we limit the scope of a style to a rule, in this case we will have 2-->
<Rule>
<Name>World Rivers</Name>
<Title>World Rivers</Title>
<!--This rule will only apply when the current scale of the map is more than 1:2,500,500-->
<MinScaleDenominator>2500000</MinScaleDenominator>
<!--This rule will not appear in the WMS legend, we will cover WMS legend in the next lesson
This rule doesn't have a TextSymbolizer, we only define the line symbol-->
<VendorOption name="inclusion">mapOnly</VendorOption>
<LineSymbolizer>
<Stroke>
<!--Let's change the blue line stroke to something lighter and set the width to 1 pixel-->
<CssParameter name="stroke">#0000FF</CssParameter>
<CssParameter name="stroke-width">2</CssParameter>
<CssParameter name="stroke">#3b82f6</CssParameter>
<CssParameter name="stroke-width">1</CssParameter>
</Stroke>
</LineSymbolizer>
</Rule>
<Rule>
<Name>World Rivers</Name>
<Title>World Rivers</Title>
<!--This rule will only apply when the current scale of the map is between 1:1 and 1:2,499,999
it's based on the actual scale of the map, it's much better than using the screen resolution
as in OpenLayers-->
<MinScaleDenominator>1</MinScaleDenominator>
<MaxScaleDenominator>2499999</MaxScaleDenominator>
<LineSymbolizer>
<Stroke>
<!--Here is the blue line stroke with the width of 4 pixels-->
<CssParameter name="stroke">#1e40af</CssParameter>
<CssParameter name="stroke-width">4</CssParameter>
</Stroke>
</LineSymbolizer>
<!--We have a TextSymbolizer with a label based on the river_map attribute of the layer-->
<TextSymbolizer>
<Label>
<ogc:PropertyName>river_map</ogc:PropertyName>
</Label>
<LabelPlacement>
<LinePlacement>
<!--For the placement, we use an offset of 15 pixels so the label is not directly over the line-->
<PerpendicularOffset>
15
</PerpendicularOffset>
</LinePlacement>
</LabelPlacement>
<Fill>
<!--The font color-->
<CssParameter name="fill">#1e40af</CssParameter>
</Fill>
<Font>
<!--The font family, style and size-->
<CssParameter name="font-family">serif</CssParameter>
<CssParameter name="font-size">16</CssParameter>
</Font>
<!--Some more options: the labels will follow the lines
geoserver have a very powerful conflct resolution algorithm
in this case, we tell it not to display a label with an angle of 30 degrees,
not to move a label by more than 200 pixels if the labels would one over
each other and to repeat the labels every 150 pixels-->
<VendorOption name="followLine">true</VendorOption>
<VendorOption name="maxAngleDelta">30</VendorOption>
<VendorOption name="maxDisplacement">200</VendorOption>
<VendorOption name="repeat">150</VendorOption>
</TextSymbolizer>
</Rule>
</FeatureTypeStyle>
</UserStyle>
</NamedLayer>
</StyledLayerDescriptor>
- You can see that SLD is much more advanced than OpenLayers vector symbolization; it's more complicated but much more powerful. Now, in the map, the style is different based on the scale of the view; if it's zoomed in enough, the lines are bolder (4px), and we can see the labels along the lines; if the map is zoomed out; the lines are thinner (1px), and there are no labels:
- Now let's have a look at how the world-administrative-boundaries were styled in Javascript:
worldAdministrativeBoundariesStyleFunction(feature, resolution) {
return new Style({
fill: new Fill({
color: "rgba(125, 125, 125, 0.1)",
}),
stroke: new Stroke({
color: "rgba(125, 125, 125, 1)",
width: 2,
}),
text: new Text({
font: "16px serif bold",
text: feature.get("name"),
fill: new Fill({
color: "rgba(32, 32, 32, 1)",
}),
}),
});
},
- We had a gray fill with an opacity of 0.1, a gray stroke, and a label on the name. This should not be too difficult to reproduce in SLD:
<?xml version="1.0" encoding="UTF-8"?>
<StyledLayerDescriptor version="1.0.0"
xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd"
xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<NamedLayer>
<Name>World administrative boundaries</Name>
<UserStyle>
<Title>World administrative boundaries</Title>
<FeatureTypeStyle>
<!--Just like for the lines, we have rules for polygons-->
<Rule>
<Title>World administrative boundaries</Title>
<!--Now we use a PolygonSymbolizer with Fill and Stroke-->
<PolygonSymbolizer>
<Fill>
<CssParameter name="fill">#7d7d7d</CssParameter>
<CssParameter name="fill-opacity">0.1</CssParameter>
</Fill>
<Stroke>
<CssParameter name="stroke">#7d7d7d</CssParameter>
<CssParameter name="stroke-width">2</CssParameter>
</Stroke>
</PolygonSymbolizer>
<!--And we use a TextSymbolizer for the labels-->
<TextSymbolizer>
<Label>
<ogc:PropertyName>name</ogc:PropertyName>
</Label>
<Font>
<CssParameter name="font-family">serif</CssParameter>
<CssParameter name="font-size">16</CssParameter>
<CssParameter name="font-style">bold</CssParameter>
</Font>
<Fill>
<CssParameter name="fill">#202020</CssParameter>
</Fill>
</TextSymbolizer>
</Rule>
</FeatureTypeStyle>
</UserStyle>
</NamedLayer>
</StyledLayerDescriptor>
- This should work exactly as our Javascript symbol, right? No! Let's take a look at the problem of the labels we introduced after saving the new style in geoserver and assigning it as the default style for the world-administrative-boundaries layer (just like we did for the world-rivers layer):
- The fill and the stroke are now ok, but why do we have so many labels? Well, it's a downside of tiled layers; geoserver can't know how many tiles will be displayed on the map, so it has to put one label per tile. We could quickly fix this problem by rolling back to an ImageLayer but let's see another way we can get around this problem in SLD while still keeping a tiled layer. In geometry, a polygon has a centroid or center of gravity, a point that can easily be calculated. Let's try to use this point to place the labels instead of the polygon itself:
<?xml version="1.0" encoding="UTF-8"?>
<StyledLayerDescriptor version="1.0.0"
xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd"
xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<NamedLayer>
<Name>World administrative boundaries</Name>
<UserStyle>
<Title>World administrative boundaries</Title>
<FeatureTypeStyle>
<Rule>
<Title>World administrative boundaries</Title>
<PolygonSymbolizer>
<Fill>
<CssParameter name="fill">#7d7d7d</CssParameter>
<CssParameter name="fill-opacity">0.1</CssParameter>
</Fill>
<Stroke>
<CssParameter name="stroke">#7d7d7d</CssParameter>
<CssParameter name="stroke-width">2</CssParameter>
</Stroke>
</PolygonSymbolizer>
<TextSymbolizer>
<Label>
<ogc:PropertyName>name</ogc:PropertyName>
</Label>
<Font>
<CssParameter name="font-family">serif</CssParameter>
<CssParameter name="font-size">16</CssParameter>
<CssParameter name="font-style">bold</CssParameter>
</Font>
<Fill>
<CssParameter name="fill">#202020</CssParameter>
</Fill>
<!--We force a geometry based on the centroid of the geom field in the TextSymbolizer-->
<Geometry>
<ogc:Function name="centroid">
<ogc:PropertyName>geom</ogc:PropertyName>
</ogc:Function>
</Geometry>
<!--We define the LabelPlacement as a PointPlacement instead of the default PolygonPlacement-->
<LabelPlacement>
<PointPlacement>
<AnchorPoint>
<AnchorPointX>0</AnchorPointX>
<AnchorPointY>0</AnchorPointY>
</AnchorPoint>
</PointPlacement>
</LabelPlacement>
</TextSymbolizer>
</Rule>
</FeatureTypeStyle>
</UserStyle>
</NamedLayer>
</StyledLayerDescriptor>
- We now have only one label per polygon, even if each polygon is split between multiple tiles! It is to be noted that this method has its limits and that labels will not display at specific scales (if the centroid of the polygon is outside the current view of the map or if geoserver doesn't manage to place the label for any other reason like label overlapping for example). In those cases, it's probably better to use an ImageLayer.
- To demonstrate more SLD rules (and later to show legend options), let's symbolize countries by an attribute available in the table. There is a continent column in the world-administrative-boundaries table in Postgresql with values for the six continents. We will create a fill and a stroke for each country, depending on its continent.
- The SLD code is long and quite repetitive, but it's flexible. We used six rules, one for each continent; we also tweaked the labels by adding a white halo. It's not beautiful, but it's an example meant for learning.
<?xml version="1.0" encoding="UTF-8"?>
<StyledLayerDescriptor version="1.0.0"
xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd"
xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<NamedLayer>
<Name>World administrative boundaries</Name>
<UserStyle>
<Title>World administrative boundaries</Title>
<FeatureTypeStyle>
<Rule>
<!--We change the title of the rule as we will have one rule per continent-->
<Title>World administrative boundaries</Title>
<Title>Africa</Title>
<!--We use an ogc:Filter to tell geoserver that this rule will only apply to countries with the
column continent equal to Africa-->
<ogc:Filter>
<ogc:PropertyIsEqualTo>
<ogc:PropertyName>continent</ogc:PropertyName>
<ogc:Literal>Africa</ogc:Literal>
</ogc:PropertyIsEqualTo>
</ogc:Filter>
<PolygonSymbolizer>
<Fill>
<CssParameter name="fill">#15803d</CssParameter>
<CssParameter name="fill-opacity">0.1</CssParameter>
</Fill>
<Stroke>
<CssParameter name="stroke">#15803d</CssParameter>
<CssParameter name="stroke-width">2</CssParameter>
<CssParameter name="stroke-width">1</CssParameter>
</Stroke>
</PolygonSymbolizer>
<TextSymbolizer>
<Label>
<ogc:PropertyName>name</ogc:PropertyName>
</Label>
<Font>
<CssParameter name="font-family">serif</CssParameter>
<CssParameter name="font-size">16</CssParameter>
<CssParameter name="font-style">bold</CssParameter>
</Font>
<Fill>
<CssParameter name="fill">#15803d</CssParameter>
</Fill>
<!--We add a white halo around the labels so the are easier to read-->
<Halo>
<Radius>1.5</Radius>
<Fill>
<CssParameter name="fill">#FFFFFF</CssParameter>
</Fill>
</Halo>
<ogc:Geometry>
<ogc:Function name="centroid">
<ogc:PropertyName>geom</ogc:PropertyName>
</ogc:Function>
</ogc:Geometry>
<LabelPlacement>
<PointPlacement>
<AnchorPoint>
<AnchorPointX>0</AnchorPointX>
<AnchorPointY>0</AnchorPointY>
</AnchorPoint>
</PointPlacement>
</LabelPlacement>
</TextSymbolizer>
</Rule>
<!--Now we repeat the same rule with different filters and colors for each continent-->
<Rule>
<Title>Americas</Title>
<ogc:Filter>
<ogc:PropertyIsEqualTo>
<ogc:PropertyName>continent</ogc:PropertyName>
<ogc:Literal>Americas</ogc:Literal>
</ogc:PropertyIsEqualTo>
</ogc:Filter>
<PolygonSymbolizer>
<Fill>
<CssParameter name="fill">#b91c1c</CssParameter>
<CssParameter name="fill-opacity">0.1</CssParameter>
</Fill>
<Stroke>
<CssParameter name="stroke">#b91c1c</CssParameter>
<CssParameter name="stroke-width">1</CssParameter>
</Stroke>
</PolygonSymbolizer>
<TextSymbolizer>
<Label>
<ogc:PropertyName>name</ogc:PropertyName>
</Label>
<Font>
<CssParameter name="font-family">serif</CssParameter>
<CssParameter name="font-size">16</CssParameter>
<CssParameter name="font-style">bold</CssParameter>
</Font>
<Fill>
<CssParameter name="fill">#b91c1c</CssParameter>
</Fill>
<Halo>
<Radius>1.5</Radius>
<Fill>
<CssParameter name="fill">#FFFFFF</CssParameter>
</Fill>
</Halo>
<ogc:Geometry>
<ogc:Function name="centroid">
<ogc:PropertyName>geom</ogc:PropertyName>
</ogc:Function>
</ogc:Geometry>
<LabelPlacement>
<PointPlacement>
<AnchorPoint>
<AnchorPointX>0</AnchorPointX>
<AnchorPointY>0</AnchorPointY>
</AnchorPoint>
</PointPlacement>
</LabelPlacement>
</TextSymbolizer>
</Rule>
<Rule>
<Title>Antarctica</Title>
<ogc:Filter>
<ogc:PropertyIsEqualTo>
<ogc:PropertyName>continent</ogc:PropertyName>
<ogc:Literal>Antarctica</ogc:Literal>
</ogc:PropertyIsEqualTo>
</ogc:Filter>
<PolygonSymbolizer>
<Fill>
<CssParameter name="fill">#1d4ed8</CssParameter>
<CssParameter name="fill-opacity">0.1</CssParameter>
</Fill>
<Stroke>
<CssParameter name="stroke">#1d4ed8</CssParameter>
<CssParameter name="stroke-width">1</CssParameter>
</Stroke>
</PolygonSymbolizer>
<TextSymbolizer>
<Label>
<ogc:PropertyName>name</ogc:PropertyName>
</Label>
<Font>
<CssParameter name="font-family">serif</CssParameter>
<CssParameter name="font-size">16</CssParameter>
<CssParameter name="font-style">bold</CssParameter>
</Font>
<Fill>
<CssParameter name="fill">#1d4ed8</CssParameter>
</Fill>
<Halo>
<Radius>1.5</Radius>
<Fill>
<CssParameter name="fill">#FFFFFF</CssParameter>
</Fill>
</Halo>
<ogc:Geometry>
<ogc:Function name="centroid">
<ogc:PropertyName>geom</ogc:PropertyName>
</ogc:Function>
</ogc:Geometry>
<LabelPlacement>
<PointPlacement>
<AnchorPoint>
<AnchorPointX>0</AnchorPointX>
<AnchorPointY>0</AnchorPointY>
</AnchorPoint>
</PointPlacement>
</LabelPlacement>
</TextSymbolizer>
</Rule>
<Rule>
<Title>Asia</Title>
<ogc:Filter>
<ogc:PropertyIsEqualTo>
<ogc:PropertyName>continent</ogc:PropertyName>
<ogc:Literal>Asia</ogc:Literal>
</ogc:PropertyIsEqualTo>
</ogc:Filter>
<PolygonSymbolizer>
<Fill>
<CssParameter name="fill">#a21caf</CssParameter>
<CssParameter name="fill-opacity">0.1</CssParameter>
</Fill>
<Stroke>
<CssParameter name="stroke">#a21caf</CssParameter>
<CssParameter name="stroke-width">1</CssParameter>
</Stroke>
</PolygonSymbolizer>
<TextSymbolizer>
<Label>
<ogc:PropertyName>name</ogc:PropertyName>
</Label>
<Font>
<CssParameter name="font-family">serif</CssParameter>
<CssParameter name="font-size">16</CssParameter>
<CssParameter name="font-style">bold</CssParameter>
</Font>
<Fill>
<CssParameter name="fill">#a21caf</CssParameter>
</Fill>
<Halo>
<Radius>1.5</Radius>
<Fill>
<CssParameter name="fill">#FFFFFF</CssParameter>
</Fill>
</Halo>
<ogc:Geometry>
<ogc:Function name="centroid">
<ogc:PropertyName>geom</ogc:PropertyName>
</ogc:Function>
</ogc:Geometry>
<LabelPlacement>
<PointPlacement>
<AnchorPoint>
<AnchorPointX>0</AnchorPointX>
<AnchorPointY>0</AnchorPointY>
</AnchorPoint>
</PointPlacement>
</LabelPlacement>
</TextSymbolizer>
</Rule>
<Rule>
<Title>Europe</Title>
<ogc:Filter>
<ogc:PropertyIsEqualTo>
<ogc:PropertyName>continent</ogc:PropertyName>
<ogc:Literal>Europe</ogc:Literal>
</ogc:PropertyIsEqualTo>
</ogc:Filter>
<PolygonSymbolizer>
<Fill>
<CssParameter name="fill">#374151</CssParameter>
<CssParameter name="fill-opacity">0.1</CssParameter>
</Fill>
<Stroke>
<CssParameter name="stroke">#374151</CssParameter>
<CssParameter name="stroke-width">1</CssParameter>
</Stroke>
</PolygonSymbolizer>
<TextSymbolizer>
<Label>
<ogc:PropertyName>name</ogc:PropertyName>
</Label>
<Font>
<CssParameter name="font-family">serif</CssParameter>
<CssParameter name="font-size">16</CssParameter>
<CssParameter name="font-style">bold</CssParameter>
</Font>
<Fill>
<CssParameter name="fill">#374151</CssParameter>
</Fill>
<Halo>
<Radius>1.5</Radius>
<Fill>
<CssParameter name="fill">#FFFFFF</CssParameter>
</Fill>
</Halo>
<ogc:Geometry>
<ogc:Function name="centroid">
<ogc:PropertyName>geom</ogc:PropertyName>
</ogc:Function>
</ogc:Geometry>
<LabelPlacement>
<PointPlacement>
<AnchorPoint>
<AnchorPointX>0</AnchorPointX>
<AnchorPointY>0</AnchorPointY>
</AnchorPoint>
</PointPlacement>
</LabelPlacement>
</TextSymbolizer>
</Rule>
<Rule>
<Title>Oceania</Title>
<ogc:Filter>
<ogc:PropertyIsEqualTo>
<ogc:PropertyName>continent</ogc:PropertyName>
<ogc:Literal>Oceania</ogc:Literal>
</ogc:PropertyIsEqualTo>
</ogc:Filter>
<PolygonSymbolizer>
<Fill>
<CssParameter name="fill">#be185d</CssParameter>
<CssParameter name="fill-opacity">0.1</CssParameter>
</Fill>
<Stroke>
<CssParameter name="stroke">#be185d</CssParameter>
<CssParameter name="stroke-width">1</CssParameter>
</Stroke>
</PolygonSymbolizer>
<TextSymbolizer>
<Label>
<ogc:PropertyName>name</ogc:PropertyName>
</Label>
<Font>
<CssParameter name="font-family">serif</CssParameter>
<CssParameter name="font-size">16</CssParameter>
<CssParameter name="font-style">bold</CssParameter>
</Font>
<Fill>
<CssParameter name="fill">#be185d</CssParameter>
</Fill>
<Halo>
<Radius>1.5</Radius>
<Fill>
<CssParameter name="fill">#FFFFFF</CssParameter>
</Fill>
</Halo>
<ogc:Geometry>
<ogc:Function name="centroid">
<ogc:PropertyName>geom</ogc:PropertyName>
</ogc:Function>
</ogc:Geometry>
<LabelPlacement>
<PointPlacement>
<AnchorPoint>
<AnchorPointX>0</AnchorPointX>
<AnchorPointY>0</AnchorPointY>
</AnchorPoint>
</PointPlacement>
</LabelPlacement>
</TextSymbolizer>
</Rule>
</FeatureTypeStyle>
</UserStyle>
</NamedLayer>
</StyledLayerDescriptor>
- We have only covered the surface of SLD; I highly recommend you look at very friendly and detailed documentation, including a cookbook and samples available on the Geoserver documentation website.
In the next post, we will change the monument layer from WFS to WMS and style it with SLD. It will break the zoom to feature and info popup functionality, but we will see how we can fix it with OpenLayers. We will also improve our legend by adding the proper symbolization for each layer's meaning.
The SLD files for this lesson are located in the resources/geodata/sld folder and the commit for this post is available here: styling-wms-layers-in-geoserver-with-sld