Merge pull request #1130 from bartvde/sld3

Add Styled Layer Descriptor (SLD) version 1.0.0 parser (read/write) (r=@ahocevar)
This commit is contained in:
Bart van den Eijnden
2013-11-25 01:56:16 -08:00
14 changed files with 1420 additions and 1 deletions

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<sld:StyledLayerDescriptor xmlns="http://www.opengis.net/sld" xmlns:sld="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml" version="1.0.0">
<sld:NamedLayer>
<sld:Name>countries</sld:Name>
<sld:UserStyle>
<sld:Name>countries</sld:Name>
<sld:Title>A sample style for countries</sld:Title>
<sld:IsDefault>1</sld:IsDefault>
<sld:Abstract>A sample style for countries</sld:Abstract>
<sld:FeatureTypeStyle>
<sld:Name>name</sld:Name>
<sld:Rule>
<sld:Name>Sample</sld:Name>
<sld:Title>Sample</sld:Title>
<sld:PolygonSymbolizer>
<sld:Fill>
<sld:CssParameter name="fill">#ff0000</sld:CssParameter>
<sld:CssParameter name="fill-opacity">0.6</sld:CssParameter>
</sld:Fill>
<sld:Stroke>
<sld:CssParameter name="stroke">#00FF00</sld:CssParameter>
<sld:CssParameter name="stroke-opacity">0.5</sld:CssParameter>
<sld:CssParameter name="stroke-width">4</sld:CssParameter>
</sld:Stroke>
</sld:PolygonSymbolizer>
</sld:Rule>
<sld:Rule>
<sld:MaxScaleDenominator>20000000</sld:MaxScaleDenominator>
<sld:TextSymbolizer>
<sld:Label>
<ogc:PropertyName>name</ogc:PropertyName>
</sld:Label>
<sld:Font>
<sld:CssParameter name="font-family">Arial</sld:CssParameter>
<sld:CssParameter name="font-size">10</sld:CssParameter>
<sld:CssParameter name="font-style">Normal</sld:CssParameter>
</sld:Font>
</sld:TextSymbolizer>
</sld:Rule>
</sld:FeatureTypeStyle>
</sld:UserStyle>
</sld:NamedLayer>
</sld:StyledLayerDescriptor>

View File

@@ -0,0 +1,56 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
<link rel="stylesheet" href="../css/ol.css" type="text/css">
<link rel="stylesheet" href="../resources/bootstrap/css/bootstrap.min.css" type="text/css">
<link rel="stylesheet" href="../resources/layout.css" type="text/css">
<link rel="stylesheet" href="../resources/bootstrap/css/bootstrap-responsive.min.css" type="text/css">
<title>Vector layer with styling from SLD example</title>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="./">OpenLayers 3 Examples</a>
<ul class="nav pull-right">
<li><iframe class="github-watch-button" src="http://ghbtns.com/github-btn.html?user=openlayers&repo=ol3&type=watch&count=true"
allowtransparency="true" frameborder="0" scrolling="0" height="20" width="90"></iframe></li>
<li><a href="https://twitter.com/share" class="twitter-share-button" data-count="none" data-hashtags="openlayers">&nbsp;</a></li>
<li><div class="g-plusone-wrapper"><div class="g-plusone" data-size="medium" data-annotation="none"></div></div></li>
</ul>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<div id="map" class="map"></div>
</div>
</div>
<div class="row-fluid">
<div class="span4">
<h4 id="title">Vector layer example</h4>
<p id="shortdesc">Example of a countries vector layer with country labels at higher zoom levels, styling info coming from SLD.</p>
<div id="docs">
<p>See the <a href="vector-layer-sld.js" target="_blank">vector-layer-sld.js source</a> to see how this is done.</p>
</div>
<div id="tags">vector, geojson, style, SLD, Styled Layer Descriptor</div>
</div>
</div>
</div>
<script src="loader.js?id=vector-layer-sld" type="text/javascript"></script>
<script src="../resources/social-links.js" type="text/javascript"></script>
</body>
</html>

View File

@@ -0,0 +1,52 @@
goog.require('ol.Map');
goog.require('ol.RendererHint');
goog.require('ol.View2D');
goog.require('ol.control');
goog.require('ol.control.ScaleLine');
goog.require('ol.layer.Tile');
goog.require('ol.layer.Vector');
goog.require('ol.parser.GeoJSON');
goog.require('ol.parser.ogc.SLD');
goog.require('ol.source.MapQuestOpenAerial');
goog.require('ol.source.Vector');
var raster = new ol.layer.Tile({
source: new ol.source.MapQuestOpenAerial()
});
var xhr = new XMLHttpRequest();
xhr.open('GET', 'data/countries.sld', true);
/**
* onload handler for the XHR request.
*/
xhr.onload = function() {
if (xhr.status == 200) {
var map = new ol.Map({
controls: ol.control.defaults().extend([
new ol.control.ScaleLine()
]),
layers: [raster],
renderer: ol.RendererHint.CANVAS,
target: 'map',
view: new ol.View2D({
center: [0, 0],
zoom: 1
})
});
var units = map.getView().getProjection().getUnits();
var sld = new ol.parser.ogc.SLD().read(xhr.responseText, units);
var style = sld.namedLayers['countries'].userStyles[0];
var vector = new ol.layer.Vector({
source: new ol.source.Vector({
parser: new ol.parser.GeoJSON(),
url: 'data/countries.geojson'
}),
style: style
});
map.getLayers().push(vector);
}
};
xhr.send();

View File

@@ -583,6 +583,18 @@
* @todo stability experimental
*/
/**
* @typedef {Object} ol.parser.SLDReadOptions
* @property {ol.proj.Units} units The units to use in scale to resolution
* calculations.
*/
/**
* @typedef {Object} ol.parser.SLDWriteOptions
* @property {ol.proj.Units} units The units to use in resolution to scale
* calculations.
*/
/**
* @typedef {Object} ol.source.BingMapsOptions
* @property {string|undefined} culture Culture code. Default is `en-us`.
@@ -803,6 +815,8 @@
* a value is provided, the rule will apply at resolutions greater than or
* equal to this value.
* @property {Array.<ol.style.Symbolizer>|undefined} symbolizers Symbolizers.
* @property {string|undefined} name Name.
* @property {string|undefined} title Title.
* @todo stability experimental
*/
@@ -832,6 +846,8 @@
* @property {Array.<ol.style.Symbolizer>|undefined} symbolizers Symbolizers
* (that apply if no rules are provided or where none of the provided rules
* apply).
* @property {string|undefined} name Name.
* @property {string|undefined} title Title.
* @todo stability experimental
*/

