/* Copyright (c) 2006-2008 MetaCarta, Inc., 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.js */ /** * Class: OpenLayers.Format.SLD.v1 * Superclass for SLD version 1 parsers. * * Inherits from: * - */ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.XML, { /** * Property: namespaces * {Object} Mapping of namespace aliases to namespace URIs. */ namespaces: { sld: "http://www.opengis.net/sld", ogc: "http://www.opengis.net/ogc", xlink: "http://www.w3.org/1999/xlink", xsi: "http://www.w3.org/2001/XMLSchema-instance" }, /** * Property: defaultPrefix */ defaultPrefix: "sld", /** * Property: schemaLocation * {String} Schema location for a particular minor version. */ schemaLocation: null, /** * APIProperty: defaultSymbolizer. * {Object} A symbolizer with the SLD defaults. */ defaultSymbolizer: { fillColor: "#808080", fillOpacity: 1, strokeColor: "#000000", strokeOpacity: 1, strokeWidth: 1, pointRadius: 6 }, /** * Constructor: OpenLayers.Format.SLD.v1 * Instances of this class are not created directly. Use the * constructor instead. * * Parameters: * options - {Object} An optional object whose properties will be set on * this instance. */ initialize: function(options) { OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); }, /** * Method: read * * Parameters: * data - {DOMElement} An SLD document element. * * Returns: * {Object} An object representing the SLD. */ read: function(data) { var sld = { namedLayers: {} }; this.readChildNodes(data, sld); return sld; }, /** * 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": { "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); // give each of the user styles this layer name for(var i=0; i 0) { rule.filter = new OpenLayers.Filter.FeatureId({ fids: obj.fids }); } else if(obj.filters.length > 0) { rule.filter = obj.filters[0]; } }, "FeatureId": function(node, obj) { var fid = node.getAttribute("fid"); if(fid) { obj.fids.push(fid); } }, "And": function(node, obj) { var filter = new OpenLayers.Filter.Logical({ type: OpenLayers.Filter.Logical.AND }); this.readChildNodes(node, filter); obj.filters.push(filter); }, "Or": function(node, obj) { var filter = new OpenLayers.Filter.Logical({ type: OpenLayers.Filter.Logical.OR }); this.readChildNodes(node, filter); obj.filters.push(filter); }, "Not": function(node, obj) { var filter = new OpenLayers.Filter.Logical({ type: OpenLayers.Filter.Logical.NOT }); this.readChildNodes(node, filter); obj.filters.push(filter); }, "PropertyIsEqualTo": function(node, obj) { var filter = new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.EQUAL_TO }); this.readChildNodes(node, filter); obj.filters.push(filter); }, "PropertyIsNotEqualTo": function(node, obj) { var filter = new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.NOT_EQUAL_TO }); this.readChildNodes(node, filter); obj.filters.push(filter); }, "PropertyIsLessThan": function(node, obj) { var filter = new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.LESS_THAN }); this.readChildNodes(node, filter); obj.filters.push(filter); }, "PropertyIsGreaterThan": function(node, obj) { var filter = new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.GREATER_THAN }); this.readChildNodes(node, filter); obj.filters.push(filter); }, "PropertyIsLessThanOrEqualTo": function(node, obj) { var filter = new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO }); this.readChildNodes(node, filter); obj.filters.push(filter); }, "PropertyIsGreaterThanOrEqualTo": function(node, obj) { var filter = new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO }); this.readChildNodes(node, filter); obj.filters.push(filter); }, "PropertyIsBetween": function(node, obj) { var filter = new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.BETWEEN }); this.readChildNodes(node, filter); obj.filters.push(filter); }, "PropertyIsLike": function(node, obj) { var filter = new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.LIKE }); this.readChildNodes(node, filter); var wildCard = node.getAttribute("wildCard"); var singleChar = node.getAttribute("singleChar"); var esc = node.getAttribute("escape"); filter.value2regex(wildCard, singleChar, esc); obj.filters.push(filter); }, "Literal": function(node, obj) { obj.value = this.getChildValue(node); }, "PropertyName": function(node, filter) { filter.property = this.getChildValue(node); }, "LowerBoundary": function(node, filter) { filter.lowerBoundary = this.readOgcExpression(node); }, "UpperBoundary": function(node, filter) { filter.upperBoundary = this.readOgcExpression(node); } } }, /** * 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) { value = this.getChildValue(node); } return value; }, /** * Property: cssMap * {Object} Object mapping supported css property names to OpenLayers * symbolizer property names. */ cssMap: { "stroke": "strokeColor", "stroke-opacity": "strokeOpacity", "stroke-width": "strokeWidth", "stroke-linecap": "strokeLinecap", "fill": "fillColor", "fill-opacity": "fillOpacity" }, /** * Method: getCssProperty * Given a symbolizer property, get the corresponding CSS property * from the . * * Parameters: * sym - {String} A symbolizer property name. * * Returns: * {String} A CSS property name or null if none found. */ getCssProperty: function(sym) { var css = null; for(var prop in this.cssMap) { if(this.cssMap[prop] == sym) { css = prop; break; } } return css; }, /** * Method: getGraphicFormat * Given a href for an external graphic, try to determine the mime-type. * This method doesn't try too hard, and will fall back to * if one of the known is not * the file extension of the provided href. * * Parameters: * href - {String} * * Returns: * {String} The graphic format. */ getGraphicFormat: function(href) { var format, regex; for(var key in this.graphicFormats) { if(this.graphicFormats[key].test(href)) { format = key; break; } } return format || this.defautlGraphicFormat; }, /** * Property: defaultGraphicFormat * {String} If none other can be determined from , this * default will be returned. */ defaultGraphicFormat: "image/png", /** * Property: graphicFormats * {Object} Mapping of image mime-types to regular extensions matching * well-known file extensions. */ graphicFormats: { "image/jpeg": /\.jpe?g$/i, "image/gif": /\.gif$/i, "image/png": /\.png$/i }, /** * Method: write * * Parameters: * sld - {Object} An object representing the SLD. * * Returns: * {DOMElement} The root of an SLD document. */ write: function(sld) { return this.writers.sld.StyledLayerDescriptor.apply(this, [sld]); }, /** * 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": { "StyledLayerDescriptor": function(sld) { var root = this.createElementNSPlus( "StyledLayerDescriptor", {attributes: { "version": this.VERSION, "xsi:schemaLocation": this.schemaLocation }} ); // add in optional name if(sld.name) { this.writeNode(root, "Name", sld.name); } // add in optional title if(sld.title) { this.writeNode(root, "Title", sld.title); } // add in optional description if(sld.description) { this.writeNode(root, "Abstract", sld.description); } // add in named layers for(var name in sld.namedLayers) { this.writeNode(root, "NamedLayer", sld.namedLayers[name]); } return root; }, "Name": function(name) { return this.createElementNSPlus("Name", {value: name}); }, "Title": function(title) { return this.createElementNSPlus("Title", {value: title}); }, "Abstract": function(description) { return this.createElementNSPlus( "Abstract", {value: description} ); }, "NamedLayer": function(layer) { var node = this.createElementNSPlus("NamedLayer"); // add in required name this.writeNode(node, "Name", layer.name); // optional sld:LayerFeatureConstraints here // add in named styles if(layer.namedStyles) { for(var i=0; i": "PropertyIsGreaterThan", "<=": "PropertyIsLessThanOrEqualTo", ">=": "PropertyIsGreaterThanOrEqualTo", "..": "PropertyIsBetween", "~": "PropertyIsLike" }, /** * Methods below this point are of general use for versioned XML parsers. * These are candidates for an abstract class. */ /** * Method: getNamespacePrefix * Get the namespace prefix for a given uri from the object. * * Returns: * {String} A namespace prefix or null if none found. */ getNamespacePrefix: function(uri) { var prefix = null; if(uri == null) { prefix = this.namespaces[this.defaultPrefix]; } else { var gotPrefix = false; for(prefix in this.namespaces) { if(this.namespaces[prefix] == uri) { gotPrefix = true; break; } } if(!gotPrefix) { prefix = null; } } return prefix; }, /** * Method: readChildNodes */ readChildNodes: function(node, obj) { var children = node.childNodes; var child, group, reader, prefix, local; for(var i=0; i group. If a local name is used (e.g. "Name") then * the namespace of the parent is assumed. * obj - {Object} Structure containing data for the writer. * * Returns: * {DOMElement} The child node. */ writeNode: function(parent, name, obj) { var prefix, local; var split = name.indexOf(":"); if(split > 0) { prefix = name.substring(0, split); local = name.substring(split + 1); } else { prefix = this.getNamespacePrefix(parent.namespaceURI); local = name; } var child = this.writers[prefix][local].apply(this, [obj]); parent.appendChild(child); return child; }, /** * Method: createElementNSPlus * Shorthand for creating namespaced elements with optional attributes and * child text nodes. * * Parameters: * name - {String} The qualified node name. * options - {Object} Optional object for node configuration. * * Returns: * {Element} An element node. */ createElementNSPlus: function(name, options) { options = options || {}; var loc = name.indexOf(":"); // order of prefix preference // 1. in the uri option // 2. in the prefix option // 3. in the qualified name // 4. from the defaultPrefix var uri = options.uri || this.namespaces[options.prefix]; if(!uri) { loc = name.indexOf(":"); uri = this.namespaces[name.substring(0, loc)]; } if(!uri) { uri = this.namespaces[this.defaultPrefix]; } var node = this.createElementNS(uri, name); if(options.attributes) { this.setAttributes(node, options.attributes); } if(options.value) { node.appendChild(this.createTextNode(options.value)); } return node; }, /** * Method: setAttributes * Set multiple attributes given key value pairs from an object. * * Parameters: * node - {Element} An element node. * obj - {Object || Array} An object whose properties represent attribute * names and values represent attribute values. If an attribute name * is a qualified name ("prefix:local"), the prefix will be looked up * in the parsers {namespaces} object. If the prefix is found, * setAttributeNS will be used instead of setAttribute. */ setAttributes: function(node, obj) { var value, loc, alias, uri; for(var name in obj) { value = obj[name].toString(); // check for qualified attribute name ("prefix:local") uri = this.namespaces[name.substring(0, name.indexOf(":"))] || null; this.setAttributeNS(node, uri, name, value); } }, CLASS_NAME: "OpenLayers.Format.SLD.v1" });