diff --git a/lib/OpenLayers/Format/Filter/v1.js b/lib/OpenLayers/Format/Filter/v1.js index 76b0c5743f..dfc3bc6829 100644 --- a/lib/OpenLayers/Format/Filter/v1.js +++ b/lib/OpenLayers/Format/Filter/v1.js @@ -77,6 +77,27 @@ OpenLayers.Format.Filter.v1 = OpenLayers.Class(OpenLayers.Format.XML, { */ readers: { "ogc": { + "_expression": function(node) { + // only the simplest of ogc:expression handled + // "some text and an attribute"} + var obj, value = ""; + for(var child=node.firstChild; child; child=child.nextSibling) { + switch(child.nodeType) { + case 1: + obj = this.readNode(child); + if (obj.property) { + value += "${" + obj.property + "}"; + } else if (obj.value !== undefined) { + value += obj.value; + } + break; + case 3: // text node + case 4: // cdata section + value += child.nodeValue; + } + } + return value; + }, "Filter": function(node, parent) { // Filters correspond to subclasses of OpenLayers.Filter. // Since they contain information we don't persist, we @@ -166,11 +187,11 @@ OpenLayers.Format.Filter.v1 = OpenLayers.Class(OpenLayers.Format.XML, { }, "LowerBoundary": function(node, filter) { filter.lowerBoundary = OpenLayers.String.numericIf( - this.readOgcExpression(node)); + this.readers.ogc._expression.call(this, node)); }, "UpperBoundary": function(node, filter) { filter.upperBoundary = OpenLayers.String.numericIf( - this.readOgcExpression(node)); + this.readers.ogc._expression.call(this, node)); }, "Intersects": function(node, obj) { this.readSpatial(node, obj, OpenLayers.Filter.Spatial.INTERSECTS); @@ -218,26 +239,6 @@ OpenLayers.Format.Filter.v1 = OpenLayers.Class(OpenLayers.Format.XML, { obj.filters.push(filter); }, - /** - * Method: readOgcExpression - * Limited support for OGC expressions. - * - * Parameters: - * node - {DOMElement} A DOM element that contains an ogc:expression. - * - * Returns: - * {String} A value to be used in a symbolizer. - */ - readOgcExpression: function(node) { - var obj = {}; - this.readChildNodes(node, obj); - var value = obj.value; - if(value === undefined) { - value = this.getChildValue(node); - } - return value; - }, - /** * Method: writeOgcExpression * Limited support for writing OGC expressions. Currently it supports diff --git a/lib/OpenLayers/Format/SLD/v1.js b/lib/OpenLayers/Format/SLD/v1.js index 8f9f39d903..5003a3d08f 100644 --- a/lib/OpenLayers/Format/SLD/v1.js +++ b/lib/OpenLayers/Format/SLD/v1.js @@ -219,16 +219,9 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { } }, "Label": function(node, symbolizer) { - // only supporting literal or property name - var obj = {}; - this.readChildNodes(node, obj); - if(obj.property) { - symbolizer.label = "${" + obj.property + "}"; - } else { - var value = this.readOgcExpression(node); - if(value) { - symbolizer.label = value; - } + var value = this.readers.ogc._expression.call(this, node); + if (value) { + symbolizer.label = value; } }, "Font": function(node, symbolizer) { @@ -243,7 +236,7 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { symbolizer.haloOpacity = obj.fillOpacity; }, "Radius": function(node, symbolizer) { - var radius = this.readOgcExpression(node); + var radius = this.readers.ogc._expression.call(this, node); if(radius != null) { // radius is only used for halo symbolizer.haloRadius = radius; @@ -345,7 +338,7 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { var symProperty = this.cssMap[cssProperty]; if(symProperty) { // Limited support for parsing of OGC expressions - var value = this.readOgcExpression(node); + var value = this.readers.ogc._expression.call(this, node); // always string, could be an empty string if(value) { symbolizer[symProperty] = value; @@ -376,7 +369,13 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { symbolizer.graphicOpacity = graphic.opacity; } if(graphic.size != undefined) { - symbolizer.pointRadius = graphic.size / 2; + var pointRadius = graphic.size / 2; + if (isNaN(pointRadius)) { + // likely a property name + symbolizer.graphicWidth = graphic.size; + } else { + symbolizer.pointRadius = graphic.size / 2; + } } if(graphic.href != undefined) { symbolizer.externalGraphic = graphic.href; @@ -395,21 +394,21 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { graphic.graphicName = this.getChildValue(node); }, "Opacity": function(node, obj) { - var opacity = this.readOgcExpression(node); + var opacity = this.readers.ogc._expression.call(this, node); // always string, could be empty string if(opacity) { obj.opacity = opacity; } }, "Size": function(node, obj) { - var size = this.readOgcExpression(node); + var size = this.readers.ogc._expression.call(this, node); // always string, could be empty string if(size) { obj.size = size; } }, "Rotation": function(node, obj) { - var rotation = this.readOgcExpression(node); + var rotation = this.readers.ogc._expression.call(this, node); // always string, could be empty string if(rotation) { obj.rotation = rotation; @@ -530,6 +529,36 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { */ writers: OpenLayers.Util.applyDefaults({ "sld": { + "_OGCExpression": function(nodeName, value) { + // only the simplest of ogc:expression handled + // {label: "some text and a ${propertyName}"} + var node = this.createElementNSPlus(nodeName); + var tokens = typeof value == "string" ? + value.split("${") : + [value]; + node.appendChild(this.createTextNode(tokens[0])); + var item, last; + for(var i=1, len=tokens.length; i 0) { + this.writeNode( + "ogc:PropertyName", + {property: item.substring(0, last)}, + node + ); + node.appendChild( + this.createTextNode(item.substring(++last)) + ); + } else { + // no ending }, so this is a literal ${ + node.appendChild( + this.createTextNode("${" + item) + ); + } + } + return node; + }, "StyledLayerDescriptor": function(sld) { var root = this.createElementNSPlus( "sld:StyledLayerDescriptor", @@ -897,32 +926,9 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { return node; }, "Label": function(label) { - // only the simplest of ogc:expression handled - // {label: "some text and a ${propertyName}"} - var node = this.createElementNSPlus("sld:Label"); - var tokens = label.split("${"); - node.appendChild(this.createTextNode(tokens[0])); - var item, last; - for(var i=1, len=tokens.length; i 0) { - this.writeNode( - "ogc:PropertyName", - {property: item.substring(0, last)}, - node - ); - node.appendChild( - this.createTextNode(item.substring(++last)) - ); - } else { - // no ending }, so this is a literal ${ - node.appendChild( - this.createTextNode("${" + item) - ); - } - } - return node; + return this.writers.sld._OGCExpression.call( + this, "sld:Label", label + ); }, "Halo": function(symbolizer) { var node = this.createElementNSPlus("sld:Halo"); @@ -1030,6 +1036,8 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { } if(symbolizer.pointRadius != undefined) { this.writeNode("Size", symbolizer.pointRadius * 2, node); + } else if (symbolizer.graphicWidth != undefined) { + this.writeNode("Size", symbolizer.graphicWidth, node); } if(symbolizer.rotation != undefined) { this.writeNode("Rotation", symbolizer.rotation, node); @@ -1070,9 +1078,9 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { }); }, "Size": function(value) { - return this.createElementNSPlus("sld:Size", { - value: value - }); + return this.writers.sld._OGCExpression.call( + this, "sld:Size", value + ); }, "Rotation": function(value) { return this.createElementNSPlus("sld:Rotation", { diff --git a/tests/Format/SLD/v1_0_0.html b/tests/Format/SLD/v1_0_0.html index 8e2c0a238a..a31ba6a5f3 100644 --- a/tests/Format/SLD/v1_0_0.html +++ b/tests/Format/SLD/v1_0_0.html @@ -39,7 +39,7 @@ '' + '' + '' + '' + 'Arial' + @@ -121,6 +121,7 @@ '2' + '' + '' + + 'SIZE' + '' + '' + '' + @@ -130,7 +131,7 @@ ''; function test_read(t) { - t.plan(22); + t.plan(23); var xml = new OpenLayers.Format.XML(); var sldxml = xml.read(sld); @@ -173,7 +174,7 @@ t.eq(poly.fillColor, "#ffffff", "(AAA161) first rule has proper fill"); t.eq(poly.strokeColor, "#000000", "(AAA161) first rule has proper stroke"); var text = symbolizer["Text"]; - t.eq(text.label, "${FOO}", "(AAA161) first rule has proper text label"); + 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"); @@ -203,6 +204,12 @@ t.ok(typeof rule.maxScaleDenominator == "number", "MaxScaleDenominator is a number"); t.eq(rule.evaluate(feature), true, "numeric filter comparison evaluates correctly"); + // check for PropertyName size + layer = obj.namedLayers["Second Layer"]; + style = layer.userStyles[0]; + rule = style.rules[0]; + t.eq(rule.symbolizer["Point"].graphicWidth, "${SIZE}", "dynamic size correctly set on graphicWidth"); + // etc. I'm convinced read works, really wanted to test write (since examples don't test that) // I'll add more tests here later. @@ -211,7 +218,7 @@ function test_write(t) { t.plan(3); - // read first - testing that write produces the SLD aboce + // read first - testing that write produces the SLD above var parser = new OpenLayers.Format.SLD.v1_0_0(); var xml = new OpenLayers.Format.XML(); var sldxml = xml.read(sld);