YSLD

The gt-ysld module provides a YAML parser/encoder for GeoTools style objects:

  • human readable alternative to machine readable XML

  • compact representation

  • flexible syntax using indentation, rather than order

  • YAML parser provides variables for snippet reuse

  • Full access to GeoTools rendering engine not limited by SLD specification

References:

YSLD Syntax

Quick example (the FeatureTypeStyle, Rule and list of Symbolizers is auto-generated):

line:
  stroke-color: '#3333cc'

Rules example (the FeatureTypeStyle is auto-generated):

rules:
- filter: ${type = 'road'}
  symbolizers:
  - line:
      stroke-color: '#000000'
      stroke-width: 2
- else: true
  symbolizers:
  - line:
      stroke-color: '#666666'
      stroke-width: 1

Complete example with names, titles and comments:

# Created on 2016-03-4
name: water
title: Lakes and Rivers
abstract: Water style using transparency to allow for hill
          shade bathymetry effects.
feature-styles:
- rules:
  - name: hydro
    title: Hydro
    symbolizers:
    - polygon:
        stroke-color: '#333089'
        stroke-width: 1.25
        fill-color: '#333089'
        fill-opacity: 0.45

Yet another markup language (YAML) uses indentation to form a document structure of mappings and lists. The specification supports comments, multiline text and definition reuse.

Expressions

Expressions are specified as CQL/ECQL parse-able expression strings. See the CQL documentation and this CQL tutorial for more information about the CQL syntax.

Literal examples:

line:
  stroke-width: 10
  stroke-linecap: 'butt'

Note: Single quotes are needed for string literals to differentiate them from attribute references.

Attribute example:

text:
  label: ${STATE_NAME}

Function example:

point:
  rotation: ${sqrt([STATE_POP])}

Color examples:

polygon:
  stroke-color: '#ff00ff'
  fill-color: rgb(255,0,255)

Color literals can be specified either as a 6 digit hex string or a 3 argument rgb function call.

Filters

Rule filters are specified as CQL/ECQL parse-able filters. A simple example:

rules:
- filter: ${type = 'highway'}
  symbolizers:
  - line:
      stroke-width: 5

See the CQL documentation and this CQL tutorial for more information about the CQL syntax.

Tuples

Some attributes are specified as pairs. For example:

rules:
- scale: [10000,20000]
point:
  anchor: [0.5,0.5]

The literal strings min and max can also be used:

rules:
- scale: [min,10000]
  symbolizers:
  - line:
    stroke-width: 3
- scale: [10000,max]
  symbolizers:
  - line:
    stroke-width: 1

Arrays

Lists and arrays are specified as space delimited. For example:

stroke-dasharray: '5 2 1 2'

Anchors & References

With YAML it is possible to reference other parts of a document. With this it is possible to support variables and mix ins. An example of a color variable:

redish: &redish '#DD0000'
point:
  fill-color: *redish

An named “anchor” is declared with the & character and then referenced with the * character. This same feature can be used to do “mix-ins” as well:

define: &highway_zoom10
  scale: (10000,20000)
  filter: type = 'highway'
rules:
- <<: *highway_zoom10
  symbolizers:
  - point

The syntax in this case is slightly different and is used when referencing an entire mapping object rather than just a simple scalar value.

YSLD Grammar

Document structure:

<YAML variable definition>
<grid definition>
<style definition>

Grid definition (predefined WGS84, WebMercator):

# grid definition
grid:
  name: <text>

Style definition:

# style definition
name: <text>
title: <text>
abstract: <text>
feature-styles:
- <feature style>

Optional top-level sld and layer definition:

# sld definition
sld-name: <text>
sld-title: <text>
sld-abstract: <text>

# named layer definition
layer-name: <text>

# user layer definition
user-name: <text>
user-remote: <text>
user-service: <text>

Feature style definition:

feature-styles:
- name: <text>
  title: <text>
  abstract: <text>
  transform:
    <transform>
  rules:
  - <rules>
  x-firstMatch: <boolean>
  x-composite: <text>
  x-composite-base: <boolean>

Rule definition:

# rules
rules:
- name: <text>
  title: <text>
  filter: <filter>
  else: <boolean>
  scale: [<min>,<max>]
  zoom: [<min>,<max>]
  symbolizers:
  - <symbolizers>
  x-inclusion: <text>

Line symbolizer definition:

symbolizers:
- line:
    geometry: <expression>
    uom: <text>
    x-labelObstacle: <boolean>
    x-composite-base: <boolean>
    x-composite: <text>
    stroke-color: <color>
    stroke-width: <expression>
    stroke-opacity: <expression>
    stroke-linejoin: <expression>
    stroke-linecap: <expression>
    stroke-dasharray: <float list>
    stroke-dashoffset: <expression>
    stroke-graphic:
      <graphic_options>
    stroke-graphic-fill:
      <graphic_options>
    offset: <expression>

