├── .eslintrc ├── .gitignore ├── README.md ├── SLD_to_JSON.js ├── exampleData ├── FKB_ElvBekk.xml └── Skyggefiler.json ├── exampleMultipleLayers ├── FKB_ElvBekk 2.xml ├── FKB_ElvBekk 3.xml ├── FKB_ElvBekk 4.xml └── FKB_ElvBekk.xml ├── images ├── diagram.png ├── forsekningskurver.png ├── mapbox-forsenkningskurve.png └── sld-forsenkningskurve.png ├── license.txt ├── package.json └── reorder ├── create_correct_layerorder.js └── layers_ordering.txt /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "sourceType": "module" 4 | }, 5 | "env": { 6 | "browser": true, 7 | "es6": true, 8 | "node": true 9 | }, 10 | "rules": { 11 | "eqeqeq": 2, 12 | "no-multi-spaces": 2, 13 | "no-mixed-spaces-and-tabs": 2, 14 | "no-trailing-spaces": 2, 15 | "space-infix-ops": 2, 16 | "space-before-blocks":2, 17 | "keyword-spacing": ["error", {"before": true, "after": true}], 18 | "quotes": [2, "single"], 19 | "comma-dangle": [2, "never"], 20 | "strict": [2, "global"], 21 | "comma-spacing": [2, {"before": false, "after": true}], 22 | "key-spacing": [2, {"beforeColon": false, "afterColon": true}], 23 | "comma-style": [2, "last"], 24 | "curly": 2, 25 | "object-curly-spacing": [2, "never"], 26 | "space-before-function-paren": [2, { "anonymous": "always", "named": "never" }], 27 | "max-len": [1, 100, 4], 28 | "semi": [2, "always"], 29 | "no-undef": 2, 30 | "radix": 2, 31 | "brace-style": 2 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SLDexit - A script for converting from SLD to Mapbox GL 2 | 3 | `SLD_to_JSON.js` is a script for converting FKB[1]-data in SLD[2]-format to JSON-files according to the Mapbox GL style specification[3]. 4 | The SLD-format is an XML-schema for describing the appearance of map layers, while the Mapbox GL specification is a JSON schema. 5 | 6 | This script is not a complete SLD to Mapbox GL converter (yet?), but it supports the styles in use by Norkart that needed to be converted. Therefore there might be attributes in the SLD standard that is not supported, simply because it wasn't in any if the styles we needed to convert. 7 | 8 | Although the script is tailored to fit our specific needs, the code should be able to handle most SLD files, and if you find cases where this isn't the case, feel free to submit a pull request. 9 | 10 | ## Contents 11 | 1. [The Mapbox GL specification](#The Mapbox GL specification) 12 | 2. [The SLD-files and the conversion](#The SLD-files and the conversion) 13 | 3. [Layout of the code](#Layout of the code) 14 | 4. [Result and manual changes](#Result and manual changes) 15 | 5. [Unsolved problems](#Unsolved problems) 16 | 6. [Running the script](#Running the script) 17 | 7. [Useful links](#Useful links) 18 | 19 | 20 | ## The Mapbox GL specification 21 | Example of valid Mapbox GL format: 22 | 23 | ```json 24 | { 25 | "id": "fill-FKB_ArealressursFlate_bebyggelse", 26 | "layout": {}, 27 | "source": "norkart", 28 | "source-layer": "FKB_ArealressursFlate_bebyggelse", 29 | "minzoom": 13, 30 | "maxzoom": 22, 31 | "type": "fill", 32 | "paint": { 33 | "fill-color": "#d7dcdf" 34 | } 35 | }, 36 | { 37 | "id": "line-FKB_ArealressursFlate_bebyggelse", 38 | "layout": {}, 39 | "source": "norkart", 40 | "source-layer": "FKB_ArealressursFlate_bebyggelse", 41 | "minzoom": 16, 42 | "maxzoom": 22, 43 | "type": "line", 44 | "paint": { 45 | "line-color": "#d7dcdf", 46 | "line-width": 0.1 47 | } 48 | } 49 | ``` 50 | 51 | - ```id``` is *unique* 52 | - ```type``` describes if it is a polygon (fill), line, text(symbol) or point(symbol) 53 | - ```source-layer``` refers to the vector tile layer-id 54 | - ```minzoom``` and ```maxzoom``` defines what zoom level the style is visible 55 | - ```paint``` and ```layout``` are objects with different attributes that describes how the layer is drawn (ie: how it will look) 56 | 57 | 58 | ## The SLD-files and the conversion 59 | 60 | 61 | To get the paint and layout attributes I used the part of the XML-schema that was within the 'rules' tag, and their valid inner tags: 62 | - **LineSymbolizer**, **TextSymbolizer**,**PolygonSymbolizer** and **PointSymbolizer**. 63 | 64 | I used xml2js.Parser() to read the XML. The disadvantage of this was that I could not directly look up the tag name, but had to iterate through the structure until the correct tag was found. This made the code less readable, as I had to learn how the layout for all the different versions of the SLD could be, to know where the tags could be found. 65 | 66 | #### Mapping from attribute name in SLD to Mapbox GL: 67 | The Xml-files has, as mentioned above, relevant info in a symbolizer-tag, that defines the "type"-attribute in Mapbox GL. 68 | 69 | The translation from symbolizer to type is: 70 | 71 | SLD symbolizer | Mapbox type 72 | ---|--- 73 | LineSymbolizer|line 74 | PolygonSymbolizer|fill 75 | TextSymbolizer|symbol 76 | PointSymbolizer|symbol 77 | 78 | Each of these has an inner tag that defines attributes that contains the "cssParameter"-tags. A lot of these could be converted directly from the css parameter name ("CssParameter name= "…" "): 79 | 80 | SLD attribute | Mapbox attribute 81 | ---|--- 82 | stroke|line-color 83 | stroke-width|line-width 84 | stroke-dasharray|line-dasharray 85 | stroke-linejoin|line-join 86 | opacity|line-opacity 87 | font-size|text-size 88 | font-family|text-font 89 | 90 | Other translations was dependent on the parent tag. 91 | 92 | SLD attribute | Mapbox attribute 93 | ---|--- 94 | PolygonSymbolizer-Fill-fill | fill-color 95 | PolygonSymbolizer-Fill-fill-opacity| fill-opacity 96 | PolygonSymbolizer-Fill-opacity|fill-opacity 97 | Label|text-field 98 | TextSymbolizer-Halo-Fill-fill|text-halo-color 99 | TextSymbolizer-Fill-fill|text-color 100 | 101 | Some of the attributes I did not find a translation for: 102 | - Font-style (could be added through text-font by adding bold after name of the font) 103 | - Font-weight 104 | 105 | 106 | #### Attribute values: 107 | An important part of the script was to extract the attribute values. I wrote a general method for this: `getCssParameters(symbTag, validAttrTag, type, outerTag)`. This method returns an array with attribute names and attribute values. 108 | 109 | The method is written based on the structure I could find in most of the SLD files I had. These files had the attribute information in a css-parameter-tagg, within a symbolizer-tag with an inner tag that defined the type, example `` or ``. 110 | 111 | ```xml 112 | 113 | 114 | 115 | # 116 | bbg 117 | 87bef1 118 | 119 | 120 | 0.1 121 | 122 | 123 | ``` 124 | 125 | Fill, stroke and opacity had the same layout as you can see above, where the attribute value is in the other `` tag. 126 | 127 | Other then this, the rest of the attributes had their values directly in the css-parameter-tag, as with you can se with for example stroke-width. 128 | 129 | Even though most of the files had layout like this, it did not apply for all attributes, or all cases of each attribute. 130 | An example is the code underneath, that shows an example where the layout is very different. 131 | 132 | ```xml 133 | 134 | 137 | 138 | 139 | 1.5 140 | 141 | ``` 142 | 143 | To handle these exceptions, I created the method `getObjFromDiffAttr()`. Here I wrote completely separate methods for the exceptions. 144 | 145 | 146 | ## Layout of the code 147 | 148 | ![diagram](images/diagram.png) 149 | 150 | 151 | 152 | ## Order of the layers 153 | 154 | In Mapbox GL the layers are drawn in the order they are defined in the JSON file. This order has to be defined manually after the creation of the JSON file. Therefor a script was created to reorder the layers. The file `layers_ordering.txt`, contains a list with the id-names for the layers, where the names are written in the order they should be drawn. By running the code `create_correct_layerorder.js` the layers in the input file are sorted in the same order as they are defined in `layers_ordering.txt`. 155 | 156 | One thing that was important, but not obvious (at least to me), was that the lines to the polygons always had to be drawn before the polygon itself. The reason is that the polygons overlap the lines, and parts of the lines are therefore hidden behind the polygon. This made it seem like the rendering of the lines were bad because they were hidden behind the polygon, which has poor rendering on the sides. 157 | 158 | 159 | ## Result and manual changes 160 | 161 | The goal of the script was to get a map which was equivalent to the map located on 1881.no now. For the most parts it worked well, and translation worked well. Still, some parts of the SLD was not translated or did not worked optimally and therefore required manual changes after the conversion. 162 | 163 | 164 | #### "Stops" attribute 165 | 166 | An important attribute in Mapbox GL, which was added to a lot of the layers and attributes manually afterwards, were 'stops'. Mapbox defines "Stops" as: 167 | 168 | *The value for any layout or paint property may be specified as a function, allowing you to parameterize the value according to the current zoom level. Functions are written as an array of stops, where each stop is an array with two elements: a zoom level and a corresponding value. Stops must be in ascending zoom order.* 169 | 170 | *Some properties support interpolated functions. The result of an interpolated function is an interpolated value between the last stop whose zoom level is less than or equal to the current zoom level, and the next stop. By default, linear interpolation is used, but you can use a different exponential base for the interpolation curve via the base property. If the current zoom is less than the first stop or greater than the last stop, the result is the value from the first or last stop respectively.* 171 | 172 | *For properties that do not support interpolated functions, the result is the value of the last stop whose zoom value is less than or equal to the current zoom level.* 173 | 174 | ```json 175 | { 176 | "line-width": { 177 | "base": 1.5, 178 | "stops": [[5, 1], [7, 2], [11, 3]] 179 | } 180 | } 181 | ``` 182 | 183 | *base: Optional number. Default is 1. 184 | The exponential base of the interpolation curve. It controls the rate at which the result increases. Higher values make the result increase more towards the high end of the range. With values close to 1 the result increases linearly.* 185 | 186 | *stops: Required array. 187 | An array of zoom level and value pairs. The value can be a number or a color value for color properties.* 188 | 189 | #### Extra layers 190 | Something that was missing in the SLD files, and that I could not find anywhere, was border lines on some of the buildings. Therefore I had to manually create some layers afterwards, and the id of these were: 191 | - line-FKB_Bygning_1 192 | - line-FKB_Bygning_2 193 | - line-FKB_Bygning_3 194 | - line-FKB_AnnenBygning_1 195 | - line-FKB_AnnenBygning_2 196 | - line-FKB_AnnenBygning_3 197 | 198 | In addition to the shadow files that were translated directly, I also made some extra shadow layers by drawing an additional building-polygon with offset and opacity value. The good thing about drawing shadow in this way is that you can choose the direction of the shadow and you can resize depending on zoom level by using the [ "stop" -attribute] (# stop). 199 | 200 | 201 | ## Unsolved problems 202 | 203 | I was not able to find how to draw Depression curves in the correct way. 204 | The image to the left shows how it should have been drawn, and is drawn in SLD, while the image to the right shows how it is drawn in Mapbox GL. It could be possible to solve this by using "line-image" in Mapbox GL. 205 | 206 | ![sld forsenkningskurve](images/forsekningskurver.png) 207 | 208 | Even when symbols are placed in the end of the JSON file, and should be drawn on top of everything else, some of the symbols are still hidden behind other elements. As far as I can tell, this is solved by adding `icon-allow-overlap:true` to the layers in question. An improvement to the script could be to add this automatically to all symbol layers, but this could maybe have an unwanted effect to some symbols. 209 | 210 | Icons are not added to all layers of type **symbol**, and not images that should fill polygons,`fill-image`, since I was not sure what icons should be used. Mapbox do have sprite sheets available, but they do not cover everything. 211 | 212 | 213 | 214 | 215 | ## Running the script 216 | 1. Run `npm install` to install dependencies. 217 | 218 | 2. You can choose to either convert one file, or to convert all files in a given folder. This is dependent on if you are commented out `parseAllFiles()`, or `parse_sld_to_rules_tag()`. You also need to fill in some specific fields, and the instruction for this is added in the script. 219 | 220 | 3. Run the script with node. 221 | 222 | 4. When the script is finished, two files are created; `Result.JSON` and `errorFiles.txt`. `Result.JSON` is the result of the conversion, and the `errorFiles.txt` is a file with names of files that could not be converted, if any. 223 | 224 | 225 | ## Useful links 226 | Mapbox GL style specification: 227 | https://www.mapbox.com/mapbox-gl-style-spec/ 228 | 229 | Mapbox GL validator: https://github.com/mapbox/mapbox-gl-style-spec/blob/mb-pages/README.md#validation 230 | 231 | SLD specification: http://docs.geoserver.org/latest/en/user/styling/sld-cookbook/index.html#sld-cookbook 232 | 233 | # Contributors 234 | 235 | - Written by: Mathilde Ørstavik, summer intern, Norkart 2015. 236 | - Input from various employees at Norkart 237 | 238 | [1]: http://www.opengeospatial.org/standards/sld 239 | [2]: http://www.kartverket.no/kart/kartdata/vektorkart/fkb/ 240 | [3]: https://www.mapbox.com/mapbox-gl-style-spec/ 241 | -------------------------------------------------------------------------------- /SLD_to_JSON.js: -------------------------------------------------------------------------------- 1 | var us = require('underscore'); 2 | var util = require('util'); 3 | var path = require('path'); 4 | var parseString = require('xml2js').parseString; 5 | var fs = require('fs'); 6 | var xml2js = require('xml2js'); 7 | var parser = new xml2js.Parser(); 8 | var nrToParse = 1; //nr to check if last file is converted - if so the end of json file is written! 9 | var nrParsed = 0; //Nr of parsed files so far 10 | 11 | 12 | //-----------------------TODO------------------------------------- 13 | //ADD YOUR SPECIFIC INFO HERE BEFORE RUNNING THE CODE: 14 | var styleSpecName = 'MapboxGLStyle2';//choose the name you want 15 | var sourceName = ''; //name of source for the tiles you want the style specification to apply for 16 | var sourceUrl = ''; //URL to the tileJSON resource 17 | var type = 'vector';//vector, raster, GeoJSON ++ 18 | 19 | 20 | //----------------------- Run script ------------------------// 21 | 22 | //You can run the script either from one file or a directory of files. 23 | //Comment out the one you don't want 24 | 25 | //add path for directory where all files you want to convert are placed 26 | var DIRECTORY_PATH = 'exampleMultipleLayers'; 27 | 28 | parseAllFiles(DIRECTORY_PATH); //parse all files in given directory 29 | 30 | var SPECIFIC_FILE_PATH = 'exampleData/FKB_ElvBekk.xml'; //path of specific file 31 | //parse_sld_to_rules_tag(SPECIFIC_FILE_PATH); //Parse only one file 32 | 33 | 34 | //-------------------------------------------------------------// 35 | 36 | var RESULT_PATH = ''; //Add path you want result files written to 37 | 38 | var VALID_SYMBOLIZERS = [ 39 | 'LineSymbolizer', 40 | 'TextSymbolizer', 41 | 'PolygonSymbolizer', 42 | 'PointSymbolizer' 43 | ]; 44 | 45 | var VALID_ATTR_TAGS = [ 46 | 'Stroke', 47 | 'Fill', 48 | 'Label', 49 | 'Font', 50 | 'Halo', 51 | 'Mark', 52 | 'Size', 53 | 'Geometry', 54 | 'Graphic' 55 | ]; 56 | //attribute-tags that must be handeled different than the rest 57 | var DIFF_ATTR_TAG = ['Label', 'Halo', 'Mark', 'Geometry', 'Graphic']; 58 | 59 | //mapping from sld symbolizer til mapbox GL type-attribute 60 | var CONV_TYPE = { 61 | 'LineSymbolizer': 'line', 62 | 'PolygonSymbolizer': 'fill', 63 | 'TextSymbolizer': 'symbol', 64 | 'PointSymbolizer': 'symbol' 65 | }; 66 | 67 | //attributes that must be handeled different than the rest, 68 | //and has relevant info placed differently (inner tag) 69 | var DIFF_ATTR = ['stroke', 'opacity', 'fill', 'fill-opacity', 'font-size', 'stroke-width']; 70 | 71 | //attrbiutes that belongs to the paint-object in Mapbox gl 72 | var PAINT_ATTR = [ 73 | 'line-color', 'line-width', 'line-dasharray', 'line-opacity', 74 | 'text-color', 'text-halo-color', 'text-halo-width', 'text-halo-blur', 'text-size', 75 | 'fill-color', 'fill-opacity', 'fill-image', 76 | 'icon-color', 'icon-opacity', 'icon-size' 77 | ]; 78 | 79 | //attributes that belongs to the layout-object in Mapbox gl 80 | var LAYOUT_ATTR = [ 81 | 'text-field', 'text-font', 'text-max-size', 'text-max-witdth', 82 | 'line-join', 'symbol-placement', 'icon-image' 83 | ]; 84 | 85 | //mapping from sld to mapbox 86 | var CONVERT_ATTR_NAME = { 87 | 'stroke': 'line-color', 88 | 'stroke-width': 'line-width', 89 | 'stroke-dasharray': 'line-dasharray', 90 | 'stroke-linejoin': 'line-join', 91 | 'opacity': 'line-opacity', 92 | 'PolygonSymbolizer-Fill-fill': 'fill-color', 93 | 'PolygonSymbolizer-Fill-fill-opacity': 'fill-opacity', 94 | 'PolygonSymbolizer-Fill-opacity': 'fill-opacity', 95 | 'font-size': 'text-size', 96 | 'font-family': 'text-font', 97 | 'Label': 'text-field', 98 | 'TextSymbolizer-Halo-Fill-fill': 'text-halo-color', 99 | 'TextSymbolizer-Fill-fill': 'text-color' 100 | }; 101 | 102 | var PUNKT = 'circle-12'; //? 103 | //get the icon-image 104 | var CONV_ICON_IMG = { 105 | 'FKB_Gravplass.xml': 'religious-christian-12', 106 | 'FKB_BautaStatue.xml': 'monument-12', 107 | 'FKB_Bensinpumpe.xml': 'fuel-24', 108 | 'FKB_Broenn.xml': '', 109 | 'FKB_Kum.xml': 'circle-stroked-24' 110 | //, 'FKB_MastTele':,'FKB_Mast_Telesmast' 111 | }; 112 | 113 | var FILES_WRITTEN = []; 114 | 115 | 116 | //translate zoom-scale to zoom-level 117 | function scale_to_zoom(scale) { 118 | if (scale > 500000000) { 119 | return 0; 120 | } 121 | if (scale > 250000000) { 122 | return 1; 123 | } 124 | if (scale > 150000000) { 125 | return 2; 126 | } 127 | if (scale > 70000000) { 128 | return 3; 129 | } 130 | if (scale > 35000000) { 131 | return 4; 132 | } 133 | if (scale > 15000000) { 134 | return 5; 135 | } 136 | if (scale > 10000000) { 137 | return 6; 138 | } 139 | if (scale > 4000000) { 140 | return 7; 141 | } 142 | if (scale > 2000000) { 143 | return 8; 144 | } 145 | if (scale > 1000000) { 146 | return 9; 147 | } 148 | if (scale > 500000) { 149 | return 10; 150 | } 151 | if (scale > 250000) { 152 | return 11; 153 | } 154 | if (scale > 150000) { 155 | return 12; 156 | } 157 | if (scale > 70000) { 158 | return 13; 159 | } 160 | if (scale > 35000) { 161 | return 14; 162 | } 163 | if (scale > 15000) { 164 | return 15; 165 | } 166 | if (scale > 8000) { 167 | return 16; 168 | } 169 | if (scale > 4000) { 170 | return 17; 171 | } 172 | if (scale > 2000) { 173 | return 18; 174 | } 175 | if (scale > 1000) { 176 | return 19; 177 | } 178 | return 20; 179 | } 180 | 181 | function parseAllFiles(path) { 182 | fs.readdir(path, function (error, list) { 183 | if (error) { 184 | console.log('error'); 185 | return error; 186 | } 187 | var filelist = []; 188 | for (var variable of list) { 189 | filelist.push(variable); 190 | } 191 | var i; 192 | nrToParse = filelist.length; 193 | for (var i = 0; i < filelist.length; i++) { 194 | parse_sld_to_rules_tag(path + '/' + filelist[i]); 195 | } 196 | }); 197 | 198 | setTimeout(function () { 199 | //not sure what time will be sufficent in large datasets 200 | }, 5000); 201 | } 202 | 203 | //parses the xml and finds symbolizer-element and type 204 | function parse_sld_to_rules_tag(file) { 205 | fs.readFile(file, function (err, data) { 206 | if (err) { 207 | console.log(err); 208 | } 209 | parseFile(data, file); 210 | }); 211 | nrParsed++; 212 | if (nrParsed === nrToParse) { 213 | //TODO: Find a way to remove the timeout? Problem is that there is no way to 214 | //know how many layers will be written to the result json 215 | //and you can therefor not do a check if the last is written or not. 216 | //You cannot send a callback since it should only be written the last time. 217 | setTimeout(function () { 218 | writeEndOfJSON(); 219 | }, 500); 220 | } 221 | } 222 | 223 | function writeStartOfJSON() { 224 | var top = '{ "version": 7, "name": "' + styleSpecName + '", "sources": { "' + sourceName + '": { "type": "vector", "url": "' + sourceUrl + '" } }, "glyphs": "mapbox://fontstack/{fontstack}/{range}.pbf", "sprite": "https://www.mapbox.com/mapbox-gl-styles/sprites/sprite", "layers": [ { "id": "background", "type": "background", "paint": { "background-color": "rgb(237, 234, 235)" } }'; 225 | // var top = '{ "version": 7, "name": "MapboxGLStyle2", "sources": { "norkart": { "type": "vector", "url": "mapbox://andersob.3ukdquxr" } }, "glyphs": "mapbox://fontstack/{fontstack}/{range}.pbf", "sprite": "https://www.mapbox.com/mapbox-gl-styles/sprites/sprite", "layers": [ { "id": "background", "type": "background", "paint": { "background-color": "rgb(237, 234, 235)" } }'; 226 | fs.writeFile(RESULT_PATH + '\\Result.JSON', top + '\n'); 227 | fs.writeFile(RESULT_PATH + '\\errorFiles.txt', 'Files that could not be converted:' + '\n'); 228 | } 229 | 230 | function writeEndOfJSON() { 231 | console.log('writing end of json'); 232 | var end = ']}'; 233 | fs.appendFile(RESULT_PATH + '\\Result.JSON', end); 234 | } 235 | 236 | var parseFile = function (data, file) { 237 | writeStartOfJSON(); 238 | parser.parseString(data, function (err, result) { 239 | var FeatureTypeStyle = result.StyledLayerDescriptor.NamedLayer[0].UserStyle[0].FeatureTypeStyle; 240 | var rulesArr = []; 241 | var k; 242 | var rules = []; 243 | for (k = 0; k < FeatureTypeStyle.length; k++) { //some files had more than one FeatureTypeStyle 244 | var rulesVer = (FeatureTypeStyle[k].Rule); 245 | var rule; 246 | for (rule = 0; rule < rulesVer.length; rule++) { 247 | //pushes all rules-tag in different FeatureTypeStyle-tags to one array 248 | rules.push(rulesVer[rule]); 249 | } 250 | } 251 | var j; 252 | var maxzoom; 253 | var minzoom; 254 | for (j = 0; j < rules.length; j++) { 255 | rule = rules[j]; 256 | name = rule.Name[0]; 257 | maxzoom = scale_to_zoom(rule.MaxScaleDenominator[0]); 258 | minzoom = scale_to_zoom(rule.MinScaleDenominator[0]); 259 | //Checks if the tag is valid, and if it is: saves the object and type-name 260 | var i; 261 | var ruleArray = Object.keys(rule); 262 | for (i = 0; i < ruleArray.length; i++) { 263 | if ((VALID_SYMBOLIZERS.indexOf(ruleArray[i])) > -1) { 264 | //Sends object, symbolizer and filename 265 | writeJSON(rule[ruleArray[i]], ruleArray[i], name, minzoom, maxzoom, file); 266 | } 267 | } 268 | } 269 | }); 270 | }; 271 | 272 | 273 | //called for each symbolizer 274 | //this runs the rest of the methods through make_JSON and so on, and writes the objects to file 275 | function writeJSON(symbTag, type, name, minzoom, maxzoom, file) { 276 | var errorFiles = []; 277 | var convType = convertType(type); 278 | try { 279 | var cssObj = getSymbolizersObj(symbTag, type, file); 280 | //if css-obj contains both fill and stroke, you have to split them into two layers 281 | if (cssObj['fill-color'] !== undefined && cssObj['line-color'] !== undefined) { 282 | var attPos = (Object.keys(cssObj)).indexOf('line-color'); 283 | var i; 284 | var obj = {}; 285 | var size = ((Object.keys(cssObj)).length); 286 | for (i = attPos; i < (size); i++) { 287 | //since i delete for each loop, it will always be this position 288 | var key = Object.keys(cssObj)[attPos]; 289 | obj[key] = cssObj[key]; 290 | delete cssObj[key]; 291 | } 292 | var styleObj1 = make_JSON(name, convType, cssObj, minzoom, maxzoom); 293 | var styleObj2 = make_JSON(name, 'line', obj, minzoom, maxzoom); 294 | var print1 = JSON.stringify(styleObj1, null, 4); 295 | var print2 = JSON.stringify(styleObj2, null, 4); 296 | console.log('Writing converted'); 297 | fs.appendFile(RESULT_PATH + '\\Result.JSON', ',\n' + print1); 298 | fs.appendFile(RESULT_PATH + '\\Result.JSON', ',\n' + print2); 299 | } else { 300 | var styleObj = make_JSON(name, convType, cssObj, minzoom, maxzoom); 301 | print = JSON.stringify(styleObj, null, 4); 302 | fs.appendFile(RESULT_PATH + '\\Result.JSON', ',\n' + print); 303 | } 304 | } catch (err) { 305 | //writes a file with all the sld-files with errors 306 | fs.appendFile(RESULT_PATH + '\\errorFiles.txt', file + '-' + name + '\n'); 307 | } 308 | } 309 | 310 | //this makes the layout of each mapbox-layout-object 311 | //name=file name, css is an object [cssName: cssValue]pairs, cssName is ie stroke, stroke-width 312 | function make_JSON(name, type, cssObj, minzoom, maxzoom) { 313 | var attr = getPaintAndLayoutAttr(cssObj); 314 | var paint = attr[0]; 315 | var layout = attr[1]; 316 | 317 | //Removing default-values, they are redundant 318 | if (Object.keys(paint).indexOf('fill-opacity') > -1) { 319 | if (paint['fill-opacity'] === 1) { 320 | delete paint['fill-opacity']; 321 | } 322 | } 323 | 324 | var styleObj = { 325 | 'id': type + '-' + name, 326 | 'type': type, 327 | 'source': 'norkart', 328 | 'source-layer': name, 329 | 'minzoom': maxzoom, 330 | 'maxzoom': minzoom, 331 | 'layout': layout, 332 | 'paint': paint 333 | }; 334 | if (!Object.keys(layout).length > 0) { //if no layout attributes 335 | delete styleObj['layout']; 336 | } 337 | return styleObj; 338 | } 339 | 340 | 341 | function getSymbolizersObj(symbTag, type, file) { 342 | //have to check all taggs in symbolizer 343 | var i; 344 | var cssObj = {}; 345 | for (i = 0; i < Object.keys(symbTag[0]).length; i++) { //for all tags under <-Symbolizer> 346 | var tagName = Object.keys(symbTag[0])[i]; 347 | if (VALID_ATTR_TAGS.indexOf(tagName) > -1) { //if tag exists in valid-array, eks Stroke 348 | 349 | //if values are not in the regular place 350 | if (DIFF_ATTR_TAG.indexOf(tagName) > -1 || 351 | ((tagName === 'Fill') && symbTag[0].Fill[0].GraphicFill !== undefined)) { 352 | var obj = getObjFromDiffAttr(tagName, type, symbTag, file); 353 | for (var key in obj) { 354 | cssObj[key] = obj[key]; 355 | } 356 | } else {//if common cssParameterTags 357 | //array with key-value pairs to add to cssObj 358 | var cssArray = getCssParameters(symbTag, tagName, type); 359 | var k; 360 | for (k = 0; k < cssArray.length; k++) { 361 | cssObj[cssArray[k][0]] = cssArray[k][1]; 362 | } 363 | } 364 | } else if (tagName !== undefined) { 365 | //console.log(tagName+" is not a valid attribute tag"); 366 | } 367 | } 368 | return cssObj; 369 | } 370 | 371 | function getCssParameters(symbTag, validAttrTag, type, outerTag) { 372 | var cssArr = []; 373 | if (outerTag === undefined) { 374 | var allCssArray = symbTag[0][validAttrTag][0]['CssParameter']; 375 | } else { 376 | var allCssArray = symbTag[0][outerTag][0][validAttrTag][0]['CssParameter']; 377 | } 378 | 379 | var nrOfCssTags = Object.keys(allCssArray).length; 380 | var j; 381 | for (j = 0; j < nrOfCssTags; j++) { //for all cssParameters 382 | var cssTag = allCssArray[j]; 383 | var conv = convert_css_parameter(cssTag, validAttrTag, type, outerTag); 384 | cssArr.push(conv); //array with arrays of cssName and cssValue 385 | } 386 | return cssArr; 387 | } 388 | 389 | //gets called if attribute-values are not placed as the rest and therefor needs 390 | //a different method the get the css-value 391 | function getObjFromDiffAttr(tagName, type, symbTag, file) { 392 | var obj = {}; 393 | if (tagName === 'Label') { 394 | obj = getLabelObj(tagName, type, symbTag, obj); 395 | } else if (tagName === 'Fill') { //some fill-attributes are defined differently than the rest 396 | obj['fill-image'] = 'SPRITE-NAME'; 397 | } else if (tagName === 'Halo') { 398 | obj = getHaloObj(tagName, type, symbTag, obj); 399 | } else if (tagName === 'Geometry') { 400 | obj = getGeometryObj(symbTag, obj); 401 | } else if (tagName === 'Graphic') { 402 | obj = getGraphicObj(file, symbTag, type, obj); 403 | } 404 | return obj; 405 | } 406 | 407 | function getLabelObj(tagName, type, symbTag, obj) { 408 | var convertedTagName = convertCssName(tagName, tagName, type); 409 | obj[convertedTagName] = '{' + symbTag[0].Label[0]['ogc:PropertyName'][0] + '}'; 410 | return obj; 411 | } 412 | 413 | function getHaloObj(tagName, type, symbTag, obj) { 414 | var j; 415 | for (j = 0; j < Object.keys(symbTag[0].Halo[0]).length; j++) { 416 | var innerTagName = (Object.keys(symbTag[0].Halo[0]))[j]; 417 | 418 | if (innerTagName === 'Radius') { 419 | var value = symbTag[0].Halo[0]['Radius'][0]['ogc:Literal'][0]; 420 | obj['text-halo-width'] = parseInt(value, 10); 421 | } else if (innerTagName === 'Fill') { 422 | //array with key-value pair to add in obj 423 | var cssArray = getCssParameters(symbTag, innerTagName, type, 'Halo'); 424 | var k; 425 | for (k = 0; k < cssArray.length; k++) { 426 | obj[cssArray[k][0]] = cssArray[k][1]; 427 | } 428 | } else { 429 | console.log('translation of: ' + innerTagName + ' is not added'); 430 | } 431 | } 432 | return obj; 433 | } 434 | 435 | function getGeometryObj(symbTag, obj) { 436 | if (symbTag[0].Geometry[0]['ogc:Function'][0].$.name === 'vertices') { 437 | obj['icon-image'] = PUNKT; 438 | } else { 439 | console.log('Cannot convert attribute value: ' + symbTag[0].Geometry[0]['ogc:Function'][0].$.name + ', for tag Geometry'); 440 | } 441 | return obj; 442 | } 443 | function getGraphicObj(file, symbTag, type, obj) { 444 | var fillColor; 445 | try { 446 | fillColor = symbTag[0].Graphic[0].Mark[0].Fill[0].CssParameter[0]['ogc:Function'][0]['ogc:Literal'][1]; 447 | var color = '#' + fillColor; 448 | var regInteger = /^\d+$/; 449 | if (!regInteger.test(fillColor)) { 450 | //console.log('Different graphic tag: '+fillColor+ ' from file: '+ file); 451 | } else { 452 | obj['icon-color'] = color; 453 | } 454 | } catch (err) { 455 | console.log('Could not set fill color for graphic tag in file: ' + file); 456 | } 457 | //Sets size 458 | try { 459 | var size = symbTag[0].Graphic[0].Size[0]; 460 | obj['icon-size'] = parseInt(size, 10); 461 | } catch (err) { 462 | console.log('Size does not exist in this graphic-tag'); 463 | } 464 | var img = getIconImage(file); 465 | if (img !== undefined) { 466 | obj['icon-image'] = img; 467 | } else { 468 | obj['icon-image'] = 'circle-12'; 469 | } 470 | return obj; 471 | } 472 | 473 | function getIconImage(file) { 474 | try { 475 | var img = CONV_ICON_IMG[file]; 476 | } catch (err) { 477 | console.log('Unknown icon'); 478 | img = undefined; 479 | } 480 | return img; 481 | } 482 | 483 | //returns an array with css parameter name and value, correctly converted 484 | //validAttrTag=name of outer tag, example stroke, fill, label 485 | function convert_css_parameter(cssTag, ValidAttrTag, type, outerTag) { 486 | var cssName = cssTag['$'].name; 487 | var cssValue; 488 | var regLetters = /^[a-zA-Z]+$/; 489 | var regInt = /^\d+$/; 490 | var regDouble = /^[0-9]+([\,\.][0-9]+)?$/g; 491 | var regNumbers = /^\d+$/; 492 | 493 | try { 494 | var cssColorValue = cssTag['_'].split('#')[1]; 495 | //testing if the value is a color: 496 | if ((DIFF_ATTR.indexOf(cssName)) > -1 497 | && !(regInt.test(cssTag['_'])) 498 | && !(regDouble.test(cssTag['_'])) 499 | && !regLetters.test(cssColorValue) 500 | && !regNumbers.test(cssColorValue) ) {//Check if different type of attribute 501 | cssValue = (cssTag['ogc:Function'][0]['ogc:Literal'][1]); 502 | } else { 503 | cssValue = cssTag['_']; 504 | } 505 | } catch (err) { 506 | if ((DIFF_ATTR.indexOf(cssName)) > -1 507 | && !(regInt.test(cssTag['_'])) 508 | && !(regDouble.test(cssTag['_']))) {//Check if different type of attribute 509 | cssValue = (cssTag['ogc:Function'][0]['ogc:Literal'][1]); 510 | } else { 511 | cssValue = cssTag['_']; 512 | } 513 | } 514 | var convertedCssName = convertCssName(cssName, ValidAttrTag, type, outerTag); 515 | var convertedCssValue = convertCssValue(cssValue, cssName); 516 | return [convertedCssName, convertedCssValue]; 517 | } 518 | 519 | //Makes sure the attribute values are returned in the correct type and defined 520 | //correctly (ie colors with a # in front) 521 | function convertCssValue(cssValue, cssName) { 522 | 523 | //linejoin describes rendering with values; mitre/round/bevel 524 | if ((cssName === 'stroke' || cssName === 'stroke-linejoin' || cssName === 'stroke-linecap')) { 525 | //some colors are defined with #, others not. 526 | //Split removes the # if it exists, so i always end up with the color value without the # 527 | //linecap is a line-border with values; butt/round/square 528 | return '#' + cssValue.split('#')[cssValue.split('#').length - 1]; 529 | } 530 | 531 | if (cssName === 'stroke-width' 532 | || cssName === 'stroke-opacity' 533 | || cssName === 'stroke--dashoffset') { 534 | return parseFloat(cssValue); 535 | } 536 | if (cssName === 'stroke-dasharray') { 537 | return cssValue.split(' ').map(Number); 538 | } 539 | 540 | if (cssName === 'fill') { 541 | //some colors are defined with #, others not. Split removes the # if it exists, 542 | //so i always end up with the color value without the # 543 | return '#' + cssValue.split('#')[cssValue.split('#').length - 1]; 544 | } 545 | 546 | if (cssName === 'opacity' || cssName === 'fill-opacity') { 547 | return parseFloat(cssValue); 548 | } 549 | 550 | if (cssName === 'font-size') { 551 | return parseFloat(cssValue); 552 | } 553 | 554 | return cssValue; 555 | 556 | } 557 | 558 | function convertCssName(cssName, validAttrTag, type, outerTag) { 559 | var newName; 560 | if (cssName === 'fill' 561 | || cssName === 'fill-opacity' 562 | || cssName === 'opacity' 563 | && validAttrTag === 'Fill') { 564 | if (outerTag === undefined) { 565 | newName = CONVERT_ATTR_NAME[type + '-' + validAttrTag + '-' + cssName]; 566 | 567 | } else { 568 | var newName = CONVERT_ATTR_NAME[type + '-' + outerTag + '-' + validAttrTag + '-' + cssName]; 569 | if (newName === undefined) { 570 | console.log( 571 | 'could not convert the attribute name: ' + type + '-' + 572 | outerTag + '-' + validAttrTag + '-' + cssName 573 | ); 574 | } 575 | } 576 | return newName; 577 | } else { 578 | var newName = CONVERT_ATTR_NAME[cssName]; 579 | //List to print those I know cannot be translated 580 | var ACCEPTED = ['font-weight', 'font-style']; 581 | //skip printing the ones I know are not translated 582 | if (newName === undefined && ACCEPTED.indexOf(newName) > -1) { 583 | console.log('could not convert the attribute name: ' + cssName); 584 | } 585 | return newName; 586 | } 587 | } 588 | 589 | function convertType(type) { 590 | try { 591 | return CONV_TYPE[type]; 592 | } catch (err) { 593 | console.log('could not convert the type: ' + type); 594 | } 595 | } 596 | 597 | //Makes paint object og layout object 598 | function getPaintAndLayoutAttr(cssObj) { 599 | var paint = {}; 600 | var layout = {}; 601 | var i; 602 | for (i = 0; i < Object.keys(cssObj).length; i++) {// for all in cssObj 603 | var key = Object.keys(cssObj)[i];//becomes line-color 604 | var value = cssObj[key]; 605 | if (PAINT_ATTR.indexOf(key) > -1) { 606 | paint[key] = value; 607 | } else if (LAYOUT_ATTR.indexOf(key) > -1) { 608 | layout[key] = value; 609 | } else { 610 | console.log('The css-key: ' + key + ', is not a valid paint or layout attribute'); 611 | } 612 | } 613 | return [paint, layout]; 614 | } 615 | -------------------------------------------------------------------------------- /exampleData/FKB_ElvBekk.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | FKB_ElvBekk 10 | 11 | FKB_ElvBekk 12 | 13 | 14 | 15 | 16 | FKB_ElvBekk_midtlinje 17 | 18 | 19 | 20 | geometritype 21 | 3 22 | 23 | 24 | 25 | 26 | medium 27 | U 28 | 29 | 30 | 31 | medium 32 | 33 | 34 | 35 | 36 | 1 37 | 8501 38 | 39 | 40 | 41 | # 42 | aebm 43 | 87BEF1 44 | 45 | 46 | 0.1 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | FKB_ElvBekk_flate 56 | 57 | 58 | 59 | geometritype 60 | 10 61 | 62 | 63 | 64 | 65 | medium 66 | U 67 | 68 | 69 | 70 | medium 71 | 72 | 73 | 74 | 75 | 1 76 | 8501 77 | 78 | 79 | 80 | # 81 | aff 82 | B2D8FA 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /exampleData/Skyggefiler.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "fill-FKB_Bygning_1-Skygge", 3 | "type": "fill", 4 | "source": "norkart", 5 | "source-layer": "FKB_Bygning_1", 6 | "paint": { 7 | "fill-color": "#8c9398", 8 | "fill-opacity": 0.8, 9 | "fill-translate": [2, 2] 10 | } 11 | }, 12 | { 13 | "id": "fill-FKB_Bygning_2-Skygge", 14 | "type": "fill", 15 | "source": "norkart", 16 | "source-layer": "FKB_Bygning_2", 17 | "paint": { 18 | "fill-color": "#8c9398", 19 | "fill-opacity": 0.8, 20 | "fill-translate": [2, 2] 21 | } 22 | }, 23 | { 24 | "id": "fill-FKB_Bygning_3-Skygge", 25 | "type": "fill", 26 | "source": "norkart", 27 | "source-layer": "FKB_Bygning_3", 28 | "paint": { 29 | "fill-color": "#8c9398", 30 | "fill-opacity": 0.8, 31 | "fill-translate": [2, 2] 32 | } 33 | }, 34 | -------------------------------------------------------------------------------- /exampleMultipleLayers/FKB_ElvBekk 2.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | FKB_ElvBekk 10 | 11 | FKB_ElvBekk 12 | 13 | 14 | 15 | 16 | FKB_ElvBekk_midtlinje 17 | 18 | 19 | 20 | geometritype 21 | 3 22 | 23 | 24 | 25 | 26 | medium 27 | U 28 | 29 | 30 | 31 | medium 32 | 33 | 34 | 35 | 36 | 1 37 | 8501 38 | 39 | 40 | 41 | # 42 | aebm 43 | 87BEF1 44 | 45 | 46 | 0.1 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | FKB_ElvBekk_flate 56 | 57 | 58 | 59 | geometritype 60 | 10 61 | 62 | 63 | 64 | 65 | medium 66 | U 67 | 68 | 69 | 70 | medium 71 | 72 | 73 | 74 | 75 | 1 76 | 8501 77 | 78 | 79 | 80 | # 81 | aff 82 | B2D8FA 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /exampleMultipleLayers/FKB_ElvBekk 3.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | FKB_ElvBekk 10 | 11 | FKB_ElvBekk 12 | 13 | 14 | 15 | 16 | FKB_ElvBekk_midtlinje 17 | 18 | 19 | 20 | geometritype 21 | 3 22 | 23 | 24 | 25 | 26 | medium 27 | U 28 | 29 | 30 | 31 | medium 32 | 33 | 34 | 35 | 36 | 1 37 | 8501 38 | 39 | 40 | 41 | # 42 | aebm 43 | 87BEF1 44 | 45 | 46 | 0.1 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | FKB_ElvBekk_flate 56 | 57 | 58 | 59 | geometritype 60 | 10 61 | 62 | 63 | 64 | 65 | medium 66 | U 67 | 68 | 69 | 70 | medium 71 | 72 | 73 | 74 | 75 | 1 76 | 8501 77 | 78 | 79 | 80 | # 81 | aff 82 | B2D8FA 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /exampleMultipleLayers/FKB_ElvBekk 4.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | FKB_ElvBekk 10 | 11 | FKB_ElvBekk 12 | 13 | 14 | 15 | 16 | FKB_ElvBekk_midtlinje 17 | 18 | 19 | 20 | geometritype 21 | 3 22 | 23 | 24 | 25 | 26 | medium 27 | U 28 | 29 | 30 | 31 | medium 32 | 33 | 34 | 35 | 36 | 1 37 | 8501 38 | 39 | 40 | 41 | # 42 | aebm 43 | 87BEF1 44 | 45 | 46 | 0.1 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | FKB_ElvBekk_flate 56 | 57 | 58 | 59 | geometritype 60 | 10 61 | 62 | 63 | 64 | 65 | medium 66 | U 67 | 68 | 69 | 70 | medium 71 | 72 | 73 | 74 | 75 | 1 76 | 8501 77 | 78 | 79 | 80 | # 81 | aff 82 | B2D8FA 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /exampleMultipleLayers/FKB_ElvBekk.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | FKB_ElvBekk 10 | 11 | FKB_ElvBekk 12 | 13 | 14 | 15 | 16 | FKB_ElvBekk_midtlinje 17 | 18 | 19 | 20 | geometritype 21 | 3 22 | 23 | 24 | 25 | 26 | medium 27 | U 28 | 29 | 30 | 31 | medium 32 | 33 | 34 | 35 | 36 | 1 37 | 8501 38 | 39 | 40 | 41 | # 42 | aebm 43 | 87BEF1 44 | 45 | 46 | 0.1 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | FKB_ElvBekk_flate 56 | 57 | 58 | 59 | geometritype 60 | 10 61 | 62 | 63 | 64 | 65 | medium 66 | U 67 | 68 | 69 | 70 | medium 71 | 72 | 73 | 74 | 75 | 1 76 | 8501 77 | 78 | 79 | 80 | # 81 | aff 82 | B2D8FA 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /images/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Norkart/SLDexit/76ddb0c04af934cd6c239160867eda0f35a9fb85/images/diagram.png -------------------------------------------------------------------------------- /images/forsekningskurver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Norkart/SLDexit/76ddb0c04af934cd6c239160867eda0f35a9fb85/images/forsekningskurver.png -------------------------------------------------------------------------------- /images/mapbox-forsenkningskurve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Norkart/SLDexit/76ddb0c04af934cd6c239160867eda0f35a9fb85/images/mapbox-forsenkningskurve.png -------------------------------------------------------------------------------- /images/sld-forsenkningskurve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Norkart/SLDexit/76ddb0c04af934cd6c239160867eda0f35a9fb85/images/sld-forsenkningskurve.png -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2016, Norkart AS 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are 6 | permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of 9 | conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 | of conditions and the following disclaimer in the documentation and/or other materials 13 | provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 16 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 18 | COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 22 | TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sld_to_mapboxgl", 3 | "version": "1.0.0", 4 | "description": "Script to convert from SLD (Styled Layer Descriptor) to Mapbox Style Specification", 5 | "main": "SLD_to_JSON.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/Norkart/SLD_to_MapboxGL.git" 12 | }, 13 | "author": "Mathilde Ørstavik", 14 | "license": "BSD-2-Clause", 15 | "bugs": { 16 | "url": "https://github.com/Norkart/SLD_to_MapboxGL/issues" 17 | }, 18 | "homepage": "https://github.com/Norkart/SLD_to_MapboxGL#readme", 19 | "dependencies": { 20 | "underscore": "^1.8.3", 21 | "xml2js": "^0.4.17" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /reorder/create_correct_layerorder.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var _us = require('underscore'); 3 | 4 | var json_file_name = "json-test.json"; //original json file 5 | var ordering_file_name = "layers_ordering.txt"; // file containing 6 | var output_filename = "json_style_ordered.json"; // name of the output file 7 | 8 | function main() { 9 | var json_original_style = JSON.parse(fs.readFileSync(json_file_name, 'utf8')); 10 | var ordering_file = fs.readFileSync(ordering_file_name, 'utf8'); 11 | 12 | if (ordering_file.indexOf('\r\n') !== -1) { 13 | ordering_list = ordering_file.split('\r\n'); 14 | } 15 | else { 16 | ordering_list = ordering_file.split('\n'); 17 | } 18 | 19 | if (ordering_list[ordering_list.length-1] === "") { // last line is usualy empty 20 | ordering_list.splice(ordering_list.length - 1, ordering_list.length) 21 | } 22 | 23 | var json_ordered_style = { 24 | "version": json_original_style.version, 25 | "name": json_original_style.name, 26 | "sources": json_original_style.sources, 27 | "glyphs": json_original_style.glyphs, 28 | "sprite": json_original_style.sprite, 29 | "layers":[] 30 | }; 31 | // console.log(JSON.stringify(json_ordered_style,null,2)); 32 | 33 | for (var i = 0; i < ordering_list.length; i++) { 34 | json_ordered_style.layers.push(get_layer_by_id(json_original_style, ordering_list[i])); 35 | } 36 | // add min max zoom for testing once.. 37 | 38 | fs.writeFileSync(output_filename, JSON.stringify(json_ordered_style, null, 2)); // resets file 39 | 40 | console.log("Is in same order as " + ordering_file_name + ": " +check_order(ordering_list, output_filename)); 41 | } 42 | 43 | 44 | function check_order(order,created_file) { 45 | var json_created = JSON.parse(fs.readFileSync(created_file, 'utf8')); 46 | 47 | for (var i = 0; i < order.length; i++) { 48 | if (order[i] !== json_created.layers[i].id) { 49 | return false; 50 | } 51 | } 52 | return true; 53 | } 54 | 55 | function get_layer_by_id(json, layerid) { 56 | var i; 57 | for(i=0; i < json.layers.length; i++){ 58 | // console.log(json.layers[i].id + "(" + json.layers[i].id.length + ")"); 59 | // console.log(layerid + "(" + layerid.length + ")"); 60 | 61 | if (json.layers[i].id === layerid){ 62 | return json.layers[i]; 63 | } 64 | } 65 | throw {name:"cantFindLayer", message:("can't find the wanted layerid: " + layerid)}; 66 | } 67 | 68 | main(); 69 | -------------------------------------------------------------------------------- /reorder/layers_ordering.txt: -------------------------------------------------------------------------------- 1 | background 2 | fill-FKB_ArealressursFlate_bebyggelse 3 | line-FKB_ArealressursFlate_bebyggelse 4 | fill-FKB_ArealressursFlate_fulldyrka 5 | line-FKB_ArealressursFlate_fulldyrka 6 | fill-FKB_ArealressursFlate_overflatedyrka 7 | line-FKB_ArealressursFlate_overflatedyrka 8 | fill-FKB_ArealressursFlate_innmarksbeite 9 | line-FKB_ArealressursFlate_innmarksbeite 10 | fill-FKB_ArealressursFlate_skog 11 | line-FKB_ArealressursFlate_skog 12 | fill-FKB_ArealressursFlate_aapen_fastmark 13 | line-FKB_ArealressursFlate_aapen_fastmark 14 | fill-FKB_ArealressursFlate_myr 15 | fill-FKB_Havflate 16 | line-FKB_Havflate 17 | fill-FKB_Flytebrygge 18 | line-FKB_FlytebryggeKant 19 | line-FKB_ElvBekk_midtlinje 20 | fill-FKB_ElvBekk_flate 21 | line-FKB_ElvBekkKant 22 | line-FKB_ElveforbygningsKant 23 | fill-FKB_Dam 24 | line-FKB_DamKant 25 | fill-FKB_Innsjoe 26 | line-FKB_InnsjoekantRegulert 27 | line-FKB_Innsjoekant 28 | fill-FKB_SnoeIsbre 29 | line-FKB_SnoeIsbreKant 30 | line-FKB_Jernbane-close 31 | line-FKB_Jernbane 32 | line-FKB_T-Bane 33 | line-FKB_Trikk 34 | line-FKB_Jernbane_Tunnel 35 | line-FKB_T-Bane_Tunnel 36 | line-WAM_Teig 37 | fill-FKB_Alpinbakke 38 | fill-FKB_Campingplass 39 | fill-FKB_Fundament_2 40 | fill-FKB_Fundament_1 41 | fill-FKB_Fyllplass 42 | fill-FKB_Golfbane 43 | fill-FKB_Gravplass 44 | fill-FKB_Grustak 45 | fill-FKB_Gruve 46 | fill-FKB_Industriomraade 47 | fill-FKB_KanalGroeft_flate 48 | fill-FKB_Leirtak 49 | fill-FKB_Lekeplass 50 | fill-FKB_Park 51 | fill-FKB_Parkeringsomraade 52 | fill-FKB_PblTiltak_1 53 | fill-FKB_PblTiltak_2 54 | fill-FKB_PblTiltak_2-2 55 | fill-FKB_PblTiltak_3 56 | fill-FKB_PblTiltak_3-2 57 | fill-FKB_Pipe_2 58 | fill-FKB_Pipe_1 59 | fill-FKB_Rasteplass 60 | fill-FKB_Silo_1 61 | fill-FKB_Silo_2 62 | fill-FKB_Skytebane 63 | fill-FKB_SportIdrettPlass 64 | fill-FKB_Stein-1 65 | fill-FKB_Stein-2 66 | fill-FKB_Steinbrudd 67 | fill-FKB_Steintipp 68 | fill-FKB_Svoemmebasseng 69 | fill-FKB_Tank_1 70 | fill-FKB_Tank_2 71 | fill-FKB_Toemmervelte 72 | fill-FKB_Torvtak 73 | fill-FKB_Trafikkoey 74 | line-FKB_Aak_1 75 | line-FKB_Aak_2 76 | line-FKB_Alle_1 77 | line-FKB_Alle_2 78 | line-FKB_AnnetGjerde 79 | line-FKB_AnnetGjerde_2 80 | line-FKB_BautaStatueGrense 81 | line-FKB_Fasadeliv_1 82 | line-FKB_Fasadeliv_2 83 | line-FKB_Fasadeliv_3 84 | line-FKB_FiktivBygningsavgrensning 85 | line-FKB_Floetningsrenne 86 | line-FKB_FlomloepKant 87 | line-FKB_FundamentKant_1 88 | line-FKB_FundamentKant_2 89 | line-FKB_Grunnmur_1 90 | line-FKB_Grunnmur_2 91 | line-FKB_Grunnmur_3 92 | line-FKB_Hekk_1 93 | line-FKB_Hoppbakke 94 | line-FKB_Idrettsanlegg 95 | line-FKB_Jernbaneplattformkant_1 96 | line-FKB_Jernbaneplattformkant_2 97 | line-FKB_KaiBryggeKant 98 | line-FKB_KanalGroeft_midtlinje_1 99 | line-FKB_KanalGroeft_midtlinje_2 100 | line-FKB_KanalGroeftKant 101 | line-FKB_Kontaktledningsaak_1 102 | line-FKB_Kontaktledningsaak_2 103 | line-FKB_Kulvert_1 104 | line-FKB_Kulvert_2 105 | line-FKB_Kystkontur 106 | line-FKB_KystkonturTekniskAnlegg 107 | line-FKB_Laavebru 108 | line-FKB_LuftledningHSP_1 109 | line-FKB_LuftledningHSP_2 110 | line-FKB_LuftledningHSP_3 111 | line-FKB_LuftledningHSP_4 112 | line-FKB_Lysloeype 113 | line-FKB_Masteomriss_Telemast 114 | line-FKB_MastTeleGrense 115 | line-FKB_MoloKant 116 | line-FKB_MurFrittstaaende_1 117 | line-FKB_MurFrittstaaende_2 118 | line-FKB_MurLodrett_1 119 | line-FKB_MurLodrett_2 120 | line-FKB_MurLodrettTverr_1 121 | line-FKB_MurLodrettTverr_2 122 | line-FKB_NettstasjonGr 123 | line-FKB_Nettverkstasjonomriss_EL_Nettstasjon 124 | line-FKB_Nettverkstasjonomriss_EL_Vindturbin 125 | line-FKB_OperativArealavgrensning 126 | line-FKB_Oppdrettskar 127 | line-FKB_OppdrettsmerderKant 128 | line-FKB_ParkeringsomraadeAvgrensning 129 | line-FKB_PblTiltakGrense_1 130 | line-FKB_PblTiltakGrense_2 131 | line-FKB_PblTiltakGrense_3 132 | line-FKB_PipeKant_1 133 | line-FKB_PipeKant_2 134 | line-FKB_Plattformgrense 135 | line-FKB_Portrom_1 136 | line-FKB_Portrom_2 137 | line-FKB_Rullebanegrense 138 | line-FKB_Roergate 139 | line-FKB_Sandkasse_1 140 | line-FKB_Sandkasse_2 141 | line-FKB_SiloKant_1 142 | line-FKB_SiloKant_2 143 | line-FKB_Skiltportal_1 144 | line-FKB_Skiltportal_2 145 | line-FKB_Skitrekk 146 | line-FKB_Skjerm_stoey 147 | line-FKB_Skjerm_snoe 148 | line-FKB_Skjerm_ras 149 | line-FKB_Skjerm_vind 150 | line-FKB_Skjerm_le 151 | line-FKB_Skjerm_lede 152 | line-FKB_Skjerm_flom 153 | line-FKB_SkraaForstoetningsmurAvgrensning_1 154 | line-FKB_SkraaForstoetningsmurAvgrensning_2 155 | line-FKB_Skytebaneinnretning 156 | line-FKB_Skytefelt 157 | line-FKB_Slipp 158 | line-FKB_Steingjerde_1 159 | line-FKB_Steingjerde_2 160 | line-FKB_SteinOmriss_1 161 | line-FKB_SteinOmriss_2 162 | line-FKB_Sti 163 | line-FKB_Stikkrenne_1 164 | line-FKB_Stikkrenne_2 165 | line-FKB_Stolheis 166 | line-FKB_SvoemmebassengKant 167 | line-FKB_Sykkelfelt_1 168 | line-FKB_Sykkelfelt_2 169 | line-FKB_Taksebanegrense 170 | line-FKB_TankKant_1 171 | line-FKB_TankKant_2 172 | line-FKB_Taubane 173 | line-FKB_Trase_LuftledningHSP_1 174 | line-FKB_Trase_LuftledningHSP_2 175 | line-FKB_Trase_LuftledningHSP_3 176 | line-FKB_Trase_LuftledningHSP_4 177 | line-FKB_Tunnellportal 178 | line-FKB_VindkraftverkGr 179 | symbol-FKB_BautaStatue_1 180 | symbol-FKB_BautaStatue_2 181 | symbol-FKB_Bensinpumpe_1 182 | symbol-FKB_Bensinpumpe_2 183 | symbol-FKB_EL_Belysningspunkt_IMast_1 184 | symbol-FKB_EL_Belysningspunkt_IMast_2 185 | symbol-FKB_EL_Belysningspunkt_IMast_3 186 | symbol-FKB_EL_Nettstasjon-minikiosk 187 | symbol-FKB_EL_Vindturbin_1 188 | symbol-FKB_EL_Vindturbin_2 189 | symbol-FKB_Flaggstang_1 190 | symbol-FKB_Flaggstang_2 191 | symbol-FKB_Floetningsrenne 192 | symbol-FKB_Fordelingsskap_1 193 | symbol-FKB_Fordelingsskap_2 194 | symbol-FKB_Fortoeyningskar_1 195 | symbol-FKB_Fortoeyningskar_2 196 | symbol-FKB_Gravplass 197 | symbol-FKB_Gondolbane 198 | symbol-FKB_Hydrant_1 199 | symbol-FKB_Hydrant_2 200 | symbol-FKB_InnmaaltTre_1 201 | symbol-FKB_InnmaaltTre_2 202 | symbol-FKB_Kum_1 203 | symbol-FKB_Kum_2 204 | symbol-FKB_MastTele_1 205 | symbol-FKB_MastTele_2 206 | symbol-FKB_MastVeilys_2 207 | symbol-FKB_MastVeilys_1 208 | symbol-FKB_MastVeilys_3 209 | symbol-FKB_Mast_EL_2 210 | symbol-FKB_Mast_EL_1 211 | symbol-FKB_Mast_EL_3 212 | symbol-FKB_Mast_Signalmast_1 213 | symbol-FKB_Mast_Signalmast_2 214 | symbol-FKB_Mast_Telemast_1 215 | symbol-FKB_Mast_Telemast_2 216 | symbol-FKB_NettstasjonKiosk 217 | symbol-FKB_Portstolpe_1 218 | symbol-FKB_Portstolpe_2 219 | symbol-FKB_Signalmast_1 220 | symbol-FKB_Signalmast_2 221 | symbol-FKB_Skap_1 222 | symbol-FKB_Skap_2 223 | symbol-FKB_Skiltportal_1 224 | symbol-FKB_Skiltportal_2 225 | symbol-FKB_Skitrekk 226 | symbol-FKB_Skjaer_1 227 | symbol-FKB_Skjaer_2 228 | symbol-FKB_Sluk_1 229 | symbol-FKB_Sluk_2 230 | symbol-FKB_Stolheis 231 | symbol-FKB_StolpeEnkel_1 232 | symbol-FKB_StolpeEnkel_2 233 | symbol-FKB_StolpeEnkel_3 234 | symbol-FKB_Taubane 235 | symbol-FKB_Terrengpunkt 236 | symbol-FKB_Toppunkt 237 | symbol-FKB_Trafikksignalpunkt_1 238 | symbol-FKB_Trafikksignalpunkt_2 239 | symbol-FKB_Vindkraftverk_1 240 | symbol-FKB_Vindkraftverk_2 241 | symbol-FKB_Broenn_1 242 | symbol-FKB_Broenn_2 243 | line-FKB_Hoeydekurve_1 244 | line-FKB_Hoeydekurve_2 245 | line-FKB_Forsenkningskurve_1 246 | line-FKB_Forsenkningskurve_2 247 | fill-FKB_FrittstaaendeTrapp_1 248 | fill-FKB_FrittstaaendeTrapp_2 249 | fill-FKB_GangSykkelveg 250 | fill-FKB_Europaveg 251 | fill-FKB_Riksveg 252 | fill-FKB_Fylkesveg 253 | fill-FKB_Andreveger 254 | fill-FKB_Traktorveg 255 | fill-FKB_GangSykkelveg_Bro 256 | fill-FKB_Traktorveg_Bro 257 | fill-FKB_Parkeringsomraade_bro 258 | fill-FKB_Riksveg_bro 259 | fill-FKB_Fylkesveg_bro 260 | fill-FKB_Andreveger_bro 261 | fill-FKB_Trafikkoey_bro 262 | line-FKB_GangfeltAvgrensning_1 263 | line-FKB_GangfeltAvgrensning_2 264 | line-FKB_GangSykkelvegkant 265 | line-FKB_Gangvegkant 266 | line-FKB_Gondolbane 267 | line-FKB_Trafikkoeykant 268 | line-FKB_FrittstaaendeTrappKant_1 269 | line-FKB_FrittstaaendeTrappKant_2 270 | line-FKB_Europaveg 271 | line-FKB_Riksveg 272 | line-FKB_Fylkesveg 273 | line-FKB_Andreveger 274 | line-FKB_VeggFrittstaaende_1 275 | line-FKB_VeggFrittstaaende_2 276 | line-FKB_VegkantAnnetVegareal_1 277 | line-FKB_VegkantAnnetVegareal_2 278 | line-FKB_VegkantAvkjoersel 279 | line-FKB_Veglenke_Lysloeype 280 | line-FKB_Veglenke_Sti 281 | line-FKB_Veglenke_Traktorveg 282 | line-FKB_Vegrekkverk_1 283 | line-FKB_Vegrekkverk_2 284 | line-FKB_Vegsperring 285 | line-FKB_Traktorveg 286 | line-FKB_TraktorvegKant 287 | line-FKB_Fortauskant 288 | line-FKB_FortauskantYtre 289 | line-FKB_AnnetVegarealAvgrensning 290 | line-FKB_Vegdekkekant 291 | fill-FKB_GangSykkelveg_Bro 292 | fill-FKB_Traktorveg_Bro 293 | fill-FKB_Parkeringsomraade_bro 294 | fill-FKB_Riksveg_bro 295 | fill-FKB_Andreveger_bro 296 | line-FKB_FortauskantYtre_Bro 297 | line-FKB_Fortauskant_Bro 298 | line-FKB_GangfeltAvgrensning_Bro_1 299 | line-FKB_GangSykkelvegkant_Bro 300 | line-FKB_Gangvegkant_Bro 301 | line-FKB_Lysloeype_Bro 302 | line-FKB_ParkeringsomraadeAvgrensning_Bro 303 | line-FKB_Jernbane_Bro 304 | line-FKB_T-Bane_Bro 305 | line-FKB_Trikk_Bro 306 | line-FKB_Sykkelfelt_Bro_1 307 | line-FKB_Sykkelfelt_Bro_2 308 | line-FKB_TraktorvegKant_Bro 309 | fill-FKB_Trafikkoey_bro 310 | line-FKB_Traktorveg_Bro 311 | fill-FKB_Fylkesveg_bro 312 | fill-FKB_Europaveg_bro 313 | line-FKB_BroennGrense_1 314 | line-FKB_BroennGrense_2 315 | line-FKB_Veglenke_Lysloeype_Bro 316 | line-FKB_Veglenke_Sti_Bro 317 | line-FKB_Veglenke_Traktorveg_Bro 318 | line-FKB_Vegrekkverk_Bro_1 319 | line-FKB_Vegrekkverk_Bro_2 320 | line-FKB_GangfeltAvgrensning_bro_2 321 | line-FKB_Sti_bro 322 | line-FKB_Trafikkoeykant_bro 323 | line-FKB_Vegdekkekant_bro 324 | line-FKB_VegkantAnnetVegareal_bro_2 325 | line-FKB_VegkantAnnetVegareal_bro_1 326 | line-FKB_VegkantAvkjoersel_bro 327 | line-FKB_Europaveg_bro 328 | line-FKB_Riksveg_bro 329 | line-FKB_Fylkesveg_bro 330 | line-FKB_Andreveger_bro 331 | line-FKB_Bruavgrensning 332 | line-FKB_AnnetVegarealAvgrensning_Bro 333 | fill-FKB_Bygning_1-Skygge 334 | fill-FKB_Bygning_2-Skygge 335 | fill-FKB_Bygning_3-Skygge 336 | fill-FKBBSK_Skygge_Bygg-1 337 | fill-FKBBSK_Skygge_Bygg-2 338 | fill-FKB_Tribune 339 | fill-FKB_Bygning_1 340 | fill-FKB_Bygning_2 341 | fill-FKB_Bygning_3 342 | fill-FKB_Taarn-flate 343 | fill-FKB_AnnenBygning_1 344 | fill-FKB_AnnenBygning_2 345 | fill-FKB_AnnenBygning_3 346 | fill-FKB_Takoverbygg_1 347 | fill-FKB_Takoverbygg_2 348 | fill-FKB_Takoverbygg_3 349 | fill-FKBBSK_Takflate_omriss-Lysvinkel_3d_1 350 | fill-FKBBSK_Takflate_omriss-Lysvinkel_3d_1-2 351 | fill-FKBBSK_Takflate_omriss-Lysvinkel_3d_2 352 | fill-FKBBSK_Takflate_omriss-Lysvinkel_3d_2-2 353 | fill-FKBBSK_Takflate_omriss-Lysvinkel_3d_3 354 | fill-FKBBSK_Takflate_omriss-Lysvinkel_3d_3-2 355 | fill-FKBBSK_Takflate_omriss-Lysvinkel_3d_4 356 | fill-FKBBSK_Takflate_omriss-Lysvinkel_3d_4-2 357 | line-FKB_AnnenBygning_1 358 | line-FKB_AnnenBygning_2 359 | line-FKB_AnnenBygning_3 360 | line-FKB_TrappBygg_1 361 | line-FKB_TrappBygg_2 362 | line-FKB_Bygning_1 363 | line-FKB_Bygning_2 364 | line-FKB_Bygning_3 365 | line-FKB_Bygning_3 366 | line-FKB_TribuneKant 367 | line-FKB_Veranda_1 368 | line-FKB_Veranda_2 369 | line-FKB_BygningBru_1 370 | line-FKB_BygningBru_2 371 | line-FKB_Bygningsdelelinje 372 | line-FKB_Taksprang_1 373 | line-FKB_Taksprang_2 374 | line-FKB_TaarnKant 375 | line-FKB_Takplataa_1 376 | line-FKB_Takplataa_2 377 | line-FKB_TakplataaTopp_1 378 | line-FKB_TakplataaTopp_2 379 | line-FKB_Takkant_1 380 | line-FKB_Takkant_2 381 | line-FKB_Takkant_3 382 | line-FKBBSK_Takflate_flate_1 383 | line-FKBBSK_Takflate_flate_2 384 | line-FKB_TakoverbyggKant_1 385 | line-FKB_TakoverbyggKant_2 386 | line-FKB_TakoverbyggKant_3 387 | line-FKB_Bygningslinje_1 388 | line-FKB_Bygningslinje_2 389 | line-FKB_Moenelinje_1 390 | line-FKB_Moenelinje_2 391 | symbol-FKB_Forsenkningspunkt 392 | symbol-FKB_Taarn-punkt 393 | symbol-Europaveg 394 | symbol-Riksveg 395 | symbol-Fylkesveg 396 | symbol-Andre_veger 397 | symbol-Europavegnummer 398 | symbol-Riksvegnummer 399 | symbol-Riksveg_Fylkesvegummer_901 400 | symbol-FLYPL_Flyplass 401 | symbol-WAM_Adresse_1 402 | symbol-WAM_Adresse_2 403 | symbol-WAM_Adresse_3 404 | symbol-WAM_Adresse_4 405 | symbol-WAM_Adresse_5 406 | symbol-WAM_GIDText_1 407 | symbol-WAM_GIDText_2 408 | symbol-WAM_GIDText_3 409 | symbol-WAM_GIDText_4 410 | symbol-FKB_PresAnnenTekst_Punkt 411 | symbol-FKB_PresAnnenTekst_Linje 412 | symbol-FKB_PresHoydetallVann 413 | symbol-FKB_PresHoydetallPunkt_7501 414 | symbol-FKB_PresHoydetallPunkt_3601 415 | symbol-FKB_PresHoydetallPunkt_1801 416 | symbol-FKB_PresStedsnavn_Terrengdetalj 417 | symbol-FKB_PresStedsnavn_Kyst_StorSkrift 418 | symbol-FKB_PresStedsnavn_Terrengform_StorSkrift 419 | symbol-FKB_PresStedsnavn_Terrengform_LitenSkrift 420 | symbol-FKB_PresStedsnavn_Terrengform_Hoyre 421 | symbol-FKB_PresStedsnavn_Kyst_LitenSkrift 422 | symbol-FKB_PresStedsnavn_Vann_StorSkrift 423 | symbol-FKB_PresStedsnavn_Vann_LitenSkrift 424 | symbol-FKB_PresStedsnavn_Vann-LandObj_Hoyre 425 | symbol-FKB_PresStedsnavn_Grustak 426 | symbol-FKB_PresStedsnavn_Myrer 427 | symbol-FKB_PresStedsnavn_Bebyggelse_StorSkrift 428 | symbol-FKB_PresStedsnavn_Bebyggelse_MiddelsSkrift 429 | symbol-FKB_PresStedsnavn_Bebyggelse_LitenSkrift 430 | symbol-FKB_PresStedsnavn_Garder 431 | symbol-FKB_PresStedsnavn_HusHytteSeter 432 | symbol-FKB_PresStedsnavn_BergverkIndustri 433 | symbol-FKB_PresStedsnavn_Samferdsel 434 | symbol-FKB_PresStedsnavn_AndreAdmOmr 435 | symbol-FKB_PresStedsnavn_Andre 436 | --------------------------------------------------------------------------------