From 050f72b44378bc2a13aec9033b00c86cec863c99 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Wed, 22 Feb 2012 09:55:45 +0100 Subject: [PATCH 1/8] start on a GeoServer profile for SLD --- lib/OpenLayers.js | 1 + lib/OpenLayers/Format/SLD.js | 9 ++ lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js | 142 ++++++++++++++++++ tests/Format/SLD/v1_0_0_GeoServer.html | 88 +++++++++++ tests/list-tests.html | 1 + 5 files changed, 241 insertions(+) create mode 100644 lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js create mode 100644 tests/Format/SLD/v1_0_0_GeoServer.html diff --git a/lib/OpenLayers.js b/lib/OpenLayers.js index 78b35da424..360c7868d1 100644 --- a/lib/OpenLayers.js +++ b/lib/OpenLayers.js @@ -287,6 +287,7 @@ "OpenLayers/Format/SLD.js", "OpenLayers/Format/SLD/v1.js", "OpenLayers/Format/SLD/v1_0_0.js", + "OpenLayers/Format/SLD/v1_0_0_GeoServer.js", "OpenLayers/Format/OWSCommon.js", "OpenLayers/Format/OWSCommon/v1.js", "OpenLayers/Format/OWSCommon/v1_0_0.js", diff --git a/lib/OpenLayers/Format/SLD.js b/lib/OpenLayers/Format/SLD.js index 20e8abf79f..2149b0a516 100644 --- a/lib/OpenLayers/Format/SLD.js +++ b/lib/OpenLayers/Format/SLD.js @@ -23,6 +23,15 @@ */ OpenLayers.Format.SLD = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { + /** + * APIProperty: profile + * {String} If provided, use a custom profile. + * + * Currently supported profiles: + * - GeoServer - parses GeoServer vendor specific capabilities for SLD. + */ + profile: null, + /** * APIProperty: defaultVersion * {String} Version number to assume if none found. Default is "1.0.0". diff --git a/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js b/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js new file mode 100644 index 0000000000..663db29d37 --- /dev/null +++ b/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js @@ -0,0 +1,142 @@ +/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the Clear BSD license. + * See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/SLD/v1_0_0.js + */ + +/** + * Class: OpenLayers.Format.SLD/v1_0_0_GeoServer + * Read SLD version 1.0.0 with GeoServer-specific enhanced options. + * See http://svn.osgeo.org/geotools/trunk/modules/extension/xsd/xsd-sld/src/main/resources/org/geotools/sld/bindings/StyledLayerDescriptor.xsd + * + * Inherits from: + * - + */ +OpenLayers.Format.SLD.v1_0_0_GeoServer = OpenLayers.Class( + OpenLayers.Format.SLD.v1_0_0, { + + /** + * Property: version + * {String} The specific parser version. + */ + version: "1.0.0", + + /** + * Property: profile + * {String} The specific profile + */ + profile: "GeoServer", + + /** + * Constructor: OpenLayers.Format.SLD.v1_0_0_GeoServer + * Create a new parser for GeoServer-enhanced SLD version 1.0.0. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * Property: readers + * Contains public functions, grouped by namespace prefix, that will + * be applied when a namespaced node is found matching the function + * name. The function will be applied in the scope of this parser + * with two arguments: the node being read and a context object passed + * from the parent. + */ + readers: { + "sld": OpenLayers.Util.applyDefaults({ + "Priority": function(node, obj) { + var value = this.readers.ogc._expression.call(this, node); + if (value) { + obj.priority = value; + } + }, + "VendorOption": function(node, obj) { + if (!obj.vendorOptions) { + obj.vendorOptions = []; + } + obj.vendorOptions.push({ + name: node.getAttribute("name"), + value: this.getChildValue(node) + }); + } + }, OpenLayers.Format.SLD.v1_0_0.prototype.readers["sld"]), + "ogc": OpenLayers.Format.SLD.v1_0_0.prototype.readers["ogc"] + }, + + /** + * Property: writers + * As a compliment to the readers property, this structure contains public + * writing functions grouped by namespace alias and named like the + * node names they produce. + */ + writers: { + "sld": OpenLayers.Util.applyDefaults({ + "Priority": function(priority) { + return this.writers.sld._OGCExpression.call( + this, "sld:Priority", priority + ); + }, + "VendorOption": function(option) { + return this.createElementNSPlus("sld:VendorOption", { + attributes: {name: option.name}, + value: option.value + }); + }, + "TextSymbolizer": function(symbolizer) { + var node = OpenLayers.Format.SLD.v1_0_0.prototype.writers["sld"]["TextSymbolizer"].apply(this, arguments); + if (symbolizer.externalGraphic || symbolizer.graphicName) { + this.writeNode("Graphic", symbolizer, node); + } + if ("priority" in symbolizer) { + this.writeNode("Priority", symbolizer.priority, node); + } + var options = symbolizer.vendorOptions; + if (options) { + for (var i=0, ii=options.length; i + + + + + +
+ + diff --git a/tests/list-tests.html b/tests/list-tests.html index 1421c2b6dc..92ebdec19a 100644 --- a/tests/list-tests.html +++ b/tests/list-tests.html @@ -73,6 +73,7 @@
  • Format/Text.html
  • Format/SLD.html
  • Format/SLD/v1_0_0.html
  • +
  • Format/SLD/v1_0_0_GeoServer.html
  • Format/Filter.html
  • Format/Filter/v1.html
  • Format/Filter/v1_0_0.html
  • From b2f95bd537dca45e52eb0cb6135474eaa01809cc Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Wed, 22 Feb 2012 11:03:48 +0100 Subject: [PATCH 2/8] TextSymbolizer->Fill->CssParameter['fill'] should map to fontColor instead --- lib/OpenLayers/Format/SLD/v1.js | 17 +++++++++++++---- tests/Format/SLD/v1_0_0.html | 4 ++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/OpenLayers/Format/SLD/v1.js b/lib/OpenLayers/Format/SLD/v1.js index be1ce6effd..0780c8d163 100644 --- a/lib/OpenLayers/Format/SLD/v1.js +++ b/lib/OpenLayers/Format/SLD/v1.js @@ -338,6 +338,10 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { "CssParameter": function(node, symbolizer) { var cssProperty = node.getAttribute("name"); var symProperty = this.cssMap[cssProperty]; + // for labels, fill should map to the fontColor + if (symbolizer.label && cssProperty === 'fill') { + symProperty = "fontColor"; + } if(symProperty) { // Limited support for parsing of OGC expressions var value = this.readers.ogc._expression.call(this, node); @@ -862,10 +866,15 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { return node; }, "CssParameter": function(obj) { + var name = this.getCssProperty(obj.key); + var value = obj.symbolizer[obj.key]; + if (obj.symbolizer.label && name === 'fill') { + value = obj.symbolizer.fontColor; + } // not handling ogc:expressions for now return this.createElementNSPlus("sld:CssParameter", { - attributes: {name: this.getCssProperty(obj.key)}, - value: obj.symbolizer[obj.key] + attributes: {name: name}, + value: value }); }, "TextSymbolizer": function(symbolizer) { @@ -888,7 +897,7 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { this.writeNode("Halo", symbolizer, node); } // add in optional Fill - if(symbolizer.fillColor != null || + if(symbolizer.fontColor != null || symbolizer.fillOpacity != null) { this.writeNode("Fill", symbolizer, node); } @@ -1004,7 +1013,7 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { // GraphicFill here // add in CssParameters - if(symbolizer.fillColor) { + if(symbolizer.fillColor || (symbolizer.label && symbolizer.fontColor)) { this.writeNode( "CssParameter", {symbolizer: symbolizer, key: "fillColor"}, diff --git a/tests/Format/SLD/v1_0_0.html b/tests/Format/SLD/v1_0_0.html index a31ba6a5f3..98f4cd161b 100644 --- a/tests/Format/SLD/v1_0_0.html +++ b/tests/Format/SLD/v1_0_0.html @@ -177,7 +177,7 @@ t.eq(text.label, "A ${FOO} label", "(AAA161) first rule has proper text label"); t.eq(layer.userStyles[0].propertyStyles["label"], true, "label added to propertyStyles"); t.eq(text.fontFamily, "Arial", "(AAA161) first rule has proper font family"); - t.eq(text.fillColor, "#000000", "(AAA161) first rule has proper text fill"); + t.eq(text.fontColor, "#000000", "(AAA161) first rule has proper text fill"); t.eq(text.haloRadius, "3", "(AAA161) first rule has proper halo radius"); t.eq(text.haloColor, "#ffffff", "(AAA161) first rule has proper halo color"); @@ -347,7 +347,7 @@ "label": "This is the ${city} in ${state}.", "fontFamily": "Arial", "fontSize": 10, - "fillColor": "blue", + "fontColor": "blue", "fontWeight": "bold", "fontStyle": "normal", "haloRadius": 2, From 82a8602b45f9b033e6458b029b1b5aa8630c5b6e Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Wed, 22 Feb 2012 11:50:37 +0100 Subject: [PATCH 3/8] use a more clean way to achieve the same --- lib/OpenLayers/Format/SLD/v1.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/OpenLayers/Format/SLD/v1.js b/lib/OpenLayers/Format/SLD/v1.js index 0780c8d163..e23a14d995 100644 --- a/lib/OpenLayers/Format/SLD/v1.js +++ b/lib/OpenLayers/Format/SLD/v1.js @@ -866,15 +866,10 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { return node; }, "CssParameter": function(obj) { - var name = this.getCssProperty(obj.key); - var value = obj.symbolizer[obj.key]; - if (obj.symbolizer.label && name === 'fill') { - value = obj.symbolizer.fontColor; - } // not handling ogc:expressions for now return this.createElementNSPlus("sld:CssParameter", { - attributes: {name: name}, - value: value + attributes: {name: this.getCssProperty(obj.key)}, + value: obj.symbolizer[obj.key] }); }, "TextSymbolizer": function(symbolizer) { @@ -899,7 +894,9 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { // add in optional Fill if(symbolizer.fontColor != null || symbolizer.fillOpacity != null) { - this.writeNode("Fill", symbolizer, node); + this.writeNode("Fill", { + fillColor: symbolizer.fontColor + }, node); } return node; }, @@ -1013,7 +1010,7 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { // GraphicFill here // add in CssParameters - if(symbolizer.fillColor || (symbolizer.label && symbolizer.fontColor)) { + if(symbolizer.fillColor) { this.writeNode( "CssParameter", {symbolizer: symbolizer, key: "fillColor"}, From f0cb98a9bf969007018c0c81820e48e6d967cd26 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Wed, 22 Feb 2012 11:57:42 +0100 Subject: [PATCH 4/8] a bit of restructuring, also making sure that a Graphic in a TextSymbolizer can be read and written (this is a GeoServer extension to produce e.g. highway shields) --- lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js | 65 ++++++++++--------- tests/Format/SLD/v1_0_0_GeoServer.html | 12 ++++ 2 files changed, 45 insertions(+), 32 deletions(-) diff --git a/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js b/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js index 663db29d37..dc77fc5387 100644 --- a/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js +++ b/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js @@ -88,55 +88,56 @@ OpenLayers.Format.SLD.v1_0_0_GeoServer = OpenLayers.Class( }); }, "TextSymbolizer": function(symbolizer) { - var node = OpenLayers.Format.SLD.v1_0_0.prototype.writers["sld"]["TextSymbolizer"].apply(this, arguments); + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; + var node = writers["sld"]["TextSymbolizer"].apply(this, arguments); if (symbolizer.externalGraphic || symbolizer.graphicName) { this.writeNode("Graphic", symbolizer, node); } if ("priority" in symbolizer) { this.writeNode("Priority", symbolizer.priority, node); } - var options = symbolizer.vendorOptions; - if (options) { - for (var i=0, ii=options.length; i #000000 + + + square + + #59BF34 + + + #2D6917 + + + 24 + population From d4e0947f1a299c8a727a70da2ef05b298038ad16 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Wed, 22 Feb 2012 12:18:56 +0100 Subject: [PATCH 5/8] even though the parsing and writing is the same for all VendorOption tags, add a more complete list in the test SLD --- tests/Format/SLD/v1_0_0_GeoServer.html | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/Format/SLD/v1_0_0_GeoServer.html b/tests/Format/SLD/v1_0_0_GeoServer.html index 94defbfe93..c396ec61ce 100644 --- a/tests/Format/SLD/v1_0_0_GeoServer.html +++ b/tests/Format/SLD/v1_0_0_GeoServer.html @@ -88,7 +88,19 @@ population 60 + true + 300 150 + false + 3 + stretch + yes + 10 + true + 15 + false + 0.3 + mbr From 941f3c0913b44701822bd0271cc70c61f453b9ea Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Wed, 22 Feb 2012 12:23:20 +0100 Subject: [PATCH 6/8] change comment to highlight it's both read and write --- lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js b/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js index dc77fc5387..50275e5d32 100644 --- a/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js +++ b/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js @@ -9,9 +9,10 @@ /** * Class: OpenLayers.Format.SLD/v1_0_0_GeoServer - * Read SLD version 1.0.0 with GeoServer-specific enhanced options. + * Read and write SLD version 1.0.0 with GeoServer-specific enhanced options. * See http://svn.osgeo.org/geotools/trunk/modules/extension/xsd/xsd-sld/src/main/resources/org/geotools/sld/bindings/StyledLayerDescriptor.xsd - * + * for more information. + * * Inherits from: * - */ From 7fb62b69333c0cf748d562d8f42340389d48c564 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Wed, 22 Feb 2012 16:18:41 +0100 Subject: [PATCH 7/8] more complete inheritance of readers and writers --- lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js b/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js index 50275e5d32..49596be1c4 100644 --- a/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js +++ b/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js @@ -48,7 +48,7 @@ OpenLayers.Format.SLD.v1_0_0_GeoServer = OpenLayers.Class( * with two arguments: the node being read and a context object passed * from the parent. */ - readers: { + readers: OpenLayers.Util.applyDefaults({ "sld": OpenLayers.Util.applyDefaults({ "Priority": function(node, obj) { var value = this.readers.ogc._expression.call(this, node); @@ -65,9 +65,8 @@ OpenLayers.Format.SLD.v1_0_0_GeoServer = OpenLayers.Class( value: this.getChildValue(node) }); } - }, OpenLayers.Format.SLD.v1_0_0.prototype.readers["sld"]), - "ogc": OpenLayers.Format.SLD.v1_0_0.prototype.readers["ogc"] - }, + }, OpenLayers.Format.SLD.v1_0_0.prototype.readers["sld"]) + }, OpenLayers.Format.SLD.v1_0_0.prototype.readers), /** * Property: writers @@ -75,7 +74,7 @@ OpenLayers.Format.SLD.v1_0_0_GeoServer = OpenLayers.Class( * writing functions grouped by namespace alias and named like the * node names they produce. */ - writers: { + writers: OpenLayers.Util.applyDefaults({ "sld": OpenLayers.Util.applyDefaults({ "Priority": function(priority) { return this.writers.sld._OGCExpression.call( @@ -114,9 +113,8 @@ OpenLayers.Format.SLD.v1_0_0_GeoServer = OpenLayers.Class( var node = writers["sld"]["PolygonSymbolizer"].apply(this, arguments); return this.addVendorOptions(node, symbolizer); } - }, OpenLayers.Format.SLD.v1_0_0.prototype.writers["sld"]), - "ogc": OpenLayers.Format.SLD.v1_0_0.prototype.writers["ogc"] - }, + }, OpenLayers.Format.SLD.v1_0_0.prototype.writers["sld"]) + }, OpenLayers.Format.SLD.v1_0_0.prototype.writers), /** * Method: addVendorOptions From 2e69d681022a86cf7733ff4697ee2a24fbf18266 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Thu, 23 Feb 2012 15:55:40 +0100 Subject: [PATCH 8/8] map fill-opacity in TextSymbolizer to fontOpacity --- lib/OpenLayers/Format/SLD/v1.js | 16 +++++++++++----- tests/Format/SLD/v1_0_0_GeoServer.html | 4 +++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/OpenLayers/Format/SLD/v1.js b/lib/OpenLayers/Format/SLD/v1.js index e23a14d995..a6fe969c4a 100644 --- a/lib/OpenLayers/Format/SLD/v1.js +++ b/lib/OpenLayers/Format/SLD/v1.js @@ -338,9 +338,14 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { "CssParameter": function(node, symbolizer) { var cssProperty = node.getAttribute("name"); var symProperty = this.cssMap[cssProperty]; - // for labels, fill should map to the fontColor - if (symbolizer.label && cssProperty === 'fill') { - symProperty = "fontColor"; + // for labels, fill should map to fontColor and fill-opacity + // to fontOpacity + if (symbolizer.label) { + if (cssProperty === 'fill') { + symProperty = "fontColor"; + } else if (cssProperty === 'fill-opacity') { + symProperty = "fontOpacity"; + } } if(symProperty) { // Limited support for parsing of OGC expressions @@ -893,9 +898,10 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { } // add in optional Fill if(symbolizer.fontColor != null || - symbolizer.fillOpacity != null) { + symbolizer.fontOpacity != null) { this.writeNode("Fill", { - fillColor: symbolizer.fontColor + fillColor: symbolizer.fontColor, + fillOpacity: symbolizer.fontOpacity }, node); } return node; diff --git a/tests/Format/SLD/v1_0_0_GeoServer.html b/tests/Format/SLD/v1_0_0_GeoServer.html index c396ec61ce..bfe9b3ec4a 100644 --- a/tests/Format/SLD/v1_0_0_GeoServer.html +++ b/tests/Format/SLD/v1_0_0_GeoServer.html @@ -71,12 +71,14 @@ #000000 + 0.5 square - #59BF34 + #59BF34 + 0.8 #2D6917