Polygon symbolizer definition:

symbolizers:
- polygon:
    geometry: <expression>
    uom: <text>
    x-labelObstacle: <boolean>
    x-composite-base: <boolean>
    x-composite: <text>
    fill-color: <color>
    fill-opacity: <expression>
    fill-graphic:
      <graphic_options>
    stroke-color: <color>
    stroke-width: <expression>
    stroke-opacity: <expression>
    stroke-linejoin: <expression>
    stroke-linecap: <expression>
    stroke-dasharray: <float list>
    stroke-dashoffset: <expression>
    stroke-graphic:
      <graphic_options>
    stroke-graphic-fill:
      <graphic_options>
    offset: <expression>
    displacement: <expression>

Point symbolizer definition:

symbolizers:
- point:
    geometry: <expression>
    uom: <text>
    x-labelObstacle: <boolean>
    x-composite-base: <boolean>
    x-composite: <text>
    symbols:
    - external:
        url: <text>
        format: <text>
    - mark:
        shape: <shape>
        fill-color: <color>
        fill-opacity: <expression>
        fill-graphic:
          <graphic_options>
        stroke-color: <color>
        stroke-width: <expression>
        stroke-opacity: <expression>
        stroke-linejoin: <expression>
        stroke-linecap: <expression>
        stroke-dasharray: <float list>
        stroke-dashoffset: <expression>
        stroke-graphic:
          <graphic_options>
        stroke-graphic-fill:
          <graphic_options>
    size: <expression>
    rotation: <expression>
    anchor: <tuple>
    displacement: <tuple>
    opacity: <expression>

Raster symbolizer definition:

symbolizers:
- raster:
    opacity: <expression>
    channels:
      gray:
        <channel_options>
      red:
        <channel_options>
      green:
        <channel_options>
      blue:
        <channel_options>
    color-map:
      type: <ramp|interval|values>
      entries:
      - [color, entry_opacity, band_value, text_label]
    contrast-enhancement:
      mode: <normalize|histogram>
      gamma: <expression>

Text symbolizer definition:

symbolizers:
- text:
    geometry: <expression>
    uom: <text>
    x-composite-base: <boolean>
    x-composite: <text>
    label: <expression>
    fill-color: <color>
    fill-opacity: <expression>
    fill-graphic:
      <graphic_options>
    stroke-graphic:
      <graphic_options>
    stroke-graphic-fill:
      <graphic_options>
    font-family: <expression>
    font-size: <expression>
    font-style: <expression>
    font-weight: <expression>
    placement: <point|line>
    offset: <expression>
    anchor: <tuple>
    displacement: <tuple>
    rotation: <expression>
    halo:
      radius: <expression>
      fill-color: <color>
      fill-opacity: <expression>
      fill-graphic:
        <graphic_options>
    graphic:
      symbols:
        <graphic_options>
      size: <expression>
      opacity: <expression>
      rotation: <expression>
    x-allowOverruns: <boolean>
    x-autoWrap: <expression>
    x-conflictResolution: <boolean>
    x-followLine: <boolean>
    x-forceLeftToRight: <boolean>
    x-goodnessOfFit: <expression>
    x-graphic-margin: <expression>
    x-graphic-resize: <none|proportional|stretch>
    x-group: <boolean>
    x-labelAllGroup: <boolean>
    x-labelPriority: <expression>
    x-repeat: <expression>
    x-maxAngleDelta: <expression>
    x-maxDisplacement: <expression>
    x-minGroupDistance: <expression>
    x-partials: <boolean>
    x-polygonAlign: <boolean>
    x-spaceAround: <expression>

Graphic options used above:

symbols:
- mark:
    shape: <shape>
    <<: *fill
    <<: *stroke
- external:
    url: <text>
    format: <text>
anchor: <tuple>
displacement: <tuple>
opacity: <expression>
rotation: <expression>
size: <expression>
options: <options>
gap: <expression>
initial-gap: <expression>

Fill used above:

fill: &fill
  fill-color: <color>
  fill-opacity: <expression>
  fill-graphic:
    <<: *graphic

Stroke used above:

stroke: &stroke
  stroke-color: <color>
  stroke-width: <expression>
  stroke-opacity: <expression>
  stroke-linejoin: <expression>
  stroke-linecap: <expression>
  stroke-dasharray: <float[]>
  stroke-dashoffset: <expression>
  stroke-graphic-fill:
    <<: *graphic
  stroke-graphic-stroke:
    <<: *graphic

Hints

Symbolizer hints are specified as normal mappings on a symbolizer object. Hints start with the prefix ‘x-’ and are limited to numeric, bool and text (no expressions).

If you are checking the GeoServer docs hints are called “vendor options”:

Hints can be used with any symbolizer:

point:
  ...
  # No labels should overlap this feature, used to ensure point graphics are clearly visible
  # and not obscured by text
  x-labelObstacle: true

