MS RFC 138: Reference SLD files in Mapfiles¶
- Author:
Seth Girvin
- Contact:
- Last Updated:
2024-03-04
- Version:
MapServer 8.2
- Status:
Adopted
1. Overview¶
This proposal outlines how Styled Layer Descriptor (SLD) files could be referenced directly in a Mapfile, allowing styles
to be applied using SLD files rather than MapServer’s CLASS
and STYLE
blocks.
This would allow easier creation of Mapfiles from other applications, such as QGIS, which could export a Mapfile referencing SLD files, rather than attempting to translate QGIS styles directly to MapServer Mapfile syntax. It would make it easier to re-use styles between different applications.
It is proposed that the LAYER’s STYLEITEM keyword is used to reference the SLD files, as in the example below:
LAYER
STYLEITEM "sld://mysldfile.xml" # uses SHAPEPATH and if not set then relative path to the Mapfile or absolute path
CLASS # Any classes will be ignored, but if there is a problem reading the SLD file it will be used as a fallback
STYLE
COLOR 255 0 0
WIDTH 1
END
END
END
The mechanisms to load and apply a file from disk referenced in a Mapfile could also be used in the future to apply future styling formats for example e.g. OGC styling could use file://style.json.
2.1 Proposed Solution¶
In MapServer 6.6 the LAYER STYLEITEM property was updated to allow a path to a JavaScript file that would return a string containing a STYLE or CLASS definition. See STYLEITEM JavaScript for more details. The same approach will be taken for SLD files, so no new Mapfile keywords or concepts are required.
MapServer currently supports drawing layers in a Mapfile using SLD files in the following scenarios:
When applying SLD from a client application using the
SLD_URL
andSLD_BODY
parameters to a MapServer layer - see the SLD docsWhen using the WMS client -
wms_sld_body
can be used to specify SLD to apply to the WMSWhen using the WMS client -
wms_sld_url
can be used to specify a URL pointing to an SLD file
Currently msSLDApplySLDURL
saves an SLD file a URL to a temporary file, and then applies this SLD to the layer.
Much of the code is already available and can be reused to implement applying SLD directly from a file.
The SLD will be applied at the end of parsing and loading the Mapfile in msLoadMap
and msLoadMapFromString
. Any classes in the layer will
be replaced by classes generated from the SLD. Applying the SLD as early as possible ensures other code paths which affect styling, such as applying SLD from a
URL are unaffected.
Currently all uses of SLD rely on the NamedLayer Name property matching the LAYER NAME. For example
popplace
in the SLD file:
<NamedLayer>
<Name>popplace</Name>
Will only be applied if the LAYER NAME, or WMS name are also popplace
:
LAYER "popplace"
METADATA
"wms_title" "popplace" # this property is also checked for a match
END
If an SLD file is defined within a layer, it is proposed:
For SLD files with multiple NamedLayers, if the Name matches the layer names then this will be used.
If there are no matches then by default the first named layer will be used. A new
SLD_USE_FIRST_NAMEDLAYER
metadata item is created to apply this logic by default. It can be set in the Mapfile to only apply NamedLayer if there is a match in the SLD file usingMETADATA "SLD_USE_FIRST_NAMEDLAYER" "false"
(or any other value than true).
Using the first layer by default will allow SLD files to be more easily reused, and would avoid confusion as to why the SLD isn’t being applied when specified in the Mapfile.
Feature-level SLD Styling¶
MS RFC 61: Enhance MapServer Feature Style Support allowed individual features to be rendered with style read from an attribute, also defined in the STYLEITEM
.
This RFC introduces support for SLD to be read from an attribute, along with OGR styles. For example, the following CSV contains two line features,
the first with an SLD in its STYLE attribute, and the second with an OGR style:
WKT,STYLE_FIELD
"LINESTRING(0.1 0.9,0.9 0.9)","<StyledLayerDescriptor version=""1.1.0""><NamedLayer><Name>test</Name><UserStyle>..
"LINESTRING(0.1 0.8,0.9 0.8)","PEN(c:#000000)","ogr style"
A LAYER
can use the STYLE_FIELD
in the CSV to style individual features using by setting this attribute in the STYLEITEM
:
LAYER
NAME "test"
CONNECTIONTYPE OGR
CONNECTION "data/mixed_styles.csv"
DATA "mixed_styles"
TYPE LINE
STATUS ON
STYLEITEM "STYLE_FIELD"
2.2 Limitations¶
MapServer supports applying multiple NamedLayers to a LAYER, by creating a copy of the layer and applying subsequent NamedLayer styles to these copies. It is proposed only one NamedLayer will be applied to a LAYER when defined as a file in the STYLEITEM property. Cloning layers already containing a STYLEITEM will make the code overly complex, and a Mapfile author is free to create as many LAYERs in the Mapfile as they wish. If multiple NamedLayers are contained in the SLD file only the first will be used.
Feature-level SLD Styling¶
When rendering individual features SLD is applied to the LAYER, the feature is rendered, and then the next feature’s SLD is applied, overriding any previous
changes. For this reason any «layer-level» features in the SLD will be ignored - for example filters and layer opacity. WMS requests such as GetStyles
will return an empty
response. This is currently the case when using OGR styling, or string styles at the feature-level, so no changes will be made in this regard.
2.3 Testing¶
Mapfiles and sample SLD files will be created and added to the msautotest test suite. There are several conflicting features that will need to be tested. Tests will include:
Applying SLD to a LAYER
Checking an error is returned if the SLD file cannot be found
Checking if multiple NamedLayer files are contained in an SLD file the NamedLayer matching the MAP LAYER is used
If there are no matches then the first NamedLayer will be used by default
Checking Legends are correctly generated
Checking SLD can be supplied from a URL or querystring to override the SLD in the STYLEITEM
Several other SLD tests however are already part of the test suite, and will ensure the changes in this RFC don’t break existing functionality:
Passing SLD via
sld_body
in a querystring is tested in many cases for examplemsautotest/wxs/wms_sld.map
Passing in an SLD URL is tested in
msautotest/sld/linemark.map
Reviewing SLD support in MapServer highlighted several use cases which do not currently have tests. These include:
Using
wms_sld_body
in a WMS clientUsing
wms_sld_url
in a WMS client
2.4 Security Concerns¶
MapServer already accepts SLD from remote URLs and client requests, so local SLD files shouldn’t cause any new concerns. A security risk of accepting external graphics in an SLD was addressed in MapServer 7.0 - see https://mapserver.org/MIGRATION_GUIDE.html#mapserver-6-4-to-7-0-migration by requiring external graphic URLs to be defined in a validation block:
WEB
VALIDATION
"sld_external_graphic" "^.*/sld/data/.*"
END
...
2.5 MapScript¶
MapScript currently includes an applySLD
function on both Map and Layer objects.
The layerObj
also includes a styleitem
property which can be used to set the STYLEITEM property.
If mapscript.msLoadMapFromString
is used to load a Mapfile from a string then any STYLEITEM
referencing an SLD file will
automatically be applied to the layer.
3. Implementation Details¶
3.1 Affected files¶
mapdraw.c
mapfile.c
maplayer.c
mapogcsld.cpp
mapogcsld.h
3.2 Ticket Reference¶
3.3 Documentation¶
Documentation will be added to the STYLEITEM docs. A link to these docs will also be added to the «Other Items Implemented» section on the SLD docs page.
4. Voting History¶
+1 from SethG, EvenR, TamasS, JukkaR, SteveL, JeromeB, DanielM, MikeS, TomK
See https://lists.osgeo.org/pipermail/mapserver-dev/2024-February/017105.html