MS RFC 138: Reference SLD files in Mapfiles

Author:

Seth Girvin

Contact:

sethg@geographika.co.uk

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 and SLD_BODY parameters to a MapServer layer - see the SLD docs

  • When using the WMS client - wms_sld_body can be used to specify SLD to apply to the WMS

  • When 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 using METADATA "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 example msautotest/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 client

  • Using 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