The majority of hints focus on controlling text:

text:
  # When false does not allow labels on lines to get beyond the beginning/end of the line.
  # By default a partial overrun is tolerated, set to false to disallow it.
  x-allowOverruns: false

  # Number of pixels are which a long label should be split into multiple lines. Works on all
  # geometries, on lines it is mutually exclusive with the followLine option
  x-autoWrap: 400

  # Enables conflict resolution (default, true) meaning no two labels will be allowed to
  # overlap. Symbolizers with conflict resolution off are considered outside of the
  # conflict resolution game, they don't reserve area and can overlap with other labels.
  x-conflictResolution: true

  # When true activates curved labels on linear geometries. The label will follow the shape of
  # the current line, as opposed to being drawn a tangent straight line
  x-followLine: true

  # When true forces labels to a readable orientation, when false they make follow the line
  # orientation even if that means the label will look upside down (useful when using
  # TTF symbol fonts to add direction markers along a line)
  x-forceLeftToRight: true

  # Sets the percentage of the label that must sit inside the geometry to allow drawing
  # the label. Works only on polygons.
  x-goodnessOfFit: 90

  # Pixels between the stretched graphic and the text, applies when graphic stretching is in use
  x-graphic-margin: 10

  # Stretches the graphic below a label to fit the label size. Possible values are 'stretch',
  # 'proportional'.
  x-graphic-resize: true

  # If true, geometries with the same labels are grouped and considered a single entity to be
  # abeled. This allows to avoid or control repeated labels
  x-group: false

  # When false,  only the biggest geometry in a group is labelled (the biggest is obtained by
  # merging, when possible, the original geometries). When true, also the smaller items in the
  # group are labeled. Works only on lines at the moment.
  x-labelAllGroup: false

  # When positive it's the desired distance between two subsequent labels on a "big" geometry.
  # Works only on lines at the moment. If zero only one label is drawn no matter how big the
  # geometry is
  x-repeat: 0

  # When drawing curved labels, max allowed angle between two subsequent characters. Higher
  # angles may cause disconnected words or overlapping characters
  x-maxAngleDelta: 90

  # The distance, in pixel, a label can be displaced from its natural position in an attempt to
  # find a position that does not conflict with already drawn labels.
  x-maxDisplacement: 400

  # Minimum distance between two labels in the same label group. To be used when both
  # displacement and repeat are used to avoid having two labels too close to each other
  x-minGroupDistance: 3

  # Option to truncate labels placed on the border of the displayArea (display partial labels).
  x-partials: true

  # Option overriding manual rotation to align label rotation automatically for polygons.
  x-polygonAlign: true

  # The minimum distance between two labels, in pixels
  x-spaceAround: 50

  # When true enables text kerning (adjustment of space between characters to get a more compact and readable layout)
  x-kerning: true

Additional hints for working with graphic fills:

# Used to specify top, right, bottom and left margins around the graphic used in the fill.
# Allowed values:
# top right bottom left (one explicit value per margin)
x-graphic-margin: 5 10 5 10

# top right-left bottom (three values, with right and left sharing the same value)
x-graphic-margin: 5 10 5

# top-bottom right-left (two values, top and bottom sharing the same value)
x-graphic-margin: 5 10

# top-right-bottom-left (single value for all four margins)
x-graphic-margin: 5

# Activates random distribution of symbol.
# none disables random distribution
x-random: none

# free generates a completely random distribution
x-random: free
# grid will generate a regular grid of positions, and only randomizes the position of the symbol
# around the cell centers, providing a more even distribution in space
x-random: grid

# Determines the size the the texture fill tile that will contain the randomly distributed symbols.
# A smaller tile size will create a more regular pattern
x-random-tile-size: 10

# Activates random symbol rotation. Possible values are none (no rotation) or free.
x-random-rotation: free

# Determines the number of symbols in the tile. Increasing this number will generate a more dense distribution of symbols
x-random-symbol-count: 5

# The “seed” used to generate the random distribution. Changing this value will result in a
# different symbol distribution.
x-random-seed property: 42

Using YSLD

YSLD relies on the gt-main style layer descriptor. Style files are parsed to a StyledLayerDescripter object, which can then be used by the GeoTools style renderer.

To read a YSLD style:

StyledLayerDescriptor style = Ysld.parse(ysld);

The value of ysld can be any of java.io.Reader, java.io.InputStream, @link java.io.File or java.lang.String containing a valid YSLD style.

To write a YSLD style, given a Styled Layer Descriptor:

Ysld.encode(sld, output);

The value of output can be any of java.io.Reader, java.io.InputStream, or java.io.File.

YSLD also provides a validator, which can be called using:

Ysld.validate(ysld);

This call accepts the everything that Ysld.parse(ysld) does, and returns a list of exceptions corresponding to syntax errors.