View File

@@ -508,7 +508,14 @@ ol.parser.ogc.Filter_v1.prototype.write = function(filter) {
*/
ol.parser.ogc.Filter_v1.prototype.writeOgcExpression = function(expr, node) {
if (expr instanceof ol.expr.Call) {
if (ol.expr.isLibCall(expr) === ol.expr.functions.CONCAT) {
var args = expr.getArgs();
for (var i = 0, ii = args.length; i < ii; ++i) {
this.writeOgcExpression(args[i], node);
}
} else {
this.writeNode('Function', expr, null, node);
}
} else if (expr instanceof ol.expr.Literal) {
this.writeNode('Literal', expr, null, node);
} else if (expr instanceof ol.expr.Identifier) {

View File

@@ -0,0 +1,27 @@
goog.provide('ol.parser.ogc.SLD');
goog.require('ol.parser.ogc.SLD_v1_0_0');
goog.require('ol.parser.ogc.Versioned');
/**
* @define {boolean} Whether to enable SLD version 1.0.0.
*/
ol.ENABLE_SLD_1_0_0 = true;
/**
* @constructor
* @param {Object=} opt_options Options which will be set on this object.
* @extends {ol.parser.ogc.Versioned}
*/
ol.parser.ogc.SLD = function(opt_options) {
opt_options = opt_options || {};
opt_options['defaultVersion'] = '1.0.0';
this.parsers = {};
if (ol.ENABLE_SLD_1_0_0) {
this.parsers['v1_0_0'] = ol.parser.ogc.SLD_v1_0_0;
}
goog.base(this, opt_options);
};
goog.inherits(ol.parser.ogc.SLD, ol.parser.ogc.Versioned);

View File

@@ -0,0 +1,732 @@
goog.provide('ol.parser.ogc.SLD_v1');
goog.require('goog.asserts');
goog.require('goog.dom.xml');
goog.require('goog.object');
goog.require('ol.expr.Literal');
goog.require('ol.parser.XML');
goog.require('ol.parser.ogc.Filter_v1_0_0');
goog.require('ol.style.Fill');
goog.require('ol.style.Icon');
goog.require('ol.style.Rule');
goog.require('ol.style.Shape');
goog.require('ol.style.Stroke');
goog.require('ol.style.Style');
goog.require('ol.style.Text');
/**
* Read Styled Layer Descriptor (SLD).
*
* @constructor
* @extends {ol.parser.XML}
*/
ol.parser.ogc.SLD_v1 = function() {
this.defaultNamespaceURI = 'http://www.opengis.net/sld';
this.readers = {};
this.readers[this.defaultNamespaceURI] = {
'StyledLayerDescriptor': function(node, sld) {
sld.version = node.getAttribute('version');
this.readChildNodes(node, sld);
},
'Name': function(node, obj) {
obj.name = this.getChildValue(node);
},
'Title': function(node, obj) {
obj.title = this.getChildValue(node);
},
'Abstract': function(node, obj) {
obj.description = this.getChildValue(node);
},
'NamedLayer': function(node, sld) {
var layer = {
userStyles: [],
namedStyles: []
};
this.readChildNodes(node, layer);
sld.namedLayers[layer.name] = layer;
},
'NamedStyle': function(node, layer) {
layer.namedStyles.push(
this.getChildValue(node.firstChild)
);
},
'UserStyle': function(node, layer) {
var obj = {rules: []};
this.featureTypeCounter = -1;
this.readChildNodes(node, obj);
layer.userStyles.push(new ol.style.Style(obj));
},
'FeatureTypeStyle': function(node, style) {
++this.featureTypeCounter;
var obj = {
rules: style.rules
};
this.readChildNodes(node, obj);
},
'Rule': function(node, obj) {
var config = {symbolizers: []};
this.readChildNodes(node, config);
var rule = new ol.style.Rule(config);
obj.rules.push(rule);
},
'ElseFilter': function(node, rule) {
rule.elseFilter = true;
},
'MinScaleDenominator': function(node, rule) {
rule.minResolution = this.getResolutionFromScaleDenominator_(
parseFloat(this.getChildValue(node)));
},
'MaxScaleDenominator': function(node, rule) {
rule.maxResolution = this.getResolutionFromScaleDenominator_(
parseFloat(this.getChildValue(node)));
},
'TextSymbolizer': function(node, rule) {
var config = {};
this.readChildNodes(node, config);
config.color = goog.isDef(config.fill) ? config.fill.fillColor :
ol.parser.ogc.SLD_v1.defaults_.fontColor;
delete config.fill;
config.zIndex = this.featureTypeCounter;
rule.symbolizers.push(
new ol.style.Text(/** @type {ol.style.TextOptions} */(config))
);
},
'Label': function(node, symbolizer) {
var ogcreaders = this.readers[this.filter_.defaultNamespaceURI];
var value = ogcreaders._expression.call(this, node);
if (value) {
symbolizer.text = value;
}
},
'Font': function(node, symbolizer) {
this.readChildNodes(node, symbolizer);
},
'Halo': function(node, symbolizer) {
var obj = {};
this.readChildNodes(node, obj);
symbolizer.stroke = new ol.style.Stroke({
color: goog.isDef(obj.fill.fillColor) ? obj.fill.fillColor :
ol.parser.ogc.SLD_v1.defaults_.haloColor,
width: goog.isDef(obj.haloRadius) ? obj.haloRadius * 2 :
ol.parser.ogc.SLD_v1.defaults_.haloRadius,
opacity: goog.isDef(obj.fill.fillOpacity) ? obj.fill.fillOpacity :
ol.parser.ogc.SLD_v1.defaults_.haloOpacity
});
},
'Radius': function(node, symbolizer) {
var ogcreaders = this.readers[this.filter_.defaultNamespaceURI];
var radius = ogcreaders._expression.call(this, node);
goog.asserts.assertInstanceof(radius, ol.expr.Literal,
'radius expected to be an ol.expr.Literal');
if (goog.isDef(radius)) {
symbolizer.haloRadius = radius.getValue();
}
},
'LineSymbolizer': function(node, rule) {
var config = {};
this.readChildNodes(node, config);
config.zIndex = this.featureTypeCounter;
rule.symbolizers.push(
new ol.style.Stroke(config)
);
},
'PolygonSymbolizer': function(node, rule) {
var config = {};
this.readChildNodes(node, config);
config.zIndex = this.featureTypeCounter;
if (goog.isDef(config.fill)) {
var fill = {
color: config.fill.fillColor.getValue(),
opacity: goog.isDef(config.fill.fillOpacity) ?
config.fill.fillOpacity :
ol.parser.ogc.SLD_v1.defaults_.fillOpacity
};
rule.symbolizers.push(
new ol.style.Fill(fill)
);
delete config.fill;
}
if (goog.isDef(config.stroke)) {
var stroke = {
color: config.stroke.strokeColor.getValue(),
opacity: goog.isDef(config.stroke.strokeOpacity) ?
config.stroke.strokeOpacity :
ol.parser.ogc.SLD_v1.defaults_.strokeOpacity,
width: goog.isDef(config.stroke.strokeWidth) ?
config.stroke.strokeWidth :
ol.parser.ogc.SLD_v1.defaults_.strokeWidth
};
rule.symbolizers.push(
new ol.style.Stroke(stroke)
);
delete config.stroke;
}
},
'PointSymbolizer': function(node, rule) {
var config = {};
this.readChildNodes(node, config);
config.zIndex = this.featureTypeCounter;
if (config.fill) {
var fillConfig = {
color: goog.isDef(config.fill.fillColor) ?
config.fill.fillColor :
ol.parser.ogc.SLD_v1.defaults_.fillColor,
opacity: goog.isDef(config.fill.fillOpacity) ?
config.fill.fillOpacity :
ol.parser.ogc.SLD_v1.defaults_.fillOpacity
};
config.fill = new ol.style.Fill(fillConfig);
}
if (config.stroke) {
var strokeConfig = {
color: goog.isDef(config.stroke.strokeColor) ?
config.stroke.strokeColor :
ol.parser.ogc.SLD_v1.defaults_.strokeColor,
width: goog.isDef(config.stroke.strokeWidth) ?
config.stroke.strokeWidth :
ol.parser.ogc.SLD_v1.defaults_.strokeWidth,
opacity: goog.isDef(config.stroke.strokeOpacity) ?
config.stroke.strokeOpacity :
ol.parser.ogc.SLD_v1.defaults_.strokeOpacity
};
config.stroke = new ol.style.Stroke(strokeConfig);
}
var symbolizer;
if (goog.isDef(config.externalGraphic)) {
config.width = config.height = config.size;
symbolizer = new ol.style.Icon(
/** @type {ol.style.IconOptions} */(config));
} else {
symbolizer = new ol.style.Shape(config);
}
rule.symbolizers.push(symbolizer);
},
'Stroke': function(node, symbolizer) {
var stroke = {};
this.readChildNodes(node, stroke);
symbolizer.stroke = stroke;
},
'Fill': function(node, symbolizer) {
var fill = {};
this.readChildNodes(node, fill);
symbolizer.fill = fill;
},
'CssParameter': function(node, symbolizer) {
var cssProperty = node.getAttribute('name');
var symProperty = ol.parser.ogc.SLD_v1.cssMap_[cssProperty];
if (symProperty) {
var ogcreaders = this.readers[this.filter_.defaultNamespaceURI];
symbolizer[symProperty] = ogcreaders._expression.call(this, node);
}
},
'Graphic': function(node, symbolizer) {
var graphic = {};
// painter's order not respected here, clobber previous with next
this.readChildNodes(node, graphic);
// directly properties with names that match symbolizer properties
var properties = [
'stroke', 'fill', 'rotation', 'opacity'
];
var prop, value;
for (var i = 0, ii = properties.length; i < ii; ++i) {
prop = properties[i];
value = graphic[prop];
if (goog.isDef(value)) {
symbolizer[prop] = value;
}
}
// set other generic properties with specific graphic property names
if (goog.isDef(graphic.graphicName)) {
symbolizer.type = graphic.graphicName;
}
if (goog.isDef(graphic.size)) {
var pointRadius = graphic.size / 2;
if (isNaN(pointRadius)) {
// likely a property name
symbolizer.size = graphic.size;
} else {
symbolizer.size = graphic.size / 2;
}
}
if (goog.isDef(graphic.href)) {
symbolizer.url = graphic.href;
}
},
'ExternalGraphic': function(node, graphic) {
this.readChildNodes(node, graphic);
},
'Mark': function(node, graphic) {
this.readChildNodes(node, graphic);
},
'WellKnownName': function(node, graphic) {
graphic.graphicName = this.getChildValue(node);
},
'Opacity': function(node, obj) {
var ogcreaders = this.readers[this.filter_.defaultNamespaceURI];
obj.opacity = ogcreaders._expression.call(this, node);
},
'Size': function(node, obj) {
var ogcreaders = this.readers[this.filter_.defaultNamespaceURI];
obj.size = ogcreaders._expression.call(this, node);
},
'Rotation': function(node, obj) {
var ogcreaders = this.readers[this.filter_.defaultNamespaceURI];
obj.rotation = ogcreaders._expression.call(this, node);
},
'OnlineResource': function(node, obj) {
obj.href = this.getAttributeNS(
node, 'http://www.w3.org/1999/xlink', 'href'
);
},
'Format': function(node, graphic) {
graphic.graphicFormat = this.getChildValue(node);
}
};
this.writers = {};
this.writers[this.defaultNamespaceURI] = {
'StyledLayerDescriptor': function(sld) {
var node = this.createElementNS('sld:StyledLayerDescriptor');
node.setAttribute('version', this.version);
if (goog.isDef(sld.name)) {
this.writeNode('Name', sld.name, null, node);
}
if (goog.isDef(sld.title)) {
this.writeNode('Title', sld.title, null, node);
}
if (goog.isDef(sld.description)) {
this.writeNode('Abstract', sld.description, null, node);
}
goog.object.forEach(sld.namedLayers, function(layer) {
this.writeNode('NamedLayer', layer, null, node);
}, this);
return node;
},
'Name': function(name) {
var node = this.createElementNS('sld:Name');
node.appendChild(this.createTextNode(name));
return node;
},
'Title': function(title) {
var node = this.createElementNS('sld:Title');
node.appendChild(this.createTextNode(title));
return node;
},
'Abstract': function(description) {
var node = this.createElementNS('sld:Abstract');
node.appendChild(this.createTextNode(description));
return node;
},
'NamedLayer': function(layer) {
var node = this.createElementNS('sld:NamedLayer');
this.writeNode('Name', layer.name, null, node);
var i, ii;
if (layer.namedStyles) {
for (i = 0, ii = layer.namedStyles.length; i < ii; ++i) {
this.writeNode('NamedStyle', layer.namedStyles[i], null, node);
}
}
if (layer.userStyles) {
for (i = 0, ii = layer.userStyles.length; i < ii; ++i) {
this.writeNode('UserStyle', layer.userStyles[i], null, node);
}
}
return node;
},
'NamedStyle': function(name) {
var node = this.createElementNS('sld:NamedStyle');
this.writeNode('Name', name, null, node);
return node;
},
'UserStyle': function(style) {
var node = this.createElementNS('sld:UserStyle');
var name = style.getName(), title = style.getTitle();
if (goog.isDef(name)) {
this.writeNode('Name', name, null, node);
}
if (goog.isDef(title)) {
this.writeNode('Title', title, null, node);
}
// TODO sorting by zIndex
this.writeNode('FeatureTypeStyle', style, null, node);
return node;
},
'FeatureTypeStyle': function(style) {
var node = this.createElementNS('sld:FeatureTypeStyle');
var rules = style.getRules();
for (var i = 0, ii = rules.length; i < ii; ++i) {
this.writeNode('Rule', rules[i], null, node);
}
var symbolizers = style.getSymbolizers();
if (symbolizers.length > 0) {
// wrap this in a Rule with an ElseFilter
var rule = new ol.style.Rule({symbolizers: symbolizers});
rule.elseFilter = true;
this.writeNode('Rule', rule, null, node);
}
return node;
},
'Rule': function(rule) {
var node = this.createElementNS('sld:Rule');
var filter = rule.getFilter();
var name = rule.getName(), title = rule.getTitle();
if (goog.isDef(name)) {
this.writeNode('Name', name, null, node);
}
if (goog.isDef(title)) {
this.writeNode('Title', title, null, node);
}
if (rule.elseFilter === true) {
this.writeNode('ElseFilter', null, null, node);
} else if (filter) {
this.writeNode('Filter', filter, this.filter_.defaultNamespaceURI,
node);
}
var minResolution = rule.getMinResolution();
if (minResolution > 0) {
this.writeNode('MinScaleDenominator',
this.getScaleDenominatorFromResolution_(minResolution),
null, node);
}
var maxResolution = rule.getMaxResolution();
if (maxResolution < Infinity) {
this.writeNode('MaxScaleDenominator',
this.getScaleDenominatorFromResolution_(maxResolution),
null, node);
}
var type, symbolizer, symbolizers = rule.getSymbolizers();
if (symbolizers) {
for (var i = 0, ii = symbolizers.length; i < ii; ++i) {
symbolizer = symbolizers[i];
if (symbolizer instanceof ol.style.Text) {
type = 'Text';
} else if (symbolizer instanceof ol.style.Stroke) {
type = 'Line';
} else if (symbolizer instanceof ol.style.Fill) {
type = 'Polygon';
} else if (symbolizer instanceof ol.style.Shape ||
symbolizer instanceof ol.style.Icon) {
type = 'Point';
}
if (goog.isDef(type)) {
this.writeNode(type + 'Symbolizer', symbolizer, null, node);
}
}
}
return node;
},
'PointSymbolizer': function(symbolizer) {
var node = this.createElementNS('sld:PointSymbolizer');
this.writeNode('Graphic', symbolizer, null, node);
return node;
},
'Mark': function(symbolizer) {
var node = this.createElementNS('sld:Mark');
this.writeNode('WellKnownName', symbolizer.getType(), null, node);
var fill = symbolizer.getFill();
if (!goog.isNull(fill)) {
this.writeNode('Fill', fill, null, node);
}
var stroke = symbolizer.getStroke();
if (!goog.isNull(stroke)) {
this.writeNode('Stroke', stroke, null, node);
}
return node;
},
'WellKnownName': function(name) {
var node = this.createElementNS('sld:WellKnownName');
node.appendChild(this.createTextNode(name));
return node;
},
'Graphic': function(symbolizer) {
var node = this.createElementNS('sld:Graphic');
var size;
if (symbolizer instanceof ol.style.Icon) {
this.writeNode('ExternalGraphic', symbolizer, null, node);
var opacity = symbolizer.getOpacity();
goog.asserts.assertInstanceof(opacity, ol.expr.Literal,
'Only ol.expr.Literal supported for graphicOpacity');
this.writeNode('Opacity', opacity.getValue(), null, node);
size = symbolizer.getWidth();
} else if (symbolizer instanceof ol.style.Shape) {
this.writeNode('Mark', symbolizer, null, node);
size = symbolizer.getSize();
}
this.writeNode('Size', size, null, node);
if (symbolizer instanceof ol.style.Icon) {
var rotation = symbolizer.getRotation();
goog.asserts.assertInstanceof(rotation, ol.expr.Literal,
'Only ol.expr.Literal supported for rotation');
this.writeNode('Rotation', rotation.getValue(), null, node);
}
return node;
},
'PolygonSymbolizer': function(symbolizer) {
var node = this.createElementNS('sld:PolygonSymbolizer');
this.writeNode('Fill', symbolizer, null, node);
return node;
},
'Fill': function(symbolizer) {
var node = this.createElementNS('sld:Fill');
var fillColor = symbolizer.getColor();
var msg = 'Only ol.expr.Literal supported for Fill properties';
goog.asserts.assertInstanceof(fillColor, ol.expr.Literal, msg);
this.writeNode('CssParameter', {
value: fillColor.getValue(),
key: 'fillColor'
}, null, node);
var fillOpacity = symbolizer.getOpacity();
goog.asserts.assertInstanceof(fillOpacity, ol.expr.Literal, msg);
this.writeNode('CssParameter', {
value: fillOpacity.getValue(),
key: 'fillOpacity'
}, null, node);
return node;
},
'TextSymbolizer': function(symbolizer) {
var node = this.createElementNS('sld:TextSymbolizer');
var text = symbolizer.getText();
this.writeNode('Label', text, null, node);
this.writeNode('Font', symbolizer, null, node);
var stroke = symbolizer.getStroke();
if (!goog.isNull(stroke)) {
this.writeNode('Halo', stroke, null, node);
}
var color = symbolizer.getColor();
goog.asserts.assertInstanceof(color, ol.expr.Literal,
'font color should be ol.expr.Literal');
this.writeNode('Fill', symbolizer, null, node);
return node;
},
'Halo': function(symbolizer) {
var node = this.createElementNS('sld:Halo');
goog.asserts.assertInstanceof(symbolizer.getWidth(), ol.expr.Literal,
'Only ol.expr.Literal supported for haloRadius');
this.writeNode('Radius', symbolizer.getWidth().getValue() / 2, null,
node);
this.writeNode('Fill', symbolizer, null, node);
return node;
},
'Radius': function(value) {
var node = this.createElementNS('sld:Radius');
node.appendChild(this.createTextNode(value));
return node;
},
'LineSymbolizer': function(symbolizer) {
var node = this.createElementNS('sld:LineSymbolizer');
this.writeNode('Stroke', symbolizer, null, node);
return node;
},
'Stroke': function(symbolizer) {
var node = this.createElementNS('sld:Stroke');
var strokeColor = symbolizer.getColor();
var msg = 'SLD writing of stroke properties only supported ' +
'for ol.expr.Literal';
goog.asserts.assertInstanceof(strokeColor, ol.expr.Literal, msg);
this.writeNode('CssParameter', {
value: strokeColor.getValue(),
key: 'strokeColor'
}, null, node);
var strokeOpacity = symbolizer.getOpacity();
goog.asserts.assertInstanceof(strokeOpacity, ol.expr.Literal, msg);
this.writeNode('CssParameter', {
value: strokeOpacity.getValue(),
key: 'strokeOpacity'
}, null, node);
var strokeWidth = symbolizer.getWidth();
goog.asserts.assertInstanceof(strokeWidth, ol.expr.Literal, msg);
this.writeNode('CssParameter', {
value: strokeWidth.getValue(),
key: 'strokeWidth'
}, null, node);
// TODO strokeDashstyle and strokeLinecap
return node;
},
'CssParameter': function(obj) {
// not handling ogc:expressions for now
var name = ol.parser.ogc.SLD_v1.getCssProperty_(obj.key);
if (goog.isDef(name)) {
var node = this.createElementNS('sld:CssParameter');
node.setAttribute('name', name);
node.appendChild(this.createTextNode(obj.value));
return node;
}
},
'Label': function(label) {
var node = this.createElementNS('sld:Label');
this.filter_.writeOgcExpression(label, node);
return node;
},
'Font': function(symbolizer) {
var node = this.createElementNS('sld:Font');
this.writeNode('CssParameter', {
key: 'fontFamily',
value: symbolizer.getFontFamily().getValue()
}, null, node);
this.writeNode('CssParameter', {
key: 'fontSize',
value: symbolizer.getFontSize().getValue()
}, null, node);
// TODO fontWeight and fontStyle
return node;
},
'MinScaleDenominator': function(scale) {
var node = this.createElementNS('sld:MinScaleDenominator');
node.appendChild(this.createTextNode(scale));
return node;
},
'MaxScaleDenominator': function(scale) {
var node = this.createElementNS('sld:MaxScaleDenominator');
node.appendChild(this.createTextNode(scale));
return node;
},
'Size': function(value) {
var node = this.createElementNS('sld:Size');
this.filter_.writeOgcExpression(value, node);
return node;
}
};
this.filter_ = new ol.parser.ogc.Filter_v1_0_0();
for (var uri in this.filter_.readers) {
for (var key in this.filter_.readers[uri]) {
if (!goog.isDef(this.readers[uri])) {
this.readers[uri] = {};
}
this.readers[uri][key] = goog.bind(this.filter_.readers[uri][key],
this.filter_);
}
}
for (var uri in this.filter_.writers) {
for (var key in this.filter_.writers[uri]) {
if (!goog.isDef(this.writers[uri])) {
this.writers[uri] = {};
}
this.writers[uri][key] = goog.bind(this.filter_.writers[uri][key],
this.filter_);
}
}
goog.base(this);
};
goog.inherits(ol.parser.ogc.SLD_v1, ol.parser.XML);
/**
* @private
*/
ol.parser.ogc.SLD_v1.cssMap_ = {
'stroke': 'strokeColor',
'stroke-opacity': 'strokeOpacity',
'stroke-width': 'strokeWidth',
'stroke-linecap': 'strokeLinecap',
'stroke-dasharray': 'strokeDashstyle',
'fill': 'fillColor',
'fill-opacity': 'fillOpacity',
'font-family': 'fontFamily',
'font-size': 'fontSize',
'font-weight': 'fontWeight',
'font-style': 'fontStyle'
};
/**
* @private
*/
ol.parser.ogc.SLD_v1.defaults_ = {
fillOpacity: 1,
strokeOpacity: 1,
strokeWidth: 1,
strokeColor: '#000000',
haloColor: '#FFFFFF',
haloOpacity: 1,
haloRadius: 1,
fillColor: '#808080',
fontColor: '#000000'
};
/**
* @private
* @param {string} sym Symbolizer property.
* @return {string|undefined} The css property that matches the symbolizer
* property.
*/
ol.parser.ogc.SLD_v1.getCssProperty_ = function(sym) {
return goog.object.findKey(ol.parser.ogc.SLD_v1.cssMap_,
function(value, key, obj) {
return (sym === value);
}
);
};
/**
* @private
* @param {number} scaleDenominator The scale denominator to convert to
* resolution.
* @return {number} resolution.
*/
ol.parser.ogc.SLD_v1.prototype.getResolutionFromScaleDenominator_ =
function(scaleDenominator) {
var dpi = 25.4 / 0.28;
var mpu = ol.METERS_PER_UNIT[this.units];
return 1 / ((1 / scaleDenominator) * (mpu * 39.37) * dpi);
};
/**
* @private
* @param {number} resolution The resolution to convert to scale denominator.
* @return {number} scale denominator.
*/
ol.parser.ogc.SLD_v1.prototype.getScaleDenominatorFromResolution_ =
function(resolution) {
var dpi = 25.4 / 0.28;
var mpu = ol.METERS_PER_UNIT[this.units];
return resolution * mpu * 39.37 * dpi;
};
/**
* @param {string|Document|Element} data Data to read.
* @param {ol.parser.SLDReadOptions=} opt_options Read options.
* @return {Object} An object representing the document.
*/
ol.parser.ogc.SLD_v1.prototype.read = function(data, opt_options) {
var units = 'm';
if (goog.isDef(opt_options) && goog.isDef(opt_options.units)) {
units = opt_options.units;
}
this.units = units;
if (goog.isString(data)) {
data = goog.dom.xml.loadXml(data);
}
if (data && data.nodeType == 9) {
data = data.documentElement;
}
var obj = {namedLayers: {}};
this.readNode(data, obj);
delete this.units;
return obj;
};
/**
* @param {Object} style The style to write out.
* @param {ol.parser.SLDWriteOptions=} opt_options Write options.
* @return {string} The serialized SLD.
*/
ol.parser.ogc.SLD_v1.prototype.write = function(style, opt_options) {
var units = 'm';
if (goog.isDef(opt_options) && goog.isDef(opt_options.units)) {
units = opt_options.units;
}
this.units = units;
var root = this.writeNode('StyledLayerDescriptor', style);
this.setAttributeNS(
root, 'http://www.w3.org/2001/XMLSchema-instance',
'xsi:schemaLocation', this.schemaLocation);
var result = this.serialize(root);
delete this.units;
return result;
};

View File

@@ -0,0 +1,18 @@
goog.provide('ol.parser.ogc.SLD_v1_0_0');
goog.require('ol.parser.ogc.SLD_v1');
/**
* @constructor
* @extends {ol.parser.ogc.SLD_v1}
*/
ol.parser.ogc.SLD_v1_0_0 = function() {
goog.base(this);
this.version = '1.0.0';
this.schemaLocation = 'http://www.opengis.net/sld ' +
'http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd';
};
goog.inherits(ol.parser.ogc.SLD_v1_0_0,
ol.parser.ogc.SLD_v1);

View File

@@ -54,6 +54,20 @@ ol.style.Rule = function(options) {
this.maxResolution_ = goog.isDef(options.maxResolution) ?
options.maxResolution : Infinity;
/**
* @type {string|undefined}
* @private
*/
this.name_ = goog.isDef(options.name) ?
options.name : undefined;
/**
* @type {string|undefined}
* @private
*/
this.title_ = goog.isDef(options.title) ?
options.title : undefined;
};
@@ -78,3 +92,43 @@ ol.style.Rule.prototype.applies = function(feature, resolution) {
ol.style.Rule.prototype.getSymbolizers = function() {
return this.symbolizers_;
};
/**
* @return {ol.expr.Expression}
*/
ol.style.Rule.prototype.getFilter = function() {
return this.filter_;
};
/**
* @return {number}
*/
ol.style.Rule.prototype.getMinResolution = function() {
return this.minResolution_;
};
/**
* @return {number}
*/
ol.style.Rule.prototype.getMaxResolution = function() {
return this.maxResolution_;
};
/**
* @return {string|undefined}
*/
ol.style.Rule.prototype.getName = function() {
return this.name_;
};
/**
* @return {string|undefined}
*/
ol.style.Rule.prototype.getTitle = function() {
return this.title_;
};

View File

@@ -40,6 +40,19 @@ ol.style.Style = function(options) {
this.symbolizers_ = goog.isDef(options.symbolizers) ?
options.symbolizers : [];
/**
* @type {string|undefined}
* @private
*/
this.name_ = goog.isDef(options.name) ?
options.name : undefined;
/**
* @type {string|undefined}
* @private
*/
this.title_ = goog.isDef(options.title) ?
options.title : undefined;
};
@@ -207,3 +220,43 @@ ol.style.Style.reduceLiterals_ = function(literals) {
}
return reduced;
};
/**
* @return {Array.<ol.style.Rule>}
*/
ol.style.Style.prototype.getRules = function() {
return this.rules_;
};
/**
* @param {Array.<ol.style.Rule>} rules The rules to set.
*/
ol.style.Style.prototype.setRules = function(rules) {
this.rules_ = rules;
};
/**
* @return {Array.<ol.style.Symbolizer>}
*/
ol.style.Style.prototype.getSymbolizers = function() {
return this.symbolizers_;
};
/**
* @return {string|undefined}
*/
ol.style.Style.prototype.getName = function() {
return this.name_;
};
/**
* @return {string|undefined}
*/
ol.style.Style.prototype.getTitle = function() {
return this.title_;
};

View File

@@ -215,6 +215,15 @@ ol.style.Text.prototype.getZIndex = function() {
};
/**
* Get the stroke.
* @return {ol.style.Stroke} Stroke.
*/
ol.style.Text.prototype.getStroke = function() {
return this.stroke_;
};
/**
* Set the font color.
* @param {ol.expr.Expression} color Font color.

View File

@@ -0,0 +1,90 @@
goog.provide('ol.test.parser.ogc.SLD_v1_0_0');
describe('ol.parser.ogc.SLD_v1_0_0', function() {
var parser = new ol.parser.ogc.SLD();
var obj;
describe('reading and writing', function() {
it('Handles reading', function(done) {
var url = 'spec/ol/parser/ogc/xml/sld_v1_0_0.xml';
afterLoadXml(url, function(xml) {
obj = parser.read(xml);
expect(obj.version).to.equal('1.0.0');
var style = obj.namedLayers['AAA161'].userStyles[0];
expect(style).to.be.a(ol.style.Style);
expect(style.rules_.length).to.equal(2);
var first = style.rules_[0];
expect(first).to.be.a(ol.style.Rule);
expect(first.filter_).to.be.a(ol.expr.Comparison);
expect(first.filter_.getLeft()).to.be.a(ol.expr.Identifier);
expect(first.filter_.getLeft().getName()).to.equal('CTE');
expect(first.filter_.getOperator()).to.equal(ol.expr.ComparisonOp.EQ);
expect(first.filter_.getRight()).to.be.a(ol.expr.Literal);
expect(first.filter_.getRight().getValue()).to.equal('V0305');
expect(first.getSymbolizers().length).to.equal(3);
expect(first.getSymbolizers()[0]).to.be.a(ol.style.Fill);
expect(first.getSymbolizers()[0].getColor().getValue()).to.equal(
'#ffffff');
expect(first.getSymbolizers()[0].getOpacity().getValue()).to.equal(1);
expect(first.getSymbolizers()[1]).to.be.a(ol.style.Stroke);
expect(first.getSymbolizers()[1].getColor().getValue()).to.equal(
'#000000');
expect(first.getSymbolizers()[2]).to.be.a(ol.style.Text);
expect(first.getSymbolizers()[2].getText()).to.be.a(ol.expr.Call);
expect(first.getSymbolizers()[2].getText().getArgs().length).to.equal(
3);
expect(first.getSymbolizers()[2].getText().getArgs()[0]).to.be.a(
ol.expr.Literal);
expect(first.getSymbolizers()[2].getText().getArgs()[0].getValue()).
to.equal('A');
expect(first.getSymbolizers()[2].getText().getArgs()[1]).to.be.a(
ol.expr.Identifier);
expect(first.getSymbolizers()[2].getText().getArgs()[1].getName()).
to.equal('FOO');
expect(first.getSymbolizers()[2].getText().getArgs()[2]).to.be.a(
ol.expr.Literal);
expect(first.getSymbolizers()[2].getText().getArgs()[2].getValue()).
to.equal('label');
expect(first.getSymbolizers()[2].getColor().getValue()).to.equal(
'#000000');
expect(first.getSymbolizers()[2].getFontFamily().getValue()).to.equal(
'Arial');
expect(first.getSymbolizers()[2].getStroke()).to.be.a(ol.style.Stroke);
expect(first.getSymbolizers()[2].getStroke().getColor().getValue())
.to.equal('#ffffff');
expect(first.getSymbolizers()[2].getStroke().getWidth().getValue())
.to.equal(6);
var second = style.rules_[1];
expect(second.filter_).to.be.a(ol.expr.Comparison);
expect(second.getSymbolizers().length).to.equal(2);
expect(second.getSymbolizers()[0]).to.be.a(ol.style.Fill);
expect(second.getSymbolizers()[1]).to.be.a(ol.style.Stroke);
done();
});
});
it('Handles write', function(done) {
var url = 'spec/ol/parser/ogc/xml/sld_v1_0_0_write.xml';
afterLoadXml(url, function(xml) {
expect(goog.dom.xml.loadXml(parser.write(obj))).to.xmleql(xml);
done();
});
});
});
});
goog.require('goog.dom.xml');
goog.require('ol.parser.ogc.SLD_v1_0_0');
goog.require('ol.parser.ogc.SLD');
goog.require('ol.expr.Call');
goog.require('ol.expr.Comparison');
goog.require('ol.expr.ComparisonOp');
goog.require('ol.expr.Identifier');
goog.require('ol.expr.Literal');
goog.require('ol.style.Fill');
goog.require('ol.style.Rule');
goog.require('ol.style.Stroke');
goog.require('ol.style.Style');
goog.require('ol.style.Text');

View File

@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8"?>
<StyledLayerDescriptor version="1.0.0" xmlns="http://www.opengis.net/sld"
xmlns:gml="http://www.opengis.net/gml" xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd">
<NamedLayer>
<Name>AAA161</Name>
<UserStyle>
<FeatureTypeStyle>
<Rule>
<Name>stortsteen</Name>
<ogc:Filter>
<ogc:PropertyIsEqualTo>
<ogc:PropertyName>CTE</ogc:PropertyName>
<ogc:Literal>V0305</ogc:Literal>
</ogc:PropertyIsEqualTo>
</ogc:Filter>
<MaxScaleDenominator>50000</MaxScaleDenominator>
<PolygonSymbolizer>
<Fill>
<CssParameter name="fill">#ffffff</CssParameter>
</Fill>
<Stroke>
<CssParameter name="stroke">#000000</CssParameter>
</Stroke>
</PolygonSymbolizer>
<TextSymbolizer>
<Label> A <ogc:PropertyName>FOO</ogc:PropertyName> label </Label>
<Font>
<CssParameter name="font-family">Arial</CssParameter>
<CssParameter name="font-size">14</CssParameter>
<CssParameter name="font-weight">bold</CssParameter>
<CssParameter name="font-style">normal</CssParameter>
</Font>
<LabelPlacement>
<PointPlacement>
<AnchorPoint>
<AnchorPointX>0.5</AnchorPointX>
<AnchorPointY>0.5</AnchorPointY>
</AnchorPoint>
<Displacement>
<DisplacementX>5</DisplacementX>
<DisplacementY>5</DisplacementY>
</Displacement>
<Rotation>45</Rotation>
</PointPlacement>
</LabelPlacement>
<Halo>
<Radius>3</Radius>
<Fill>
<CssParameter name="fill">#ffffff</CssParameter>
</Fill>
</Halo>
<Fill>
<CssParameter name="fill">#000000</CssParameter>
</Fill>
</TextSymbolizer>
</Rule>
<Rule>
<Name>betonbekleding</Name>
<ogc:Filter>
<ogc:PropertyIsLessThan>
<ogc:PropertyName>CTE</ogc:PropertyName>
<ogc:Literal>1000</ogc:Literal>
</ogc:PropertyIsLessThan>
</ogc:Filter>
<MaxScaleDenominator>50000</MaxScaleDenominator>
<PolygonSymbolizer>
<Fill>
<CssParameter name="fill">#ffff00</CssParameter>
</Fill>
<Stroke>
<CssParameter name="stroke">#0000ff</CssParameter>
</Stroke>
</PolygonSymbolizer>
</Rule>
</FeatureTypeStyle>
</UserStyle>
</NamedLayer>
<NamedLayer>
<Name>Second Layer</Name>
<UserStyle>
<FeatureTypeStyle>
<Rule>
<Name>first rule second layer</Name>
<ogc:Filter>
<ogc:Or>
<ogc:PropertyIsBetween>
<ogc:PropertyName>number</ogc:PropertyName>
<ogc:LowerBoundary>
<ogc:Literal>1064866676</ogc:Literal>
</ogc:LowerBoundary>
<ogc:UpperBoundary>
<ogc:Literal>1065512599</ogc:Literal>
</ogc:UpperBoundary>
</ogc:PropertyIsBetween>
<ogc:PropertyIsLike wildCard="*" singleChar="." escape="!">
<ogc:PropertyName>cat</ogc:PropertyName>
<ogc:Literal>*dog.food!*good</ogc:Literal>
</ogc:PropertyIsLike>
<ogc:Not>
<ogc:PropertyIsLessThanOrEqualTo>
<ogc:PropertyName>FOO</ogc:PropertyName>
<ogc:Literal>5000</ogc:Literal>
</ogc:PropertyIsLessThanOrEqualTo>
</ogc:Not>
</ogc:Or>
</ogc:Filter>
<MaxScaleDenominator>10000</MaxScaleDenominator>
<PointSymbolizer>
<Graphic>
<Mark>
<WellKnownName>star</WellKnownName>
<Fill>
<CssParameter name="fill">lime</CssParameter>
</Fill>
<Stroke>
<CssParameter name="stroke">olive</CssParameter>
<CssParameter name="stroke-width">2</CssParameter>
</Stroke>
</Mark>
<Size><ogc:PropertyName>SIZE</ogc:PropertyName></Size>
</Graphic>
</PointSymbolizer>
</Rule>
</FeatureTypeStyle>
</UserStyle>
</NamedLayer>
</StyledLayerDescriptor>

View File

@@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?>
<sld:StyledLayerDescriptor xmlns:sld="http://www.opengis.net/sld" version="1.0.0"
xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<sld:NamedLayer>
<sld:Name>AAA161</sld:Name>
<sld:UserStyle>
<sld:FeatureTypeStyle>
<sld:Rule>
<sld:Name>stortsteen</sld:Name>
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
<ogc:PropertyIsEqualTo>
<ogc:PropertyName>CTE</ogc:PropertyName>
<ogc:Literal>V0305</ogc:Literal>
</ogc:PropertyIsEqualTo>
</ogc:Filter>
<sld:MaxScaleDenominator>49999.99999999999</sld:MaxScaleDenominator>
<sld:PolygonSymbolizer>
<sld:Fill>
<sld:CssParameter name="fill">#ffffff</sld:CssParameter>
<sld:CssParameter name="fill-opacity">1</sld:CssParameter>
</sld:Fill>
</sld:PolygonSymbolizer>
<sld:LineSymbolizer>
<sld:Stroke>
<sld:CssParameter name="stroke">#000000</sld:CssParameter>
<sld:CssParameter name="stroke-opacity">1</sld:CssParameter>
<sld:CssParameter name="stroke-width">1</sld:CssParameter>
</sld:Stroke>
</sld:LineSymbolizer>
<sld:TextSymbolizer>
<sld:Label><ogc:Literal xmlns:ogc="http://www.opengis.net/ogc"
>A</ogc:Literal><ogc:PropertyName
xmlns:ogc="http://www.opengis.net/ogc"
>FOO</ogc:PropertyName><ogc:Literal
xmlns:ogc="http://www.opengis.net/ogc"
>label</ogc:Literal></sld:Label>
<sld:Font>
<sld:CssParameter name="font-family">Arial</sld:CssParameter>
<sld:CssParameter name="font-size">14</sld:CssParameter>
</sld:Font>
<sld:Halo>
<sld:Radius>3</sld:Radius>
<sld:Fill>
<sld:CssParameter name="fill">#ffffff</sld:CssParameter>
<sld:CssParameter name="fill-opacity">1</sld:CssParameter>
</sld:Fill>
</sld:Halo>
<sld:Fill>
<sld:CssParameter name="fill">#000000</sld:CssParameter>
<sld:CssParameter name="fill-opacity">1</sld:CssParameter>
</sld:Fill>
</sld:TextSymbolizer>
</sld:Rule>
<sld:Rule>
<sld:Name>betonbekleding</sld:Name>
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
<ogc:PropertyIsLessThan>
<ogc:PropertyName>CTE</ogc:PropertyName>
<ogc:Literal>1000</ogc:Literal>
</ogc:PropertyIsLessThan>
</ogc:Filter>
<sld:MaxScaleDenominator>49999.99999999999</sld:MaxScaleDenominator>
<sld:PolygonSymbolizer>
<sld:Fill>
<sld:CssParameter name="fill">#ffff00</sld:CssParameter>
<sld:CssParameter name="fill-opacity">1</sld:CssParameter>
</sld:Fill>
</sld:PolygonSymbolizer>
<sld:LineSymbolizer>
<sld:Stroke>
<sld:CssParameter name="stroke">#0000ff</sld:CssParameter>
<sld:CssParameter name="stroke-opacity">1</sld:CssParameter>
<sld:CssParameter name="stroke-width">1</sld:CssParameter>
</sld:Stroke>
</sld:LineSymbolizer>
</sld:Rule>
</sld:FeatureTypeStyle>
</sld:UserStyle>
</sld:NamedLayer>
<sld:NamedLayer>
<sld:Name>Second Layer</sld:Name>
<sld:UserStyle>
<sld:FeatureTypeStyle>
<sld:Rule>
<sld:Name>first rule second layer</sld:Name>
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
<ogc:Or>
<ogc:Not>
<ogc:PropertyIsLessThanOrEqualTo>
<ogc:PropertyName>FOO</ogc:PropertyName>
<ogc:Literal>5000</ogc:Literal>
</ogc:PropertyIsLessThanOrEqualTo>
</ogc:Not>
<ogc:PropertyIsLike wildCard="*" singleChar="." escape="!">
<ogc:PropertyName>cat</ogc:PropertyName>
<ogc:Literal>*dog.food!*good</ogc:Literal>
</ogc:PropertyIsLike>
<ogc:PropertyIsBetween>
<ogc:PropertyName>number</ogc:PropertyName>
<ogc:LowerBoundary>
<ogc:Literal>1064866676</ogc:Literal>
</ogc:LowerBoundary>
<ogc:UpperBoundary>
<ogc:Literal>1065512599</ogc:Literal>
</ogc:UpperBoundary>
</ogc:PropertyIsBetween>
</ogc:Or>
</ogc:Filter>
<sld:MaxScaleDenominator>10000</sld:MaxScaleDenominator>
<sld:PointSymbolizer>
<sld:Graphic>
<sld:Mark>
<sld:WellKnownName>star</sld:WellKnownName>
<sld:Fill>
<sld:CssParameter name="fill">lime</sld:CssParameter>
<sld:CssParameter name="fill-opacity">1</sld:CssParameter>
</sld:Fill>
<sld:Stroke>
<sld:CssParameter name="stroke">olive</sld:CssParameter>
<sld:CssParameter name="stroke-opacity">1</sld:CssParameter>
<sld:CssParameter name="stroke-width">2</sld:CssParameter>
</sld:Stroke>
</sld:Mark>
<sld:Size><ogc:PropertyName xmlns:ogc="http://www.opengis.net/ogc"
>SIZE</ogc:PropertyName></sld:Size>
</sld:Graphic>
</sld:PointSymbolizer>
</sld:Rule>
</sld:FeatureTypeStyle>
</sld:UserStyle>
</sld:NamedLayer>
</sld:StyledLayerDescriptor>