{"id":14036173,"url":"https://github.com/NieuwlandGeo/SLDReader","last_synced_at":"2025-07-27T03:31:29.423Z","repository":{"id":21717758,"uuid":"93855575","full_name":"NieuwlandGeo/SLDReader","owner":"NieuwlandGeo","description":"SLD styling for online mapping libraries","archived":false,"fork":false,"pushed_at":"2025-07-23T13:53:11.000Z","size":4841,"stargazers_count":74,"open_issues_count":4,"forks_count":22,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-07-23T13:56:23.792Z","etag":null,"topics":["openlayers","openlayers-plugins","sld","styled-layer-descriptor"],"latest_commit_sha":null,"homepage":"https://nieuwlandgeo.github.io/SLDReader","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NieuwlandGeo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-06-09T12:15:12.000Z","updated_at":"2025-07-23T13:53:15.000Z","dependencies_parsed_at":"2023-02-14T15:31:29.594Z","dependency_job_id":"61f817d4-8f1c-4eb2-937f-0cc6bbca632a","html_url":"https://github.com/NieuwlandGeo/SLDReader","commit_stats":{"total_commits":618,"total_committers":14,"mean_commits":"44.142857142857146","dds":0.56957928802589,"last_synced_commit":"6135baa97afd4085c0418fa482cc3d74488722d5"},"previous_names":[],"tags_count":54,"template":false,"template_full_name":null,"purl":"pkg:github/NieuwlandGeo/SLDReader","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NieuwlandGeo%2FSLDReader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NieuwlandGeo%2FSLDReader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NieuwlandGeo%2FSLDReader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NieuwlandGeo%2FSLDReader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NieuwlandGeo","download_url":"https://codeload.github.com/NieuwlandGeo/SLDReader/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NieuwlandGeo%2FSLDReader/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267294180,"owners_count":24065343,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-27T02:00:11.917Z","response_time":82,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["openlayers","openlayers-plugins","sld","styled-layer-descriptor"],"created_at":"2024-08-12T03:01:51.705Z","updated_at":"2025-07-27T03:31:29.412Z","avatar_url":"https://github.com/NieuwlandGeo.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# SLDReader\n\n[![npm version](https://badge.fury.io/js/%40nieuwlandgeo%2Fsldreader.svg)](https://badge.fury.io/js/%40nieuwlandgeo%2Fsldreader)\n\n[Live demos](https://nieuwlandgeo.github.io/SLDReader)\n\nA javascript package that aims to bring styling from a [sld document](http://www.opengeospatial.org/standards/sld) to popular mapping\ntools. The project consists of two parts:\n\n- An SLDReader that parses an SLD document into a style object.\n- A function createOlStyleFunction that converts the parsed style object into a function that you can use in OpenLayers to style features.\n\nThe OpenLayers style converter tries to be as efficient as possible by recycling OpenLayers Style instances whenever possible.\n\n**CONTRIBUTIONS WELCOME!**\n\nMore information about the standards:\n\n- [Symbology](http://www.opengeospatial.org/standards/symbol/)\n- [SLD](http://www.opengeospatial.org/standards/sld)\n\n## Examples\n\nSee docs/examples folder, to serve them locally\n\n```\nnpm start\n```\n\n## Api docs\n\n[Api docs](https://nieuwlandgeo.github.io/SLDReader/api.html)\n\n## Requirements\n\n- Most SLDReader functions work from OpenLayers v6.15 or higher.\n- OpenLayers version 8.3.0 or higher required to use `GraphicStroke` symbolizers without visual artefacts.\n- OpenLayers version 10.3.0 or higher required to support custom `Mark` symbols.\n- An up-to date browser. If you need to support older browsers, you have to compile SLDReader yourself with a different `browserslist` setting in `package.json`.\n  - The browsers supported by SLDReader can be found here: https://browsersl.ist/#q=defaults .\n- If you want to build and/or run SLDReader, NodeJS v18.18 or higher is required.\n\n## Restrictions on supported SLD Features\n\nThe SLDReader library can read both SLD v1.0 and SLD v1.1 documents, but not every part of the SLD standard is (or can be) implemented by the SLDReader and OpenLayers style converter (yet).\n\n### Symbolizers\n\n#### PointSymbolizer\n\nMarks with well known symbol names are supported: circle, square, triangle, star, cross, x, hexagon, octagon. ExternalGraphic icons are supported.\n\nTwo custom marks are also supported: `horline` for a horizontal line through the center and `backslash` for a line from the top left to the bottom right. Use backslash instead of horline if you want to have diagonal hashing as a polygon graphic fill.\n\nWellknown names that reference a symbol library, like `ttf://CustomFont#42` are not supported. The Size and Rotation elements may be dynamic by using the PropertyName element.\n\nOnly one Graphic per PointSymbolizer is supported. Each Graphic can only have one Mark or one ExternalGraphic.\n\nSome vendor-specific marks (GeoServer, QGIS) are also supported, see the [Mark Gallery demo page](https://nieuwlandgeo.github.io/SLDReader/mark-gallery.html). *Note:* for full custom symbol support you need to use OpenLayers v10.3.0 or higher.\n\n#### ExternalGraphic\n\nExternal graphics can be used with an `OnlineResource` linking to a valid image url.\n\n```xml\n\u003cse:ExternalGraphic\u003e\n  \u003cse:OnlineResource xlink:type=\"simple\" xlink:href=\"assets/img/flag-nl.png\"/\u003e\n  \u003cse:Format\u003eimage/png\u003c/se:Format\u003e\n\u003c/se:ExternalGraphic\u003e\n```\n\nA valid image url can also be a base64 url:\n```xml\n\u003cse:ExternalGraphic\u003e\n  \u003cse:OnlineResource xlink:type=\"simple\" xlink:href=\"data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==\"/\u003e\n  \u003cse:Format\u003eimage/jpeg\u003c/se:Format\u003e\n\u003c/se:ExternalGraphic\u003e\n```\n\nInstead of using base64 urls inside an `OnlineResource`, external graphics can also be embedded as base64 string using `InlineContent` with `encoding=\"base64\"`.\n\n```xml\n\u003cse:ExternalGraphic\u003e\n  \u003cse:InlineContent encoding=\"base64\"\u003eiVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==\u003c/se:InlineContent\u003e\n  \u003cse:Format\u003eimage/jpeg\u003c/se:Format\u003e\n\u003c/se:ExternalGraphic\u003e\n```\n\nInline content can also be SVG with `encoding=\"xml\"`.\n\n```xml\n\u003cse:ExternalGraphic\u003e\n  \u003cse:InlineContent encoding=\"xml\"\u003e\n    \u003csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" width=\"100\" height=\"100\"\u003e\n      \u003cpath d=\"M50,3l12,36h38l-30,22l11,36l-31-21l-31,21l11-36l-30-22h38z\" fill=\"#0F0\" stroke=\"#040\" stroke-width=\"2\"/\u003e\n    \u003c/svg\u003e\n  \u003c/se:InlineContent\u003e\n  \u003cse:Format\u003eimage/svg+xml\u003c/se:Format\u003e\n\u003c/se:ExternalGraphic\u003e\n```\n\n**Important notes:**\n\n- SLDReader does not support `ColorReplacement` inside `ExternalGraphic`s.\n- Do not include the `\u003c?xml ... ?\u003e` header for inline SVG content.\n- Make sure that inline SVG has `width` and `height` attributes. Without it, (most?) browsers cannot properly load the SVG as an image.\n\n#### QGIS parametric SVG support (experimental)\n\nSLD's with parametric embedded SVG's exported by QGIS should be able to be used in SLDReader.\n\nSupport for this functionality is quite hacky and experimental, but appears to work for simple examples.\n\n#### Custom mark symbols\nIt's possible to register your own symbols under your own `WellKnownName`.\n\nCustom symbol coordinates must be entered in counterclockwise order and must all lie within a  `[-1, -1, 1, 1]` bounding box.\nThe coordinates will be scaled by the symbol `\u003cSize\u003e` parameter.\n\nExample (see the [Mark Gallery demo page](https://nieuwlandgeo.github.io/SLDReader/mark-gallery.html)):\n```javascript\nSLDReader.registerCustomSymbol('crystal', [\n  [0.5, 0],\n  [0.75, 0.75],\n  [0, 0.5],\n  [-1, 1],\n  [-0.5, 0],\n  [-0.75, -0.75],\n  [0, -0.5],\n  [1, -1],\n]);\n```\n\n```xml\n\u003cse:PointSymbolizer\u003e\n  \u003cse:Graphic\u003e\n    \u003cse:Mark\u003e\n      \u003cse:WellKnownName\u003ecrystal\u003c/se:WellKnownName\u003e\n      \u003c!-- ...etc... --\u003e\n```\n\nNote: OpenLayers v10.3.0 or higher is required to use the custom symbol functionality. On lower versions, a square is displayed instead.\n\n#### LineSymbolizer\n\nOnly these svg-parameters are supported:\n\n- stroke\n- stroke-width\n- stroke-opacity\n- stroke-linejoin\n- stroke-linecap\n- stroke-dasharray\n- stroke-dashoffset\n\nGraphicStroke with Mark or ExternalGraphic is mostly supported.\n\nGraphicFill and PerpendicularOffset are not supported.\n\n#### Note about GraphicStroke\n\n- It's not possible to use property-dependent values inside a GraphicStroke symbolizer.\n- ExternalGraphic is mostly supported with these caveats:\n  - Always add a Size-element, even if using an ExternalGraphic instead of a Mark.\n  - SLD V1.0.0 does not officially support the Gap property. For this, SLDReader implements the same workaround that Geoserver uses. You can use the `stroke-dasharray` parameter to add a gap between stroke marks. To do this, use a dash array with two parameters: the first parameter being the size of the graphic and the second being the gap size. See the \" GraphicStroke: ExternalGraphic\" example.\n\n#### GraphicStroke vendor options\n\nThe following QGIS vendor options are supported on line symbolizers with a graphic stroke:\n\n- `\u003cVendorOption name=\"placement\"\u003efirstPoint\u003c/VendorOption\u003e`\n- `\u003cVendorOption name=\"placement\"\u003elastPoint\u003c/VendorOption\u003e`\n\nSee the demo page for an example.\n\n#### PolygonSymbolizer\n\nPolygons with static fill and stroke style parameters are supported. See LineSymbolizer above for supported properties for the polygon outline.\n\nFor polygon graphic fills, both ExternalGraphic and Mark graphic fills are supported. The Marks supported here are the same as for a point symbolizer, with the additional restriction that feature-dependent value cannot be used.\n\nThe following WellKnownNames used by QGIS simple fills can be used as well:\n\n- x\n- cross\n- line\n- horline\n- slash\n- backslash\n- brush://dense1 (till dense7)\n\n**Note:** It's not possible to use property-dependent values for inside a GraphicFill element.\n\n#### TextSymbolizer\n\nDynamic Labels (with PropertyName elements), Font and Halo are supported. No vendor-specific options are supported. LabelPlacement or PointPlacement are supported. Graphic elements to display behind the label text are not supported.\n\n- For PointPlacement, Displacement is supported\u003csup\u003e1\u003c/sup\u003e.\n- For PointPlacement, Rotation is supported\u003csup\u003e1\u003c/sup\u003e. PropertyName as rotation value is supported.\n- For PointPlacement, AnchorPoint is partially supported. Since OpenLayers does not support fractional anchor points, the label anchor is snapped to the alignment closest to left/right/top/bottom/center alignment. For instance: an `AnchorPointX` of 0.1 is snapped to 0, corresponding to left alignment in OpenLayers.\n- For LinePlacement, PerpendicularOffset is not supported.\n\n[1]: according to the SLD-spec, label rotation takes place before displacement, but OpenLayers applies displacement before rotation. Beware when combining rotation and displacement inside a single text symbolizer.\n\n### Dynamic parameter values\n\nAccording to the SLD spec, most values can be mixed type (a combination of plain text and [Filter expressions](https://docs.geoserver.org/stable/en/user/styling/sld/reference/filters.html#sld-filter-expression)). This means that most values can depend on feature properties.\n\nSLDReader supports dynamic values in these cases:\n\n- PointSymbolizer Size\n- PointSymbolizer Rotation\n- TextSymbolizer Label\n- SvgParameters used for styling:\n  - `stroke`\n  - `stroke-opacity`\n  - `stroke-width`\n  - `fill`\n  - `fill-opacity`\n  - `font-family`\n  - `font-style`\n  - `font-weight`\n  - `font-size`\n\n**Note:** dynamic parameter values currently have no effect on Marks used inside GraphicStroke or GraphicFill and will use SLD defaults instead.\n\n### Arithmetic operators\n\nOperators `Add`, `Sub`, `Mul`, and `Div` are implemented by converting them to function expressions.\n\n### Units of measure\n\nThe following units of measure are supported on symbolizers, as `uom` attribute:\n\n```\nhttp://www.opengeospatial.org/se/units/pixel\nhttp://www.opengeospatial.org/se/units/metre\nhttp://www.opengeospatial.org/se/units/foot\n```\n\nValues can be forced to pixels by appending px:\n\n```xml\n\u003cse:PointSymbolizer uom=\"http://www.opengeospatial.org/se/units/metre\"\u003e\n  \u003cse:Graphic\u003e\n    \u003cse:Mark\u003e\n      \u003cse:WellKnownName\u003ecircle\u003c/se:WellKnownName\u003e\n      \u003cse:Fill\u003e\n        \u003cse:SvgParameter name=\"fill\"\u003e#88aa88\u003c/se:SvgParameter\u003e\n      \u003c/se:Fill\u003e\n      \u003cse:Stroke\u003e\n        \u003cse:SvgParameter name=\"stroke\"\u003e#004000\u003c/se:SvgParameter\u003e\n        \u003c!-- Override symbolizer uom with pixels by appending px to the value. --\u003e\n        \u003cse:SvgParameter name=\"stroke-width\"\u003e2px\u003c/se:SvgParameter\u003e\n      \u003c/se:Stroke\u003e\n    \u003c/se:Mark\u003e\n    \u003cse:Size\u003e10\u003c/se:Size\u003e \u003c!-- in metres, as per uom attribute --\u003e\n  \u003c/se:Graphic\u003e\n\u003c/se:PointSymbolizer\u003e\n```\n\n**Restrictions:**\n\n- Units of measure are not supported for `GraphicStroke` and `GraphicFill`.\n- Units of measure are not supported on `stroke-dasharray`.\n- Units of measure are not supported within or as return value of `Function` elements. The return type of `Functions` is always treated as dimensionless or pixels, depending on context.\n- Values will always be treated as pixels where units of measure are not supported.\n\n#### Important remark about resolution\n\nWhen converting metres (or feet) to pixels, SLDReader assumes that the resolution passed to the style function by OpenLayers is in `metres/pixel`. This is only true for some map projections. If you care about (approximately) correct sizes in metres, you have to pass a function that calculate the true point resolution in metres per pixel from the view resolution.\n\nSee the `convertResolution` option in the API example [here](https://nieuwlandgeo.github.io/SLDReader/api.html#applying-an-sld-to-a-layer-as-a-style-function).\n\n### Geometry element\n\nThe use of a Geometry element to point to a different geometry property on a feature to use for styling is not supported.\n\n### Filter comparisons\n\nThe SLDReader library supports the following operators inside Filter elements:\n\n- PropertyIsEqualTo\n- PropertyIsNotEqualTo\n- PropertyIsLessThan\n- PropertyIsLessThanOrEqualTo\n- PropertyIsGreaterThan\n- PropertyIsGreaterThanOrEqualTo\n- PropertyIsNull\n- PropertyIsLike\n- PropertyIsBetween\n- And\n- Or\n- Not\n- FeatureId\n\n## Function support\n\nSLDReader can parse `\u003cFunction\u003e` elements, but the support for functions is vendor specific. Geoserver supports different functions than QGIS does. Since it's not feasible to support all possible vendor specific functions, SLDReader only supports a handful of them, listed below.\n\n### Functions supported by SLDReader\n\n- `geometryType(geometry) -\u003e string`\n\n  - Returns OpenLayers geometry type for the input geometry: (Multi)Point, (Multi)LineString, (Multi)Polygon, LinearRing, Circle, or GeometryCollection.\n\n- `dimension(geometry) -\u003e integer`\n\n  - Returns the dimension of the input geometry. 0 for points, 1 for lines and 2 for polygons.\n  - Returns -1 for GeometryCollection.\n  - Returns -1 for null geometry or unknown geometry type.\n  - For a multipart geometry, returns the dimension of the part geometries.\n  - See the [dynamic styling](https://nieuwlandgeo.github.io/SLDReader/dynamic-styling.html) demo for an example of dimension-based styling.\n\n```xml\n\u003cFilter\u003e\n  \u003cPropertyIsEqualTo\u003e\n    \u003cFunction name=\"dimension\"\u003e\n      \u003cPropertyName\u003egeometry\u003c/PropertyName\u003e\n    \u003c/Function\u003e\n    \u003cLiteral\u003e1\u003c/Literal\u003e\n  \u003c/PropertyIsEqualTo\u003e\n\u003c/Filter\u003e\n```\n\n- `substr(string, start, [length]) -\u003e string`\n\n  - Returns part of a string, starting from start index, starting with 1 (!!).\n  - Runs until the end if length is not given.\n  - A negative start index `-N` means start `N` characters from the end.\n  - If length is negative, omit the last `length` characters from the end of the string.\n  - See [QGIS docs](https://docs.qgis.org/3.28/en/docs/user_manual/expressions/functions_list.html#substr) for more info.\n\n- `strSubstring(string, begin, end) -\u003e string`\n\n  - Returns a new string that is a substring of this string. The substring begins at the specified begin and extends to the character at index endIndex - 1 (indexes are zero-based).\n\n- `strSubstringStart(string, begin) -\u003e string`\n\n  - Returns a new string that is a substring of this string. The substring begins at the specified begin and extends to the last character of the string.\n  - A negative `begin` index means: start at that many characters from the end of the string.\n\n- `in(test, ...candidates) -\u003e boolean`\n\n  - Returns `true` if `test` value is present in the list of `candidates` arguments, using string-based, case sensitive, comparison.\n  - Example: `in('fox', 'the', 'quick', 'brown', 'fox') --\u003e true`.\n  - Example: `in(2, '1', '2', '3') --\u003e true`.\n\n- `in2..in10`\n  - These are aliases for the `in` function, coming from (older) GeoServer versions that required a different function for different parameter counts.\n\n### Implementing your own function\n\nIt's possible to add support for a specific function yourself, using `SLDReader.registerFunction(functionName, implementation)`.\n\nExample:\n\n```javascript\nSLDReader.registerFunction('strSubstringStart', (text, startIndex) =\u003e\n  text.slice(startIndex)\n);\n```\n\nAfter registering your function implementation, you can use it for example in a filter expression:\n\n```xml\n\u003cFilter\u003e\n  \u003cPropertyIsEqualTo\u003e\n    \u003cFunction name=\"strSubstringStart\"\u003e\n      \u003cPropertyName\u003etitle\u003c/PropertyName\u003e\n      \u003cLiteral\u003e2\u003c/Literal\u003e\n    \u003c/Function\u003e\n    \u003cLiteral\u003eLLO WORLD\u003c/Literal\u003e\n  \u003c/PropertyIsEqualTo\u003e\n\u003c/Filter\u003e\n```\n\nThe registered function will be called with the value of its child expressions as parameters.\n\n**Important notes:**\n\n- `\u003cLiteral\u003e` expression parameters are always passed as string. If your function expects numeric parameters, convert accordingly.\n- The type of `\u003cPropertyName\u003e` expressions depends on the feature. Typically, when serializing from GeoJSON, integer values are actual integers.\n- SLDReader does not check if the functions are called with the correct number of parameters. Make your function robust against receiving fewer parameters than expected.\n- Geometry-valued expressions will always be OpenLayers Geometry instances.\n- Unless specifically set for your features, the geometry property name is `'geometry'` for OpenLayers features by default.\n- Make your functions as lenient as possible regarding possible inputs. Do not throw errors, but try to return a value that makes sense in that case. If you return `null` from a function implementation, the function fallback value will be used if one is specified in the SLD.\n  - `\u003cFunction name=\"someFunction\" fallbackValue=\"42\"\u003e`\n\n## Contributing\n\n### Creating an issue\n\nPlease include an example sld and if possible an example feature as GeoJSON.\n\n### Pull requests\n\nBefore starting on a pull request, please raise a Github issue first to prevent starting work on something we're already planning/working on.\n\nWhen making a pull request, please:\n\n- Address only a single issue or add a single item of functionality.\n- Create a test for your functionality.\n- Follow eslint rules and apply prettier.\n- Update or add an example.\n\n### Commands\n\nTo install dependencies, test, build and document\n\n```\nnpm install\nnpm test\nnpm run build\nnpm run docs\ndocker-compose up (runs doc website on :4000)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNieuwlandGeo%2FSLDReader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FNieuwlandGeo%2FSLDReader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNieuwlandGeo%2FSLDReader/lists"}