diff options
author | Chris Schlaeger <chris@linux.com> | 2014-08-12 21:56:44 +0200 |
---|---|---|
committer | Chris Schlaeger <chris@linux.com> | 2014-08-12 21:56:44 +0200 |
commit | ea346a785dc1b3f7c156f6fc33da634e1f1a627b (patch) | |
tree | af67530553d20b6e82ad60fd79593e9c4abf5565 /misc/openlayers/lib/OpenLayers/Format | |
parent | 59741cd535c47f25971bf8c32b25da25ceadc6d5 (diff) | |
download | postrunner-ea346a785dc1b3f7c156f6fc33da634e1f1a627b.zip |
Adding jquery, flot and openlayers to be included with the GEM.v0.0.4
Diffstat (limited to 'misc/openlayers/lib/OpenLayers/Format')
83 files changed, 23427 insertions, 0 deletions
diff --git a/misc/openlayers/lib/OpenLayers/Format/ArcXML.js b/misc/openlayers/lib/OpenLayers/Format/ArcXML.js new file mode 100644 index 0000000..9d523d1 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/ArcXML.js @@ -0,0 +1,1028 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Geometry/Polygon.js + * @requires OpenLayers/Geometry/Point.js + * @requires OpenLayers/Geometry/MultiPolygon.js + * @requires OpenLayers/Geometry/LinearRing.js + */ + +/** + * Class: OpenLayers.Format.ArcXML + * Read/Write ArcXML. Create a new instance with the <OpenLayers.Format.ArcXML> + * constructor. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.ArcXML = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * Property: fontStyleKeys + * {Array} List of keys used in font styling. + */ + fontStyleKeys: [ + 'antialiasing', 'blockout', 'font', 'fontcolor','fontsize', 'fontstyle', + 'glowing', 'interval', 'outline', 'printmode', 'shadow', 'transparency' + ], + + /** + * Property: request + * A get_image request destined for an ArcIMS server. + */ + request: null, + + /** + * Property: response + * A parsed response from an ArcIMS server. + */ + response: null, + + /** + * Constructor: OpenLayers.Format.ArcXML + * Create a new parser/writer for ArcXML. Create an instance of this class + * to begin authoring a request to an ArcIMS service. This is used + * primarily by the ArcIMS layer, but could be used to do other wild + * stuff, like geocoding. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + this.request = new OpenLayers.Format.ArcXML.Request(); + this.response = new OpenLayers.Format.ArcXML.Response(); + + if (options) { + if (options.requesttype == "feature") { + this.request.get_image = null; + + var qry = this.request.get_feature.query; + this.addCoordSys(qry.featurecoordsys, options.featureCoordSys); + this.addCoordSys(qry.filtercoordsys, options.filterCoordSys); + + if (options.polygon) { + qry.isspatial = true; + qry.spatialfilter.polygon = options.polygon; + } else if (options.envelope) { + qry.isspatial = true; + qry.spatialfilter.envelope = {minx:0, miny:0, maxx:0, maxy:0}; + this.parseEnvelope(qry.spatialfilter.envelope, options.envelope); + } + } else if (options.requesttype == "image") { + this.request.get_feature = null; + + var props = this.request.get_image.properties; + this.parseEnvelope(props.envelope, options.envelope); + + this.addLayers(props.layerlist, options.layers); + this.addImageSize(props.imagesize, options.tileSize); + this.addCoordSys(props.featurecoordsys, options.featureCoordSys); + this.addCoordSys(props.filtercoordsys, options.filterCoordSys); + } else { + // if an arcxml object is being created with no request type, it is + // probably going to consume a response, so do not throw an error if + // the requesttype is not defined + this.request = null; + } + } + + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); + }, + + /** + * Method: parseEnvelope + * Parse an array of coordinates into an ArcXML envelope structure. + * + * Parameters: + * env - {Object} An envelope object that will contain the parsed coordinates. + * arr - {Array(double)} An array of coordinates in the order: [ minx, miny, maxx, maxy ] + */ + parseEnvelope: function(env, arr) { + if (arr && arr.length == 4) { + env.minx = arr[0]; + env.miny = arr[1]; + env.maxx = arr[2]; + env.maxy = arr[3]; + } + }, + + /** + * Method: addLayers + * Add a collection of layers to another collection of layers. Each layer in the list is tuple of + * { id, visible }. These layer collections represent the + * /ARCXML/REQUEST/get_image/PROPERTIES/LAYERLIST/LAYERDEF items in ArcXML + * + * TODO: Add support for dynamic layer rendering. + * + * Parameters: + * ll - {Array({id,visible})} A list of layer definitions. + * lyrs - {Array({id,visible})} A list of layer definitions. + */ + addLayers: function(ll, lyrs) { + for(var lind = 0, len=lyrs.length; lind < len; lind++) { + ll.push(lyrs[lind]); + } + }, + + /** + * Method: addImageSize + * Set the size of the requested image. + * + * Parameters: + * imsize - {Object} An ArcXML imagesize object. + * olsize - {<OpenLayers.Size>} The image size to set. + */ + addImageSize: function(imsize, olsize) { + if (olsize !== null) { + imsize.width = olsize.w; + imsize.height = olsize.h; + imsize.printwidth = olsize.w; + imsize.printheight = olsize.h; + } + }, + + /** + * Method: addCoordSys + * Add the coordinate system information to an object. The object may be + * + * Parameters: + * featOrFilt - {Object} A featurecoordsys or filtercoordsys ArcXML structure. + * fsys - {String} or {<OpenLayers.Projection>} or {filtercoordsys} or + * {featurecoordsys} A projection representation. If it's a {String}, + * the value is assumed to be the SRID. If it's a {OpenLayers.Projection} + * AND Proj4js is available, the projection number and name are extracted + * from there. If it's a filter or feature ArcXML structure, it is copied. + */ + addCoordSys: function(featOrFilt, fsys) { + if (typeof fsys == "string") { + featOrFilt.id = parseInt(fsys); + featOrFilt.string = fsys; + } + // is this a proj4js instance? + else if (typeof fsys == "object" && fsys.proj !== null){ + featOrFilt.id = fsys.proj.srsProjNumber; + featOrFilt.string = fsys.proj.srsCode; + } else { + featOrFilt = fsys; + } + }, + + /** + * APIMethod: iserror + * Check to see if the response from the server was an error. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. If nothing is supplied, + * the current response is examined. + * + * Returns: + * {Boolean} true if the response was an error. + */ + iserror: function(data) { + var ret = null; + + if (!data) { + ret = (this.response.error !== ''); + } else { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + var errorNodes = data.documentElement.getElementsByTagName("ERROR"); + ret = (errorNodes !== null && errorNodes.length > 0); + } + + return ret; + }, + + /** + * APIMethod: read + * Read data from a string, and return an response. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {<OpenLayers.Format.ArcXML.Response>} An ArcXML response. Note that this response + * data may change in the future. + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + + var arcNode = null; + if (data && data.documentElement) { + if(data.documentElement.nodeName == "ARCXML") { + arcNode = data.documentElement; + } else { + arcNode = data.documentElement.getElementsByTagName("ARCXML")[0]; + } + } + + // in Safari, arcNode will be there but will have a child named + // parsererror + if (!arcNode || arcNode.firstChild.nodeName === 'parsererror') { + var error, source; + try { + error = data.firstChild.nodeValue; + source = data.firstChild.childNodes[1].firstChild.nodeValue; + } catch (err) { + // pass + } + throw { + message: "Error parsing the ArcXML request", + error: error, + source: source + }; + } + + var response = this.parseResponse(arcNode); + return response; + }, + + /** + * APIMethod: write + * Generate an ArcXml document string for sending to an ArcIMS server. + * + * Returns: + * {String} A string representing the ArcXML document request. + */ + write: function(request) { + if (!request) { + request = this.request; + } + var root = this.createElementNS("", "ARCXML"); + root.setAttribute("version","1.1"); + + var reqElem = this.createElementNS("", "REQUEST"); + + if (request.get_image != null) { + var getElem = this.createElementNS("", "GET_IMAGE"); + reqElem.appendChild(getElem); + + var propElem = this.createElementNS("", "PROPERTIES"); + getElem.appendChild(propElem); + + var props = request.get_image.properties; + if (props.featurecoordsys != null) { + var feat = this.createElementNS("", "FEATURECOORDSYS"); + propElem.appendChild(feat); + + if (props.featurecoordsys.id === 0) { + feat.setAttribute("string", props.featurecoordsys['string']); + } + else { + feat.setAttribute("id", props.featurecoordsys.id); + } + } + + if (props.filtercoordsys != null) { + var filt = this.createElementNS("", "FILTERCOORDSYS"); + propElem.appendChild(filt); + + if (props.filtercoordsys.id === 0) { + filt.setAttribute("string", props.filtercoordsys.string); + } + else { + filt.setAttribute("id", props.filtercoordsys.id); + } + } + + if (props.envelope != null) { + var env = this.createElementNS("", "ENVELOPE"); + propElem.appendChild(env); + + env.setAttribute("minx", props.envelope.minx); + env.setAttribute("miny", props.envelope.miny); + env.setAttribute("maxx", props.envelope.maxx); + env.setAttribute("maxy", props.envelope.maxy); + } + + var imagesz = this.createElementNS("", "IMAGESIZE"); + propElem.appendChild(imagesz); + + imagesz.setAttribute("height", props.imagesize.height); + imagesz.setAttribute("width", props.imagesize.width); + + if (props.imagesize.height != props.imagesize.printheight || + props.imagesize.width != props.imagesize.printwidth) { + imagesz.setAttribute("printheight", props.imagesize.printheight); + imagesz.setArrtibute("printwidth", props.imagesize.printwidth); + } + + if (props.background != null) { + var backgrnd = this.createElementNS("", "BACKGROUND"); + propElem.appendChild(backgrnd); + + backgrnd.setAttribute("color", + props.background.color.r + "," + + props.background.color.g + "," + + props.background.color.b); + + if (props.background.transcolor !== null) { + backgrnd.setAttribute("transcolor", + props.background.transcolor.r + "," + + props.background.transcolor.g + "," + + props.background.transcolor.b); + } + } + + if (props.layerlist != null && props.layerlist.length > 0) { + var layerlst = this.createElementNS("", "LAYERLIST"); + propElem.appendChild(layerlst); + + for (var ld = 0; ld < props.layerlist.length; ld++) { + var ldef = this.createElementNS("", "LAYERDEF"); + layerlst.appendChild(ldef); + + ldef.setAttribute("id", props.layerlist[ld].id); + ldef.setAttribute("visible", props.layerlist[ld].visible); + + if (typeof props.layerlist[ld].query == "object") { + var query = props.layerlist[ld].query; + + if (query.where.length < 0) { + continue; + } + + var queryElem = null; + if (typeof query.spatialfilter == "boolean" && query.spatialfilter) { + // handle spatial filter madness + queryElem = this.createElementNS("", "SPATIALQUERY"); + } + else { + queryElem = this.createElementNS("", "QUERY"); + } + + queryElem.setAttribute("where", query.where); + + if (typeof query.accuracy == "number" && query.accuracy > 0) { + queryElem.setAttribute("accuracy", query.accuracy); + } + if (typeof query.featurelimit == "number" && query.featurelimit < 2000) { + queryElem.setAttribute("featurelimit", query.featurelimit); + } + if (typeof query.subfields == "string" && query.subfields != "#ALL#") { + queryElem.setAttribute("subfields", query.subfields); + } + if (typeof query.joinexpression == "string" && query.joinexpression.length > 0) { + queryElem.setAttribute("joinexpression", query.joinexpression); + } + if (typeof query.jointables == "string" && query.jointables.length > 0) { + queryElem.setAttribute("jointables", query.jointables); + } + + ldef.appendChild(queryElem); + } + + if (typeof props.layerlist[ld].renderer == "object") { + this.addRenderer(ldef, props.layerlist[ld].renderer); + } + } + } + } else if (request.get_feature != null) { + var getElem = this.createElementNS("", "GET_FEATURES"); + getElem.setAttribute("outputmode", "newxml"); + getElem.setAttribute("checkesc", "true"); + + if (request.get_feature.geometry) { + getElem.setAttribute("geometry", request.get_feature.geometry); + } + else { + getElem.setAttribute("geometry", "false"); + } + + if (request.get_feature.compact) { + getElem.setAttribute("compact", request.get_feature.compact); + } + + if (request.get_feature.featurelimit == "number") { + getElem.setAttribute("featurelimit", request.get_feature.featurelimit); + } + + getElem.setAttribute("globalenvelope", "true"); + reqElem.appendChild(getElem); + + if (request.get_feature.layer != null && request.get_feature.layer.length > 0) { + var lyrElem = this.createElementNS("", "LAYER"); + lyrElem.setAttribute("id", request.get_feature.layer); + getElem.appendChild(lyrElem); + } + + var fquery = request.get_feature.query; + if (fquery != null) { + var qElem = null; + if (fquery.isspatial) { + qElem = this.createElementNS("", "SPATIALQUERY"); + } else { + qElem = this.createElementNS("", "QUERY"); + } + getElem.appendChild(qElem); + + if (typeof fquery.accuracy == "number") { + qElem.setAttribute("accuracy", fquery.accuracy); + } + //qElem.setAttribute("featurelimit", "5"); + + if (fquery.featurecoordsys != null) { + var fcsElem1 = this.createElementNS("", "FEATURECOORDSYS"); + + if (fquery.featurecoordsys.id == 0) { + fcsElem1.setAttribute("string", fquery.featurecoordsys.string); + } else { + fcsElem1.setAttribute("id", fquery.featurecoordsys.id); + } + qElem.appendChild(fcsElem1); + } + + if (fquery.filtercoordsys != null) { + var fcsElem2 = this.createElementNS("", "FILTERCOORDSYS"); + + if (fquery.filtercoordsys.id === 0) { + fcsElem2.setAttribute("string", fquery.filtercoordsys.string); + } else { + fcsElem2.setAttribute("id", fquery.filtercoordsys.id); + } + qElem.appendChild(fcsElem2); + } + + if (fquery.buffer > 0) { + var bufElem = this.createElementNS("", "BUFFER"); + bufElem.setAttribute("distance", fquery.buffer); + qElem.appendChild(bufElem); + } + + if (fquery.isspatial) { + var spfElem = this.createElementNS("", "SPATIALFILTER"); + spfElem.setAttribute("relation", fquery.spatialfilter.relation); + qElem.appendChild(spfElem); + + if (fquery.spatialfilter.envelope) { + var envElem = this.createElementNS("", "ENVELOPE"); + envElem.setAttribute("minx", fquery.spatialfilter.envelope.minx); + envElem.setAttribute("miny", fquery.spatialfilter.envelope.miny); + envElem.setAttribute("maxx", fquery.spatialfilter.envelope.maxx); + envElem.setAttribute("maxy", fquery.spatialfilter.envelope.maxy); + spfElem.appendChild(envElem); + } else if(typeof fquery.spatialfilter.polygon == "object") { + spfElem.appendChild(this.writePolygonGeometry(fquery.spatialfilter.polygon)); + } + } + + if (fquery.where != null && fquery.where.length > 0) { + qElem.setAttribute("where", fquery.where); + } + } + } + + root.appendChild(reqElem); + + return OpenLayers.Format.XML.prototype.write.apply(this, [root]); + }, + + + addGroupRenderer: function(ldef, toprenderer) { + var topRelem = this.createElementNS("", "GROUPRENDERER"); + ldef.appendChild(topRelem); + + for (var rind = 0; rind < toprenderer.length; rind++) { + var renderer = toprenderer[rind]; + this.addRenderer(topRelem, renderer); + } + }, + + + addRenderer: function(topRelem, renderer) { + if (OpenLayers.Util.isArray(renderer)) { + this.addGroupRenderer(topRelem, renderer); + } else { + var renderElem = this.createElementNS("", renderer.type.toUpperCase() + "RENDERER"); + topRelem.appendChild(renderElem); + + if (renderElem.tagName == "VALUEMAPRENDERER") { + this.addValueMapRenderer(renderElem, renderer); + } else if (renderElem.tagName == "VALUEMAPLABELRENDERER") { + this.addValueMapLabelRenderer(renderElem, renderer); + } else if (renderElem.tagName == "SIMPLELABELRENDERER") { + this.addSimpleLabelRenderer(renderElem, renderer); + } else if (renderElem.tagName == "SCALEDEPENDENTRENDERER") { + this.addScaleDependentRenderer(renderElem, renderer); + } + } + }, + + + addScaleDependentRenderer: function(renderElem, renderer) { + if (typeof renderer.lower == "string" || typeof renderer.lower == "number") { + renderElem.setAttribute("lower", renderer.lower); + } + if (typeof renderer.upper == "string" || typeof renderer.upper == "number") { + renderElem.setAttribute("upper", renderer.upper); + } + + this.addRenderer(renderElem, renderer.renderer); + }, + + + addValueMapLabelRenderer: function(renderElem, renderer) { + renderElem.setAttribute("lookupfield", renderer.lookupfield); + renderElem.setAttribute("labelfield", renderer.labelfield); + + if (typeof renderer.exacts == "object") { + for (var ext=0, extlen=renderer.exacts.length; ext<extlen; ext++) { + var exact = renderer.exacts[ext]; + + var eelem = this.createElementNS("", "EXACT"); + + if (typeof exact.value == "string") { + eelem.setAttribute("value", exact.value); + } + if (typeof exact.label == "string") { + eelem.setAttribute("label", exact.label); + } + if (typeof exact.method == "string") { + eelem.setAttribute("method", exact.method); + } + + renderElem.appendChild(eelem); + + if (typeof exact.symbol == "object") { + var selem = null; + + if (exact.symbol.type == "text") { + selem = this.createElementNS("", "TEXTSYMBOL"); + } + + if (selem != null) { + var keys = this.fontStyleKeys; + for (var i = 0, len = keys.length; i < len; i++) { + var key = keys[i]; + if (exact.symbol[key]) { + selem.setAttribute(key, exact.symbol[key]); + } + } + eelem.appendChild(selem); + } + } + } // for each exact + } + }, + + addValueMapRenderer: function(renderElem, renderer) { + renderElem.setAttribute("lookupfield", renderer.lookupfield); + + if (typeof renderer.ranges == "object") { + for(var rng=0, rnglen=renderer.ranges.length; rng<rnglen; rng++) { + var range = renderer.ranges[rng]; + + var relem = this.createElementNS("", "RANGE"); + relem.setAttribute("lower", range.lower); + relem.setAttribute("upper", range.upper); + + renderElem.appendChild(relem); + + if (typeof range.symbol == "object") { + var selem = null; + + if (range.symbol.type == "simplepolygon") { + selem = this.createElementNS("", "SIMPLEPOLYGONSYMBOL"); + } + + if (selem != null) { + if (typeof range.symbol.boundarycolor == "string") { + selem.setAttribute("boundarycolor", range.symbol.boundarycolor); + } + if (typeof range.symbol.fillcolor == "string") { + selem.setAttribute("fillcolor", range.symbol.fillcolor); + } + if (typeof range.symbol.filltransparency == "number") { + selem.setAttribute("filltransparency", range.symbol.filltransparency); + } + relem.appendChild(selem); + } + } + } // for each range + } else if (typeof renderer.exacts == "object") { + for (var ext=0, extlen=renderer.exacts.length; ext<extlen; ext++) { + var exact = renderer.exacts[ext]; + + var eelem = this.createElementNS("", "EXACT"); + if (typeof exact.value == "string") { + eelem.setAttribute("value", exact.value); + } + if (typeof exact.label == "string") { + eelem.setAttribute("label", exact.label); + } + if (typeof exact.method == "string") { + eelem.setAttribute("method", exact.method); + } + + renderElem.appendChild(eelem); + + if (typeof exact.symbol == "object") { + var selem = null; + + if (exact.symbol.type == "simplemarker") { + selem = this.createElementNS("", "SIMPLEMARKERSYMBOL"); + } + + if (selem != null) { + if (typeof exact.symbol.antialiasing == "string") { + selem.setAttribute("antialiasing", exact.symbol.antialiasing); + } + if (typeof exact.symbol.color == "string") { + selem.setAttribute("color", exact.symbol.color); + } + if (typeof exact.symbol.outline == "string") { + selem.setAttribute("outline", exact.symbol.outline); + } + if (typeof exact.symbol.overlap == "string") { + selem.setAttribute("overlap", exact.symbol.overlap); + } + if (typeof exact.symbol.shadow == "string") { + selem.setAttribute("shadow", exact.symbol.shadow); + } + if (typeof exact.symbol.transparency == "number") { + selem.setAttribute("transparency", exact.symbol.transparency); + } + //if (typeof exact.symbol.type == "string") + // selem.setAttribute("type", exact.symbol.type); + if (typeof exact.symbol.usecentroid == "string") { + selem.setAttribute("usecentroid", exact.symbol.usecentroid); + } + if (typeof exact.symbol.width == "number") { + selem.setAttribute("width", exact.symbol.width); + } + + eelem.appendChild(selem); + } + } + } // for each exact + } + }, + + + addSimpleLabelRenderer: function(renderElem, renderer) { + renderElem.setAttribute("field", renderer.field); + var keys = ['featureweight', 'howmanylabels', 'labelbufferratio', + 'labelpriorities', 'labelweight', 'linelabelposition', + 'rotationalangles']; + for (var i=0, len=keys.length; i<len; i++) { + var key = keys[i]; + if (renderer[key]) { + renderElem.setAttribute(key, renderer[key]); + } + } + + if (renderer.symbol.type == "text") { + var symbol = renderer.symbol; + var selem = this.createElementNS("", "TEXTSYMBOL"); + renderElem.appendChild(selem); + + var keys = this.fontStyleKeys; + for (var i=0, len=keys.length; i<len; i++) { + var key = keys[i]; + if (symbol[key]) { + selem.setAttribute(key, renderer[key]); + } + } + } + }, + + writePolygonGeometry: function(polygon) { + if (!(polygon instanceof OpenLayers.Geometry.Polygon)) { + throw { + message:'Cannot write polygon geometry to ArcXML with an ' + + polygon.CLASS_NAME + ' object.', + geometry: polygon + }; + } + + var polyElem = this.createElementNS("", "POLYGON"); + + for (var ln=0, lnlen=polygon.components.length; ln<lnlen; ln++) { + var ring = polygon.components[ln]; + var ringElem = this.createElementNS("", "RING"); + + for (var rn=0, rnlen=ring.components.length; rn<rnlen; rn++) { + var point = ring.components[rn]; + var pointElem = this.createElementNS("", "POINT"); + + pointElem.setAttribute("x", point.x); + pointElem.setAttribute("y", point.y); + + ringElem.appendChild(pointElem); + } + + polyElem.appendChild(ringElem); + } + + return polyElem; + }, + + /** + * Method: parseResponse + * Take an ArcXML response, and parse in into this object's internal properties. + * + * Parameters: + * data - {String} or {DOMElement} The ArcXML response, as either a string or the + * top level DOMElement of the response. + */ + parseResponse: function(data) { + if(typeof data == "string") { + var newData = new OpenLayers.Format.XML(); + data = newData.read(data); + } + var response = new OpenLayers.Format.ArcXML.Response(); + + var errorNode = data.getElementsByTagName("ERROR"); + + if (errorNode != null && errorNode.length > 0) { + response.error = this.getChildValue(errorNode, "Unknown error."); + } else { + var responseNode = data.getElementsByTagName("RESPONSE"); + + if (responseNode == null || responseNode.length == 0) { + response.error = "No RESPONSE tag found in ArcXML response."; + return response; + } + + var rtype = responseNode[0].firstChild.nodeName; + if (rtype == "#text") { + rtype = responseNode[0].firstChild.nextSibling.nodeName; + } + + if (rtype == "IMAGE") { + var envelopeNode = data.getElementsByTagName("ENVELOPE"); + var outputNode = data.getElementsByTagName("OUTPUT"); + + if (envelopeNode == null || envelopeNode.length == 0) { + response.error = "No ENVELOPE tag found in ArcXML response."; + } else if (outputNode == null || outputNode.length == 0) { + response.error = "No OUTPUT tag found in ArcXML response."; + } else { + var envAttr = this.parseAttributes(envelopeNode[0]); + var outputAttr = this.parseAttributes(outputNode[0]); + + if (typeof outputAttr.type == "string") { + response.image = { + envelope: envAttr, + output: { + type: outputAttr.type, + data: this.getChildValue(outputNode[0]) + } + }; + } else { + response.image = { envelope: envAttr, output: outputAttr }; + } + } + } else if (rtype == "FEATURES") { + var features = responseNode[0].getElementsByTagName("FEATURES"); + + // get the feature count + var featureCount = features[0].getElementsByTagName("FEATURECOUNT"); + response.features.featurecount = featureCount[0].getAttribute("count"); + + if (response.features.featurecount > 0) { + // get the feature envelope + var envelope = features[0].getElementsByTagName("ENVELOPE"); + response.features.envelope = this.parseAttributes(envelope[0], typeof(0)); + + // get the field values per feature + var featureList = features[0].getElementsByTagName("FEATURE"); + for (var fn = 0; fn < featureList.length; fn++) { + var feature = new OpenLayers.Feature.Vector(); + var fields = featureList[fn].getElementsByTagName("FIELD"); + + for (var fdn = 0; fdn < fields.length; fdn++) { + var fieldName = fields[fdn].getAttribute("name"); + var fieldValue = fields[fdn].getAttribute("value"); + feature.attributes[ fieldName ] = fieldValue; + } + + var geom = featureList[fn].getElementsByTagName("POLYGON"); + + if (geom.length > 0) { + // if there is a polygon, create an openlayers polygon, and assign + // it to the .geometry property of the feature + var ring = geom[0].getElementsByTagName("RING"); + + var polys = []; + for (var rn = 0; rn < ring.length; rn++) { + var linearRings = []; + linearRings.push(this.parsePointGeometry(ring[rn])); + + var holes = ring[rn].getElementsByTagName("HOLE"); + for (var hn = 0; hn < holes.length; hn++) { + linearRings.push(this.parsePointGeometry(holes[hn])); + } + holes = null; + polys.push(new OpenLayers.Geometry.Polygon(linearRings)); + linearRings = null; + } + ring = null; + + if (polys.length == 1) { + feature.geometry = polys[0]; + } else + { + feature.geometry = new OpenLayers.Geometry.MultiPolygon(polys); + } + } + + response.features.feature.push(feature); + } + } + } else { + response.error = "Unidentified response type."; + } + } + return response; + }, + + + /** + * Method: parseAttributes + * + * Parameters: + * node - {<DOMElement>} An element to parse attributes from. + * + * Returns: + * {Object} An attributes object, with properties set to attribute values. + */ + parseAttributes: function(node,type) { + var attributes = {}; + for(var attr = 0; attr < node.attributes.length; attr++) { + if (type == "number") { + attributes[node.attributes[attr].nodeName] = parseFloat(node.attributes[attr].nodeValue); + } else { + attributes[node.attributes[attr].nodeName] = node.attributes[attr].nodeValue; + } + } + return attributes; + }, + + + /** + * Method: parsePointGeometry + * + * Parameters: + * node - {<DOMElement>} An element to parse <COORDS> or <POINT> arcxml data from. + * + * Returns: + * {<OpenLayers.Geometry.LinearRing>} A linear ring represented by the node's points. + */ + parsePointGeometry: function(node) { + var ringPoints = []; + var coords = node.getElementsByTagName("COORDS"); + + if (coords.length > 0) { + // if coords is present, it's the only coords item + var coordArr = this.getChildValue(coords[0]); + coordArr = coordArr.split(/;/); + for (var cn = 0; cn < coordArr.length; cn++) { + var coordItems = coordArr[cn].split(/ /); + ringPoints.push(new OpenLayers.Geometry.Point(coordItems[0], coordItems[1])); + } + coords = null; + } else { + var point = node.getElementsByTagName("POINT"); + if (point.length > 0) { + for (var pn = 0; pn < point.length; pn++) { + ringPoints.push( + new OpenLayers.Geometry.Point( + parseFloat(point[pn].getAttribute("x")), + parseFloat(point[pn].getAttribute("y")) + ) + ); + } + } + point = null; + } + + return new OpenLayers.Geometry.LinearRing(ringPoints); + }, + + CLASS_NAME: "OpenLayers.Format.ArcXML" +}); + +OpenLayers.Format.ArcXML.Request = OpenLayers.Class({ + initialize: function(params) { + var defaults = { + get_image: { + properties: { + background: null, + /*{ + color: { r:255, g:255, b:255 }, + transcolor: null + },*/ + draw: true, + envelope: { + minx: 0, + miny: 0, + maxx: 0, + maxy: 0 + }, + featurecoordsys: { + id:0, + string:"", + datumtransformid:0, + datumtransformstring:"" + }, + filtercoordsys:{ + id:0, + string:"", + datumtransformid:0, + datumtransformstring:"" + }, + imagesize:{ + height:0, + width:0, + dpi:96, + printheight:0, + printwidth:0, + scalesymbols:false + }, + layerlist:[], + /* no support for legends */ + output:{ + baseurl:"", + legendbaseurl:"", + legendname:"", + legendpath:"", + legendurl:"", + name:"", + path:"", + type:"jpg", + url:"" + } + } + }, + + get_feature: { + layer: "", + query: { + isspatial: false, + featurecoordsys: { + id:0, + string:"", + datumtransformid:0, + datumtransformstring:"" + }, + filtercoordsys: { + id:0, + string:"", + datumtransformid:0, + datumtransformstring:"" + }, + buffer:0, + where:"", + spatialfilter: { + relation: "envelope_intersection", + envelope: null + } + } + }, + + environment: { + separators: { + cs:" ", + ts:";" + } + }, + + layer: [], + workspaces: [] + }; + + return OpenLayers.Util.extend(this, defaults); + }, + + CLASS_NAME: "OpenLayers.Format.ArcXML.Request" +}); + +OpenLayers.Format.ArcXML.Response = OpenLayers.Class({ + initialize: function(params) { + var defaults = { + image: { + envelope:null, + output:'' + }, + + features: { + featurecount: 0, + envelope: null, + feature: [] + }, + + error:'' + }; + + return OpenLayers.Util.extend(this, defaults); + }, + + CLASS_NAME: "OpenLayers.Format.ArcXML.Response" +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/ArcXML/Features.js b/misc/openlayers/lib/OpenLayers/Format/ArcXML/Features.js new file mode 100644 index 0000000..5b8730d --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/ArcXML/Features.js @@ -0,0 +1,46 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/ArcXML.js + */ + +/** + * Class: OpenLayers.Format.ArcXML.Features + * Read/Write ArcXML features. Create a new instance with the + * <OpenLayers.Format.ArcXML.Features> constructor. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.ArcXML.Features = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * Constructor: OpenLayers.Format.ArcXML.Features + * Create a new parser/writer for ArcXML Features. Create an instance of this class + * to get a set of features from an ArcXML response. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Read data from a string of ArcXML, and return a set of OpenLayers features. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array(<OpenLayers.Feature.Vector>)} A collection of features. + */ + read: function(data) { + var axl = new OpenLayers.Format.ArcXML(); + var parsed = axl.read(data); + + return parsed.features.feature; + } +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/Atom.js b/misc/openlayers/lib/OpenLayers/Format/Atom.js new file mode 100644 index 0000000..8eb5792 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/Atom.js @@ -0,0 +1,712 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Format/GML/v3.js + * @requires OpenLayers/Feature/Vector.js + */ + +/** + * Class: OpenLayers.Format.Atom + * Read/write Atom feeds. Create a new instance with the + * <OpenLayers.Format.AtomFeed> constructor. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.Atom = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. Properties + * of this object should not be set individually. Read-only. All + * XML subclasses should have their own namespaces object. Use + * <setNamespace> to add or set a namespace alias after construction. + */ + namespaces: { + atom: "http://www.w3.org/2005/Atom", + georss: "http://www.georss.org/georss" + }, + + /** + * APIProperty: feedTitle + * {String} Atom feed elements require a title. Default is "untitled". + */ + feedTitle: "untitled", + + /** + * APIProperty: defaultEntryTitle + * {String} Atom entry elements require a title. In cases where one is + * not provided in the feature attributes, this will be used. Default + * is "untitled". + */ + defaultEntryTitle: "untitled", + + /** + * Property: gmlParse + * {Object} GML Format object for parsing features + * Non-API and only created if necessary + */ + gmlParser: null, + + /** + * APIProperty: xy + * {Boolean} Order of the GML coordinate: true:(x,y) or false:(y,x) + * For GeoRSS the default is (y,x), therefore: false + */ + xy: false, + + /** + * Constructor: OpenLayers.Format.AtomEntry + * Create a new parser for Atom. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Return a list of features from an Atom feed or entry document. + + * Parameters: + * doc - {Element} or {String} + * + * Returns: + * Array({<OpenLayers.Feature.Vector>}) + */ + read: function(doc) { + if (typeof doc == "string") { + doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]); + } + return this.parseFeatures(doc); + }, + + /** + * APIMethod: write + * Serialize or more feature nodes to Atom documents. + * + * Parameters: + * features - {<OpenLayers.Feature.Vector>} or Array({<OpenLayers.Feature.Vector>}) + * + * Returns: + * {String} an Atom entry document if passed one feature node, or a feed + * document if passed an array of feature nodes. + */ + write: function(features) { + var doc; + if (OpenLayers.Util.isArray(features)) { + doc = this.createElementNSPlus("atom:feed"); + doc.appendChild( + this.createElementNSPlus("atom:title", { + value: this.feedTitle + }) + ); + for (var i=0, ii=features.length; i<ii; i++) { + doc.appendChild(this.buildEntryNode(features[i])); + } + } + else { + doc = this.buildEntryNode(features); + } + return OpenLayers.Format.XML.prototype.write.apply(this, [doc]); + }, + + /** + * Method: buildContentNode + * + * Parameters: + * content - {Object} + * + * Returns: + * {DOMElement} an Atom content node. + * + * TODO: types other than text. + */ + buildContentNode: function(content) { + var node = this.createElementNSPlus("atom:content", { + attributes: { + type: content.type || null + } + }); + if (content.src) { + node.setAttribute("src", content.src); + } else { + if (content.type == "text" || content.type == null) { + node.appendChild( + this.createTextNode(content.value) + ); + } else if (content.type == "html") { + if (typeof content.value != "string") { + throw "HTML content must be in form of an escaped string"; + } + node.appendChild( + this.createTextNode(content.value) + ); + } else if (content.type == "xhtml") { + node.appendChild(content.value); + } else if (content.type == "xhtml" || + content.type.match(/(\+|\/)xml$/)) { + node.appendChild(content.value); + } + else { // MUST be a valid Base64 encoding + node.appendChild( + this.createTextNode(content.value) + ); + } + } + return node; + }, + + /** + * Method: buildEntryNode + * Build an Atom entry node from a feature object. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} + * + * Returns: + * {DOMElement} an Atom entry node. + * + * These entries are geared for publication using AtomPub. + * + * TODO: support extension elements + */ + buildEntryNode: function(feature) { + var attrib = feature.attributes; + var atomAttrib = attrib.atom || {}; + var entryNode = this.createElementNSPlus("atom:entry"); + + // atom:author + if (atomAttrib.authors) { + var authors = OpenLayers.Util.isArray(atomAttrib.authors) ? + atomAttrib.authors : [atomAttrib.authors]; + for (var i=0, ii=authors.length; i<ii; i++) { + entryNode.appendChild( + this.buildPersonConstructNode( + "author", authors[i] + ) + ); + } + } + + // atom:category + if (atomAttrib.categories) { + var categories = OpenLayers.Util.isArray(atomAttrib.categories) ? + atomAttrib.categories : [atomAttrib.categories]; + var category; + for (var i=0, ii=categories.length; i<ii; i++) { + category = categories[i]; + entryNode.appendChild( + this.createElementNSPlus("atom:category", { + attributes: { + term: category.term, + scheme: category.scheme || null, + label: category.label || null + } + }) + ); + } + } + + // atom:content + if (atomAttrib.content) { + entryNode.appendChild(this.buildContentNode(atomAttrib.content)); + } + + // atom:contributor + if (atomAttrib.contributors) { + var contributors = OpenLayers.Util.isArray(atomAttrib.contributors) ? + atomAttrib.contributors : [atomAttrib.contributors]; + for (var i=0, ii=contributors.length; i<ii; i++) { + entryNode.appendChild( + this.buildPersonConstructNode( + "contributor", + contributors[i] + ) + ); + } + } + + // atom:id + if (feature.fid) { + entryNode.appendChild( + this.createElementNSPlus("atom:id", { + value: feature.fid + }) + ); + } + + // atom:link + if (atomAttrib.links) { + var links = OpenLayers.Util.isArray(atomAttrib.links) ? + atomAttrib.links : [atomAttrib.links]; + var link; + for (var i=0, ii=links.length; i<ii; i++) { + link = links[i]; + entryNode.appendChild( + this.createElementNSPlus("atom:link", { + attributes: { + href: link.href, + rel: link.rel || null, + type: link.type || null, + hreflang: link.hreflang || null, + title: link.title || null, + length: link.length || null + } + }) + ); + } + } + + // atom:published + if (atomAttrib.published) { + entryNode.appendChild( + this.createElementNSPlus("atom:published", { + value: atomAttrib.published + }) + ); + } + + // atom:rights + if (atomAttrib.rights) { + entryNode.appendChild( + this.createElementNSPlus("atom:rights", { + value: atomAttrib.rights + }) + ); + } + + // atom:source not implemented + + // atom:summary + if (atomAttrib.summary || attrib.description) { + entryNode.appendChild( + this.createElementNSPlus("atom:summary", { + value: atomAttrib.summary || attrib.description + }) + ); + } + + // atom:title + entryNode.appendChild( + this.createElementNSPlus("atom:title", { + value: atomAttrib.title || attrib.title || this.defaultEntryTitle + }) + ); + + // atom:updated + if (atomAttrib.updated) { + entryNode.appendChild( + this.createElementNSPlus("atom:updated", { + value: atomAttrib.updated + }) + ); + } + + // georss:where + if (feature.geometry) { + var whereNode = this.createElementNSPlus("georss:where"); + whereNode.appendChild( + this.buildGeometryNode(feature.geometry) + ); + entryNode.appendChild(whereNode); + } + + return entryNode; + }, + + /** + * Method: initGmlParser + * Creates a GML parser. + */ + initGmlParser: function() { + this.gmlParser = new OpenLayers.Format.GML.v3({ + xy: this.xy, + featureNS: "http://example.com#feature", + internalProjection: this.internalProjection, + externalProjection: this.externalProjection + }); + }, + + /** + * Method: buildGeometryNode + * builds a GeoRSS node with a given geometry + * + * Parameters: + * geometry - {<OpenLayers.Geometry>} + * + * Returns: + * {DOMElement} A gml node. + */ + buildGeometryNode: function(geometry) { + if (!this.gmlParser) { + this.initGmlParser(); + } + var node = this.gmlParser.writeNode("feature:_geometry", geometry); + return node.firstChild; + }, + + /** + * Method: buildPersonConstructNode + * + * Parameters: + * name - {String} + * value - {Object} + * + * Returns: + * {DOMElement} an Atom person construct node. + * + * Example: + * >>> buildPersonConstructNode("author", {name: "John Smith"}) + * {<author><name>John Smith</name></author>} + * + * TODO: how to specify extension elements? Add to the oNames array? + */ + buildPersonConstructNode: function(name, value) { + var oNames = ["uri", "email"]; + var personNode = this.createElementNSPlus("atom:" + name); + personNode.appendChild( + this.createElementNSPlus("atom:name", { + value: value.name + }) + ); + for (var i=0, ii=oNames.length; i<ii; i++) { + if (value[oNames[i]]) { + personNode.appendChild( + this.createElementNSPlus("atom:" + oNames[i], { + value: value[oNames[i]] + }) + ); + } + } + return personNode; + }, + + /** + * Method: getFirstChildValue + * + * Parameters: + * node - {DOMElement} + * nsuri - {String} Child node namespace uri ("*" for any). + * name - {String} Child node name. + * def - {String} Optional string default to return if no child found. + * + * Returns: + * {String} The value of the first child with the given tag name. Returns + * default value or empty string if none found. + */ + getFirstChildValue: function(node, nsuri, name, def) { + var value; + var nodes = this.getElementsByTagNameNS(node, nsuri, name); + if (nodes && nodes.length > 0) { + value = this.getChildValue(nodes[0], def); + } else { + value = def; + } + return value; + }, + + /** + * Method: parseFeature + * Parse feature from an Atom entry node.. + * + * Parameters: + * node - {DOMElement} An Atom entry or feed node. + * + * Returns: + * {<OpenLayers.Feature.Vector>} + */ + parseFeature: function(node) { + var atomAttrib = {}; + var value = null; + var nodes = null; + var attval = null; + var atomns = this.namespaces.atom; + + // atomAuthor* + this.parsePersonConstructs(node, "author", atomAttrib); + + // atomCategory* + nodes = this.getElementsByTagNameNS(node, atomns, "category"); + if (nodes.length > 0) { + atomAttrib.categories = []; + } + for (var i=0, ii=nodes.length; i<ii; i++) { + value = {}; + value.term = nodes[i].getAttribute("term"); + attval = nodes[i].getAttribute("scheme"); + if (attval) { value.scheme = attval; } + attval = nodes[i].getAttribute("label"); + if (attval) { value.label = attval; } + atomAttrib.categories.push(value); + } + + // atomContent? + nodes = this.getElementsByTagNameNS(node, atomns, "content"); + if (nodes.length > 0) { + value = {}; + attval = nodes[0].getAttribute("type"); + if (attval) { + value.type = attval; + } + attval = nodes[0].getAttribute("src"); + if (attval) { + value.src = attval; + } else { + if (value.type == "text" || + value.type == "html" || + value.type == null ) { + value.value = this.getFirstChildValue( + node, + atomns, + "content", + null + ); + } else if (value.type == "xhtml" || + value.type.match(/(\+|\/)xml$/)) { + value.value = this.getChildEl(nodes[0]); + } else { // MUST be base64 encoded + value.value = this.getFirstChildValue( + node, + atomns, + "content", + null + ); + } + atomAttrib.content = value; + } + } + + // atomContributor* + this.parsePersonConstructs(node, "contributor", atomAttrib); + + // atomId + atomAttrib.id = this.getFirstChildValue(node, atomns, "id", null); + + // atomLink* + nodes = this.getElementsByTagNameNS(node, atomns, "link"); + if (nodes.length > 0) { + atomAttrib.links = new Array(nodes.length); + } + var oAtts = ["rel", "type", "hreflang", "title", "length"]; + for (var i=0, ii=nodes.length; i<ii; i++) { + value = {}; + value.href = nodes[i].getAttribute("href"); + for (var j=0, jj=oAtts.length; j<jj; j++) { + attval = nodes[i].getAttribute(oAtts[j]); + if (attval) { + value[oAtts[j]] = attval; + } + } + atomAttrib.links[i] = value; + } + + // atomPublished? + value = this.getFirstChildValue(node, atomns, "published", null); + if (value) { + atomAttrib.published = value; + } + + // atomRights? + value = this.getFirstChildValue(node, atomns, "rights", null); + if (value) { + atomAttrib.rights = value; + } + + // atomSource? -- not implemented + + // atomSummary? + value = this.getFirstChildValue(node, atomns, "summary", null); + if (value) { + atomAttrib.summary = value; + } + + // atomTitle + atomAttrib.title = this.getFirstChildValue( + node, atomns, "title", null + ); + + // atomUpdated + atomAttrib.updated = this.getFirstChildValue( + node, atomns, "updated", null + ); + + var featureAttrib = { + title: atomAttrib.title, + description: atomAttrib.summary, + atom: atomAttrib + }; + var geometry = this.parseLocations(node)[0]; + var feature = new OpenLayers.Feature.Vector(geometry, featureAttrib); + feature.fid = atomAttrib.id; + return feature; + }, + + /** + * Method: parseFeatures + * Return features from an Atom entry or feed. + * + * Parameters: + * node - {DOMElement} An Atom entry or feed node. + * + * Returns: + * Array({<OpenLayers.Feature.Vector>}) + */ + parseFeatures: function(node) { + var features = []; + var entries = this.getElementsByTagNameNS( + node, this.namespaces.atom, "entry" + ); + if (entries.length == 0) { + entries = [node]; + } + for (var i=0, ii=entries.length; i<ii; i++) { + features.push(this.parseFeature(entries[i])); + } + return features; + }, + + /** + * Method: parseLocations + * Parse the locations from an Atom entry or feed. + * + * Parameters: + * node - {DOMElement} An Atom entry or feed node. + * + * Returns: + * Array({<OpenLayers.Geometry>}) + */ + parseLocations: function(node) { + var georssns = this.namespaces.georss; + + var locations = {components: []}; + var where = this.getElementsByTagNameNS(node, georssns, "where"); + if (where && where.length > 0) { + if (!this.gmlParser) { + this.initGmlParser(); + } + for (var i=0, ii=where.length; i<ii; i++) { + this.gmlParser.readChildNodes(where[i], locations); + } + } + + var components = locations.components; + var point = this.getElementsByTagNameNS(node, georssns, "point"); + if (point && point.length > 0) { + for (var i=0, ii=point.length; i<ii; i++) { + var xy = OpenLayers.String.trim( + point[i].firstChild.nodeValue + ).split(/\s+/); + if (xy.length !=2) { + xy = OpenLayers.String.trim( + point[i].firstChild.nodeValue + ).split(/\s*,\s*/); + } + components.push(new OpenLayers.Geometry.Point(xy[1], xy[0])); + } + } + + var line = this.getElementsByTagNameNS(node, georssns, "line"); + if (line && line.length > 0) { + var coords; + var p; + var points; + for (var i=0, ii=line.length; i<ii; i++) { + coords = OpenLayers.String.trim( + line[i].firstChild.nodeValue + ).split(/\s+/); + points = []; + for (var j=0, jj=coords.length; j<jj; j+=2) { + p = new OpenLayers.Geometry.Point(coords[j+1], coords[j]); + points.push(p); + } + components.push( + new OpenLayers.Geometry.LineString(points) + ); + } + } + + var polygon = this.getElementsByTagNameNS(node, georssns, "polygon"); + if (polygon && polygon.length > 0) { + var coords; + var p; + var points; + for (var i=0, ii=polygon.length; i<ii; i++) { + coords = OpenLayers.String.trim( + polygon[i].firstChild.nodeValue + ).split(/\s+/); + points = []; + for (var j=0, jj=coords.length; j<jj; j+=2) { + p = new OpenLayers.Geometry.Point(coords[j+1], coords[j]); + points.push(p); + } + components.push( + new OpenLayers.Geometry.Polygon( + [new OpenLayers.Geometry.LinearRing(points)] + ) + ); + } + } + + if (this.internalProjection && this.externalProjection) { + for (var i=0, ii=components.length; i<ii; i++) { + if (components[i]) { + components[i].transform( + this.externalProjection, + this.internalProjection + ); + } + } + } + + return components; + }, + + /** + * Method: parsePersonConstruct + * Parse Atom person constructs from an Atom entry node. + * + * Parameters: + * node - {DOMElement} An Atom entry or feed node. + * name - {String} Construcy name ("author" or "contributor") + * data = {Object} Object in which to put parsed persons. + * + * Returns: + * An {Object}. + */ + parsePersonConstructs: function(node, name, data) { + var persons = []; + var atomns = this.namespaces.atom; + var nodes = this.getElementsByTagNameNS(node, atomns, name); + var oAtts = ["uri", "email"]; + for (var i=0, ii=nodes.length; i<ii; i++) { + var value = {}; + value.name = this.getFirstChildValue( + nodes[i], + atomns, + "name", + null + ); + for (var j=0, jj=oAtts.length; j<jj; j++) { + var attval = this.getFirstChildValue( + nodes[i], + atomns, + oAtts[j], + null); + if (attval) { + value[oAtts[j]] = attval; + } + } + persons.push(value); + } + if (persons.length > 0) { + data[name + "s"] = persons; + } + }, + + CLASS_NAME: "OpenLayers.Format.Atom" +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/CQL.js b/misc/openlayers/lib/OpenLayers/Format/CQL.js new file mode 100644 index 0000000..8430a8b --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/CQL.js @@ -0,0 +1,452 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WKT.js + * @requires OpenLayers/Filter/Comparison.js + * @requires OpenLayers/Filter/Logical.js + * @requires OpenLayers/Filter/Spatial.js + */ + +/** + * Class: OpenLayers.Format.CQL + * Read CQL strings to get <OpenLayers.Filter> objects. Write + * <OpenLayers.Filter> objects to get CQL strings. Create a new parser with + * the <OpenLayers.Format.CQL> constructor. + * + * Inherits from: + * - <OpenLayers.Format> + */ +OpenLayers.Format.CQL = (function() { + + var tokens = [ + "PROPERTY", "COMPARISON", "VALUE", "LOGICAL" + ], + + patterns = { + PROPERTY: /^[_a-zA-Z]\w*/, + COMPARISON: /^(=|<>|<=|<|>=|>|LIKE)/i, + IS_NULL: /^IS NULL/i, + COMMA: /^,/, + LOGICAL: /^(AND|OR)/i, + VALUE: /^('([^']|'')*'|\d+(\.\d*)?|\.\d+)/, + LPAREN: /^\(/, + RPAREN: /^\)/, + SPATIAL: /^(BBOX|INTERSECTS|DWITHIN|WITHIN|CONTAINS)/i, + NOT: /^NOT/i, + BETWEEN: /^BETWEEN/i, + GEOMETRY: function(text) { + var type = /^(POINT|LINESTRING|POLYGON|MULTIPOINT|MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)/.exec(text); + if (type) { + var len = text.length; + var idx = text.indexOf("(", type[0].length); + if (idx > -1) { + var depth = 1; + while (idx < len && depth > 0) { + idx++; + switch(text.charAt(idx)) { + case '(': + depth++; + break; + case ')': + depth--; + break; + default: + // in default case, do nothing + } + } + } + return [text.substr(0, idx+1)]; + } + }, + END: /^$/ + }, + + follows = { + LPAREN: ['GEOMETRY', 'SPATIAL', 'PROPERTY', 'VALUE', 'LPAREN'], + RPAREN: ['NOT', 'LOGICAL', 'END', 'RPAREN'], + PROPERTY: ['COMPARISON', 'BETWEEN', 'COMMA', 'IS_NULL'], + BETWEEN: ['VALUE'], + IS_NULL: ['END'], + COMPARISON: ['VALUE'], + COMMA: ['GEOMETRY', 'VALUE', 'PROPERTY'], + VALUE: ['LOGICAL', 'COMMA', 'RPAREN', 'END'], + SPATIAL: ['LPAREN'], + LOGICAL: ['NOT', 'VALUE', 'SPATIAL', 'PROPERTY', 'LPAREN'], + NOT: ['PROPERTY', 'LPAREN'], + GEOMETRY: ['COMMA', 'RPAREN'] + }, + + operators = { + '=': OpenLayers.Filter.Comparison.EQUAL_TO, + '<>': OpenLayers.Filter.Comparison.NOT_EQUAL_TO, + '<': OpenLayers.Filter.Comparison.LESS_THAN, + '<=': OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO, + '>': OpenLayers.Filter.Comparison.GREATER_THAN, + '>=': OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO, + 'LIKE': OpenLayers.Filter.Comparison.LIKE, + 'BETWEEN': OpenLayers.Filter.Comparison.BETWEEN, + 'IS NULL': OpenLayers.Filter.Comparison.IS_NULL + }, + + operatorReverse = {}, + + logicals = { + 'AND': OpenLayers.Filter.Logical.AND, + 'OR': OpenLayers.Filter.Logical.OR + }, + + logicalReverse = {}, + + precedence = { + 'RPAREN': 3, + 'LOGICAL': 2, + 'COMPARISON': 1 + }; + + var i; + for (i in operators) { + if (operators.hasOwnProperty(i)) { + operatorReverse[operators[i]] = i; + } + } + + for (i in logicals) { + if (logicals.hasOwnProperty(i)) { + logicalReverse[logicals[i]] = i; + } + } + + function tryToken(text, pattern) { + if (pattern instanceof RegExp) { + return pattern.exec(text); + } else { + return pattern(text); + } + } + + function nextToken(text, tokens) { + var i, token, len = tokens.length; + for (i=0; i<len; i++) { + token = tokens[i]; + var pat = patterns[token]; + var matches = tryToken(text, pat); + if (matches) { + var match = matches[0]; + var remainder = text.substr(match.length).replace(/^\s*/, ""); + return { + type: token, + text: match, + remainder: remainder + }; + } + } + + var msg = "ERROR: In parsing: [" + text + "], expected one of: "; + for (i=0; i<len; i++) { + token = tokens[i]; + msg += "\n " + token + ": " + patterns[token]; + } + + throw new Error(msg); + } + + function tokenize(text) { + var results = []; + var token, expect = ["NOT", "GEOMETRY", "SPATIAL", "PROPERTY", "LPAREN"]; + + do { + token = nextToken(text, expect); + text = token.remainder; + expect = follows[token.type]; + if (token.type != "END" && !expect) { + throw new Error("No follows list for " + token.type); + } + results.push(token); + } while (token.type != "END"); + + return results; + } + + function buildAst(tokens) { + var operatorStack = [], + postfix = []; + + while (tokens.length) { + var tok = tokens.shift(); + switch (tok.type) { + case "PROPERTY": + case "GEOMETRY": + case "VALUE": + postfix.push(tok); + break; + case "COMPARISON": + case "BETWEEN": + case "IS_NULL": + case "LOGICAL": + var p = precedence[tok.type]; + + while (operatorStack.length > 0 && + (precedence[operatorStack[operatorStack.length - 1].type] <= p) + ) { + postfix.push(operatorStack.pop()); + } + + operatorStack.push(tok); + break; + case "SPATIAL": + case "NOT": + case "LPAREN": + operatorStack.push(tok); + break; + case "RPAREN": + while (operatorStack.length > 0 && + (operatorStack[operatorStack.length - 1].type != "LPAREN") + ) { + postfix.push(operatorStack.pop()); + } + operatorStack.pop(); // toss out the LPAREN + + if (operatorStack.length > 0 && + operatorStack[operatorStack.length-1].type == "SPATIAL") { + postfix.push(operatorStack.pop()); + } + case "COMMA": + case "END": + break; + default: + throw new Error("Unknown token type " + tok.type); + } + } + + while (operatorStack.length > 0) { + postfix.push(operatorStack.pop()); + } + + function buildTree() { + var tok = postfix.pop(); + switch (tok.type) { + case "LOGICAL": + var rhs = buildTree(), + lhs = buildTree(); + return new OpenLayers.Filter.Logical({ + filters: [lhs, rhs], + type: logicals[tok.text.toUpperCase()] + }); + case "NOT": + var operand = buildTree(); + return new OpenLayers.Filter.Logical({ + filters: [operand], + type: OpenLayers.Filter.Logical.NOT + }); + case "BETWEEN": + var min, max, property; + postfix.pop(); // unneeded AND token here + max = buildTree(); + min = buildTree(); + property = buildTree(); + return new OpenLayers.Filter.Comparison({ + property: property, + lowerBoundary: min, + upperBoundary: max, + type: OpenLayers.Filter.Comparison.BETWEEN + }); + case "COMPARISON": + var value = buildTree(), + property = buildTree(); + return new OpenLayers.Filter.Comparison({ + property: property, + value: value, + type: operators[tok.text.toUpperCase()] + }); + case "IS_NULL": + var property = buildTree(); + return new OpenLayers.Filter.Comparison({ + property: property, + type: operators[tok.text.toUpperCase()] + }); + case "VALUE": + var match = tok.text.match(/^'(.*)'$/); + if (match) { + return match[1].replace(/''/g, "'"); + } else { + return Number(tok.text); + } + case "SPATIAL": + switch(tok.text.toUpperCase()) { + case "BBOX": + var maxy = buildTree(), + maxx = buildTree(), + miny = buildTree(), + minx = buildTree(), + prop = buildTree(); + + return new OpenLayers.Filter.Spatial({ + type: OpenLayers.Filter.Spatial.BBOX, + property: prop, + value: OpenLayers.Bounds.fromArray( + [minx, miny, maxx, maxy] + ) + }); + case "INTERSECTS": + var value = buildTree(), + property = buildTree(); + return new OpenLayers.Filter.Spatial({ + type: OpenLayers.Filter.Spatial.INTERSECTS, + property: property, + value: value + }); + case "WITHIN": + var value = buildTree(), + property = buildTree(); + return new OpenLayers.Filter.Spatial({ + type: OpenLayers.Filter.Spatial.WITHIN, + property: property, + value: value + }); + case "CONTAINS": + var value = buildTree(), + property = buildTree(); + return new OpenLayers.Filter.Spatial({ + type: OpenLayers.Filter.Spatial.CONTAINS, + property: property, + value: value + }); + case "DWITHIN": + var distance = buildTree(), + value = buildTree(), + property = buildTree(); + return new OpenLayers.Filter.Spatial({ + type: OpenLayers.Filter.Spatial.DWITHIN, + value: value, + property: property, + distance: Number(distance) + }); + } + case "GEOMETRY": + return OpenLayers.Geometry.fromWKT(tok.text); + default: + return tok.text; + } + } + + var result = buildTree(); + if (postfix.length > 0) { + var msg = "Remaining tokens after building AST: \n"; + for (var i = postfix.length - 1; i >= 0; i--) { + msg += postfix[i].type + ": " + postfix[i].text + "\n"; + } + throw new Error(msg); + } + + return result; + } + + return OpenLayers.Class(OpenLayers.Format, { + /** + * APIMethod: read + * Generate a filter from a CQL string. + + * Parameters: + * text - {String} The CQL text. + * + * Returns: + * {<OpenLayers.Filter>} A filter based on the CQL text. + */ + read: function(text) { + var result = buildAst(tokenize(text)); + if (this.keepData) { + this.data = result; + } + return result; + }, + + /** + * APIMethod: write + * Convert a filter into a CQL string. + + * Parameters: + * filter - {<OpenLayers.Filter>} The filter. + * + * Returns: + * {String} A CQL string based on the filter. + */ + write: function(filter) { + if (filter instanceof OpenLayers.Geometry) { + return filter.toString(); + } + switch (filter.CLASS_NAME) { + case "OpenLayers.Filter.Spatial": + switch(filter.type) { + case OpenLayers.Filter.Spatial.BBOX: + return "BBOX(" + + filter.property + "," + + filter.value.toBBOX() + + ")"; + case OpenLayers.Filter.Spatial.DWITHIN: + return "DWITHIN(" + + filter.property + ", " + + this.write(filter.value) + ", " + + filter.distance + ")"; + case OpenLayers.Filter.Spatial.WITHIN: + return "WITHIN(" + + filter.property + ", " + + this.write(filter.value) + ")"; + case OpenLayers.Filter.Spatial.INTERSECTS: + return "INTERSECTS(" + + filter.property + ", " + + this.write(filter.value) + ")"; + case OpenLayers.Filter.Spatial.CONTAINS: + return "CONTAINS(" + + filter.property + ", " + + this.write(filter.value) + ")"; + default: + throw new Error("Unknown spatial filter type: " + filter.type); + } + case "OpenLayers.Filter.Logical": + if (filter.type == OpenLayers.Filter.Logical.NOT) { + // TODO: deal with precedence of logical operators to + // avoid extra parentheses (not urgent) + return "NOT (" + this.write(filter.filters[0]) + ")"; + } else { + var res = "("; + var first = true; + for (var i = 0; i < filter.filters.length; i++) { + if (first) { + first = false; + } else { + res += ") " + logicalReverse[filter.type] + " ("; + } + res += this.write(filter.filters[i]); + } + return res + ")"; + } + case "OpenLayers.Filter.Comparison": + if (filter.type == OpenLayers.Filter.Comparison.BETWEEN) { + return filter.property + " BETWEEN " + + this.write(filter.lowerBoundary) + " AND " + + this.write(filter.upperBoundary); + } else { + return (filter.value !== null) ? filter.property + + " " + operatorReverse[filter.type] + " " + + this.write(filter.value) : filter.property + + " " + operatorReverse[filter.type]; + } + case undefined: + if (typeof filter === "string") { + return "'" + filter.replace(/'/g, "''") + "'"; + } else if (typeof filter === "number") { + return String(filter); + } + default: + throw new Error("Can't encode: " + filter.CLASS_NAME + " " + filter); + } + }, + + CLASS_NAME: "OpenLayers.Format.CQL" + + }); +})(); + diff --git a/misc/openlayers/lib/OpenLayers/Format/CSWGetDomain.js b/misc/openlayers/lib/OpenLayers/Format/CSWGetDomain.js new file mode 100644 index 0000000..18d5328 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/CSWGetDomain.js @@ -0,0 +1,34 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format.js + */ + +/** + * Class: OpenLayers.Format.CSWGetDomain + * Default version is 2.0.2. + * + * Returns: + * {<OpenLayers.Format>} A CSWGetDomain format of the given version. + */ +OpenLayers.Format.CSWGetDomain = function(options) { + options = OpenLayers.Util.applyDefaults( + options, OpenLayers.Format.CSWGetDomain.DEFAULTS + ); + var cls = OpenLayers.Format.CSWGetDomain["v"+options.version.replace(/\./g, "_")]; + if(!cls) { + throw "Unsupported CSWGetDomain version: " + options.version; + } + return new cls(options); +}; + +/** + * Constant: DEFAULTS + * {Object} Default properties for the CSWGetDomain format. + */ +OpenLayers.Format.CSWGetDomain.DEFAULTS = { + "version": "2.0.2" +}; diff --git a/misc/openlayers/lib/OpenLayers/Format/CSWGetDomain/v2_0_2.js b/misc/openlayers/lib/OpenLayers/Format/CSWGetDomain/v2_0_2.js new file mode 100644 index 0000000..78200ea --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/CSWGetDomain/v2_0_2.js @@ -0,0 +1,240 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Format/CSWGetDomain.js + */ + +/** + * Class: OpenLayers.Format.CSWGetDomain.v2_0_2 + * A format for creating CSWGetDomain v2.0.2 transactions. + * Create a new instance with the + * <OpenLayers.Format.CSWGetDomain.v2_0_2> constructor. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.CSWGetDomain.v2_0_2 = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance", + csw: "http://www.opengis.net/cat/csw/2.0.2" + }, + + /** + * Property: defaultPrefix + * {String} The default prefix (used by Format.XML). + */ + defaultPrefix: "csw", + + /** + * Property: version + * {String} CSW version number. + */ + version: "2.0.2", + + /** + * Property: schemaLocation + * {String} http://www.opengis.net/cat/csw/2.0.2 + * http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd + */ + schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", + + /** + * APIProperty: PropertyName + * {String} Value of the csw:PropertyName element, used when + * writing a GetDomain document. + */ + PropertyName: null, + + /** + * APIProperty: ParameterName + * {String} Value of the csw:ParameterName element, used when + * writing a GetDomain document. + */ + ParameterName: null, + + /** + * Constructor: OpenLayers.Format.CSWGetDomain.v2_0_2 + * A class for parsing and generating CSWGetDomain v2.0.2 transactions. + * + * Parameters: + * options - {Object} Optional object whose properties will be set on the + * instance. + * + * Valid options properties: + * - PropertyName + * - ParameterName + */ + + /** + * APIMethod: read + * Parse the response from a GetDomain request. + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + if(data && data.nodeType == 9) { + data = data.documentElement; + } + var obj = {}; + this.readNode(data, obj); + return obj; + }, + + /** + * 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: { + "csw": { + "GetDomainResponse": function(node, obj) { + this.readChildNodes(node, obj); + }, + "DomainValues": function(node, obj) { + if (!(OpenLayers.Util.isArray(obj.DomainValues))) { + obj.DomainValues = []; + } + var attrs = node.attributes; + var domainValue = {}; + for(var i=0, len=attrs.length; i<len; ++i) { + domainValue[attrs[i].name] = attrs[i].nodeValue; + } + this.readChildNodes(node, domainValue); + obj.DomainValues.push(domainValue); + }, + "PropertyName": function(node, obj) { + obj.PropertyName = this.getChildValue(node); + }, + "ParameterName": function(node, obj) { + obj.ParameterName = this.getChildValue(node); + }, + "ListOfValues": function(node, obj) { + if (!(OpenLayers.Util.isArray(obj.ListOfValues))) { + obj.ListOfValues = []; + } + this.readChildNodes(node, obj.ListOfValues); + }, + "Value": function(node, obj) { + var attrs = node.attributes; + var value = {}; + for(var i=0, len=attrs.length; i<len; ++i) { + value[attrs[i].name] = attrs[i].nodeValue; + } + value.value = this.getChildValue(node); + obj.push({Value: value}); + }, + "ConceptualScheme": function(node, obj) { + obj.ConceptualScheme = {}; + this.readChildNodes(node, obj.ConceptualScheme); + }, + "Name": function(node, obj) { + obj.Name = this.getChildValue(node); + }, + "Document": function(node, obj) { + obj.Document = this.getChildValue(node); + }, + "Authority": function(node, obj) { + obj.Authority = this.getChildValue(node); + }, + "RangeOfValues": function(node, obj) { + obj.RangeOfValues = {}; + this.readChildNodes(node, obj.RangeOfValues); + }, + "MinValue": function(node, obj) { + var attrs = node.attributes; + var value = {}; + for(var i=0, len=attrs.length; i<len; ++i) { + value[attrs[i].name] = attrs[i].nodeValue; + } + value.value = this.getChildValue(node); + obj.MinValue = value; + }, + "MaxValue": function(node, obj) { + var attrs = node.attributes; + var value = {}; + for(var i=0, len=attrs.length; i<len; ++i) { + value[attrs[i].name] = attrs[i].nodeValue; + } + value.value = this.getChildValue(node); + obj.MaxValue = value; + } + } + }, + + /** + * APIMethod: write + * Given an configuration js object, write a CSWGetDomain request. + * + * Parameters: + * options - {Object} A object mapping the request. + * + * Returns: + * {String} A serialized CSWGetDomain request. + */ + write: function(options) { + var node = this.writeNode("csw:GetDomain", options); + return OpenLayers.Format.XML.prototype.write.apply(this, [node]); + }, + + /** + * 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: { + "csw": { + "GetDomain": function(options) { + var node = this.createElementNSPlus("csw:GetDomain", { + attributes: { + service: "CSW", + version: this.version + } + }); + if (options.PropertyName || this.PropertyName) { + this.writeNode( + "csw:PropertyName", + options.PropertyName || this.PropertyName, + node + ); + } else if (options.ParameterName || this.ParameterName) { + this.writeNode( + "csw:ParameterName", + options.ParameterName || this.ParameterName, + node + ); + } + this.readChildNodes(node, options); + return node; + }, + "PropertyName": function(value) { + var node = this.createElementNSPlus("csw:PropertyName", { + value: value + }); + return node; + }, + "ParameterName": function(value) { + var node = this.createElementNSPlus("csw:ParameterName", { + value: value + }); + return node; + } + } + }, + + CLASS_NAME: "OpenLayers.Format.CSWGetDomain.v2_0_2" +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/CSWGetRecords.js b/misc/openlayers/lib/OpenLayers/Format/CSWGetRecords.js new file mode 100644 index 0000000..923c548 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/CSWGetRecords.js @@ -0,0 +1,34 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format.js + */ + +/** + * Class: OpenLayers.Format.CSWGetRecords + * Default version is 2.0.2. + * + * Returns: + * {<OpenLayers.Format>} A CSWGetRecords format of the given version. + */ +OpenLayers.Format.CSWGetRecords = function(options) { + options = OpenLayers.Util.applyDefaults( + options, OpenLayers.Format.CSWGetRecords.DEFAULTS + ); + var cls = OpenLayers.Format.CSWGetRecords["v"+options.version.replace(/\./g, "_")]; + if(!cls) { + throw "Unsupported CSWGetRecords version: " + options.version; + } + return new cls(options); +}; + +/** + * Constant: DEFAULTS + * {Object} Default properties for the CSWGetRecords format. + */ +OpenLayers.Format.CSWGetRecords.DEFAULTS = { + "version": "2.0.2" +}; diff --git a/misc/openlayers/lib/OpenLayers/Format/CSWGetRecords/v2_0_2.js b/misc/openlayers/lib/OpenLayers/Format/CSWGetRecords/v2_0_2.js new file mode 100644 index 0000000..3c87612 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/CSWGetRecords/v2_0_2.js @@ -0,0 +1,457 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Format/CSWGetRecords.js + * @requires OpenLayers/Format/Filter/v1_0_0.js + * @requires OpenLayers/Format/Filter/v1_1_0.js + * @requires OpenLayers/Format/OWSCommon/v1_0_0.js + */ + +/** + * Class: OpenLayers.Format.CSWGetRecords.v2_0_2 + * A format for creating CSWGetRecords v2.0.2 transactions. + * Create a new instance with the + * <OpenLayers.Format.CSWGetRecords.v2_0_2> constructor. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.CSWGetRecords.v2_0_2 = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + csw: "http://www.opengis.net/cat/csw/2.0.2", + dc: "http://purl.org/dc/elements/1.1/", + dct: "http://purl.org/dc/terms/", + gmd: "http://www.isotc211.org/2005/gmd", + geonet: "http://www.fao.org/geonetwork", + ogc: "http://www.opengis.net/ogc", + ows: "http://www.opengis.net/ows", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance" + }, + + /** + * Property: defaultPrefix + * {String} The default prefix (used by Format.XML). + */ + defaultPrefix: "csw", + + /** + * Property: version + * {String} CSW version number. + */ + version: "2.0.2", + + /** + * Property: schemaLocation + * {String} http://www.opengis.net/cat/csw/2.0.2 + * http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd + */ + schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", + + /** + * APIProperty: requestId + * {String} Value of the requestId attribute of the GetRecords element. + */ + requestId: null, + + /** + * APIProperty: resultType + * {String} Value of the resultType attribute of the GetRecords element, + * specifies the result type in the GetRecords response, "hits" is + * the default. + */ + resultType: null, + + /** + * APIProperty: outputFormat + * {String} Value of the outputFormat attribute of the GetRecords element, + * specifies the format of the GetRecords response, + * "application/xml" is the default. + */ + outputFormat: null, + + /** + * APIProperty: outputSchema + * {String} Value of the outputSchema attribute of the GetRecords element, + * specifies the schema of the GetRecords response. + */ + outputSchema: null, + + /** + * APIProperty: startPosition + * {String} Value of the startPosition attribute of the GetRecords element, + * specifies the start position (offset+1) for the GetRecords response, + * 1 is the default. + */ + startPosition: null, + + /** + * APIProperty: maxRecords + * {String} Value of the maxRecords attribute of the GetRecords element, + * specifies the maximum number of records in the GetRecords response, + * 10 is the default. + */ + maxRecords: null, + + /** + * APIProperty: DistributedSearch + * {String} Value of the csw:DistributedSearch element, used when writing + * a csw:GetRecords document. + */ + DistributedSearch: null, + + /** + * APIProperty: ResponseHandler + * {Array({String})} Values of the csw:ResponseHandler elements, used when + * writting a csw:GetRecords document. + */ + ResponseHandler: null, + + /** + * APIProperty: Query + * {String} Value of the csw:Query element, used when writing a csw:GetRecords + * document. + */ + Query: null, + + /** + * Property: regExes + * Compiled regular expressions for manipulating strings. + */ + regExes: { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g) + }, + + /** + * Constructor: OpenLayers.Format.CSWGetRecords.v2_0_2 + * A class for parsing and generating CSWGetRecords v2.0.2 transactions. + * + * Parameters: + * options - {Object} Optional object whose properties will be set on the + * instance. + * + * Valid options properties (documented as class properties): + * - requestId + * - resultType + * - outputFormat + * - outputSchema + * - startPosition + * - maxRecords + * - DistributedSearch + * - ResponseHandler + * - Query + */ + initialize: function(options) { + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); + }, + + /** + * APIMethod: read + * Parse the response from a GetRecords request. + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + if(data && data.nodeType == 9) { + data = data.documentElement; + } + var obj = {}; + this.readNode(data, obj); + return obj; + }, + + /** + * 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: { + "csw": { + "GetRecordsResponse": function(node, obj) { + obj.records = []; + this.readChildNodes(node, obj); + var version = this.getAttributeNS(node, "", 'version'); + if (version != "") { + obj.version = version; + } + }, + "RequestId": function(node, obj) { + obj.RequestId = this.getChildValue(node); + }, + "SearchStatus": function(node, obj) { + obj.SearchStatus = {}; + var timestamp = this.getAttributeNS(node, "", 'timestamp'); + if (timestamp != "") { + obj.SearchStatus.timestamp = timestamp; + } + }, + "SearchResults": function(node, obj) { + this.readChildNodes(node, obj); + var attrs = node.attributes; + var SearchResults = {}; + for(var i=0, len=attrs.length; i<len; ++i) { + if ((attrs[i].name == "numberOfRecordsMatched") || + (attrs[i].name == "numberOfRecordsReturned") || + (attrs[i].name == "nextRecord")) { + SearchResults[attrs[i].name] = parseInt(attrs[i].nodeValue); + } else { + SearchResults[attrs[i].name] = attrs[i].nodeValue; + } + } + obj.SearchResults = SearchResults; + }, + "SummaryRecord": function(node, obj) { + var record = {type: "SummaryRecord"}; + this.readChildNodes(node, record); + obj.records.push(record); + }, + "BriefRecord": function(node, obj) { + var record = {type: "BriefRecord"}; + this.readChildNodes(node, record); + obj.records.push(record); + }, + "DCMIRecord": function(node, obj) { + var record = {type: "DCMIRecord"}; + this.readChildNodes(node, record); + obj.records.push(record); + }, + "Record": function(node, obj) { + var record = {type: "Record"}; + this.readChildNodes(node, record); + obj.records.push(record); + }, + "*": function(node, obj) { + var name = node.localName || node.nodeName.split(":").pop(); + obj[name] = this.getChildValue(node); + } + }, + "geonet": { + "info": function(node, obj) { + var gninfo = {}; + this.readChildNodes(node, gninfo); + obj.gninfo = gninfo; + } + }, + "dc": { + // audience, contributor, coverage, creator, date, description, format, + // identifier, language, provenance, publisher, relation, rights, + // rightsHolder, source, subject, title, type, URI + "*": function(node, obj) { + var name = node.localName || node.nodeName.split(":").pop(); + if (!(OpenLayers.Util.isArray(obj[name]))) { + obj[name] = []; + } + var dc_element = {}; + var attrs = node.attributes; + for(var i=0, len=attrs.length; i<len; ++i) { + dc_element[attrs[i].name] = attrs[i].nodeValue; + } + dc_element.value = this.getChildValue(node); + if (dc_element.value != "") { + obj[name].push(dc_element); + } + } + }, + "dct": { + // abstract, modified, spatial + "*": function(node, obj) { + var name = node.localName || node.nodeName.split(":").pop(); + if (!(OpenLayers.Util.isArray(obj[name]))) { + obj[name] = []; + } + obj[name].push(this.getChildValue(node)); + } + }, + "ows": OpenLayers.Util.applyDefaults({ + "BoundingBox": function(node, obj) { + if (obj.bounds) { + obj.BoundingBox = [{crs: obj.projection, value: + [ + obj.bounds.left, + obj.bounds.bottom, + obj.bounds.right, + obj.bounds.top + ] + }]; + delete obj.projection; + delete obj.bounds; + } + OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]["BoundingBox"].apply( + this, arguments); + } + }, OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]) + }, + + /** + * Method: write + * Given an configuration js object, write a CSWGetRecords request. + * + * Parameters: + * options - {Object} A object mapping the request. + * + * Returns: + * {String} A serialized CSWGetRecords request. + */ + write: function(options) { + var node = this.writeNode("csw:GetRecords", options); + node.setAttribute("xmlns:gmd", this.namespaces.gmd); + return OpenLayers.Format.XML.prototype.write.apply(this, [node]); + }, + + /** + * 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: { + "csw": { + "GetRecords": function(options) { + if (!options) { + options = {}; + } + var node = this.createElementNSPlus("csw:GetRecords", { + attributes: { + service: "CSW", + version: this.version, + requestId: options.requestId || this.requestId, + resultType: options.resultType || this.resultType, + outputFormat: options.outputFormat || this.outputFormat, + outputSchema: options.outputSchema || this.outputSchema, + startPosition: options.startPosition || this.startPosition, + maxRecords: options.maxRecords || this.maxRecords + } + }); + if (options.DistributedSearch || this.DistributedSearch) { + this.writeNode( + "csw:DistributedSearch", + options.DistributedSearch || this.DistributedSearch, + node + ); + } + var ResponseHandler = options.ResponseHandler || this.ResponseHandler; + if (OpenLayers.Util.isArray(ResponseHandler) && ResponseHandler.length > 0) { + // ResponseHandler must be a non-empty array + for(var i=0, len=ResponseHandler.length; i<len; i++) { + this.writeNode( + "csw:ResponseHandler", + ResponseHandler[i], + node + ); + } + } + this.writeNode("Query", options.Query || this.Query, node); + return node; + }, + "DistributedSearch": function(options) { + var node = this.createElementNSPlus("csw:DistributedSearch", { + attributes: { + hopCount: options.hopCount + } + }); + return node; + }, + "ResponseHandler": function(options) { + var node = this.createElementNSPlus("csw:ResponseHandler", { + value: options.value + }); + return node; + }, + "Query": function(options) { + if (!options) { + options = {}; + } + var node = this.createElementNSPlus("csw:Query", { + attributes: { + typeNames: options.typeNames || "csw:Record" + } + }); + var ElementName = options.ElementName; + if (OpenLayers.Util.isArray(ElementName) && ElementName.length > 0) { + // ElementName must be a non-empty array + for(var i=0, len=ElementName.length; i<len; i++) { + this.writeNode( + "csw:ElementName", + ElementName[i], + node + ); + } + } else { + this.writeNode( + "csw:ElementSetName", + options.ElementSetName || {value: 'summary'}, + node + ); + } + if (options.Constraint) { + this.writeNode( + "csw:Constraint", + options.Constraint, + node + ); + } + if (options.SortBy) { + this.writeNode( + "ogc:SortBy", + options.SortBy, + node + ); + } + return node; + }, + "ElementName": function(options) { + var node = this.createElementNSPlus("csw:ElementName", { + value: options.value + }); + return node; + }, + "ElementSetName": function(options) { + var node = this.createElementNSPlus("csw:ElementSetName", { + attributes: { + typeNames: options.typeNames + }, + value: options.value + }); + return node; + }, + "Constraint": function(options) { + var node = this.createElementNSPlus("csw:Constraint", { + attributes: { + version: options.version + } + }); + if (options.Filter) { + var format = new OpenLayers.Format.Filter({ + version: options.version + }); + node.appendChild(format.write(options.Filter)); + } else if (options.CqlText) { + var child = this.createElementNSPlus("CqlText", { + value: options.CqlText.value + }); + node.appendChild(child); + } + return node; + } + }, + "ogc": OpenLayers.Format.Filter.v1_1_0.prototype.writers["ogc"] + }, + + CLASS_NAME: "OpenLayers.Format.CSWGetRecords.v2_0_2" +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/Context.js b/misc/openlayers/lib/OpenLayers/Format/Context.js new file mode 100644 index 0000000..73d6203 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/Context.js @@ -0,0 +1,334 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML/VersionedOGC.js + */ + +/** + * Class: OpenLayers.Format.Context + * Base class for both Format.WMC and Format.OWSContext + * + * Inherits from: + * - <OpenLayers.Format.XML.VersionedOGC> + */ +OpenLayers.Format.Context = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { + + /** + * Property: layerOptions + * {Object} Default options for layers created by the parser. These + * options are overridden by the options which are read from the + * capabilities document. + */ + layerOptions: null, + + /** + * Property: layerParams + * {Object} Default parameters for layers created by the parser. This + * can be used e.g. to override DEFAULT_PARAMS for + * OpenLayers.Layer.WMS. + */ + layerParams: null, + + /** + * Constructor: OpenLayers.Format.Context + * Create a new parser for Context documents. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Read Context data from a string, and return an object with map + * properties and a list of layers. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * options - {Object} The options object must contain a map property. If + * the map property is a string, it must be the id of a dom element + * where the new map will be placed. If the map property is an + * <OpenLayers.Map>, the layers from the context document will be added + * to the map. + * + * Returns: + * {<OpenLayers.Map>} A map based on the context. + */ + read: function(data, options) { + var context = OpenLayers.Format.XML.VersionedOGC.prototype.read.apply(this, + arguments); + var map; + if(options && options.map) { + this.context = context; + if(options.map instanceof OpenLayers.Map) { + map = this.mergeContextToMap(context, options.map); + } else { + var mapOptions = options.map; + if(OpenLayers.Util.isElement(mapOptions) || + typeof mapOptions == "string") { + // we assume mapOptions references a div + // element + mapOptions = {div: mapOptions}; + } + map = this.contextToMap(context, mapOptions); + } + } else { + // not documented as part of the API, provided as a non-API option + map = context; + } + return map; + }, + + /** + * Method: getLayerFromContext + * Create a WMS layer from a layerContext object. + * + * Parameters: + * layerContext - {Object} An object representing a WMS layer. + * + * Returns: + * {<OpenLayers.Layer.WMS>} A WMS layer. + */ + getLayerFromContext: function(layerContext) { + var i, len; + // fill initial options object from layerContext + var options = { + queryable: layerContext.queryable, //keep queryable for api compatibility + visibility: layerContext.visibility, + maxExtent: layerContext.maxExtent, + metadata: OpenLayers.Util.applyDefaults(layerContext.metadata, + {styles: layerContext.styles, + formats: layerContext.formats, + "abstract": layerContext["abstract"], + dataURL: layerContext.dataURL + }), + numZoomLevels: layerContext.numZoomLevels, + units: layerContext.units, + isBaseLayer: layerContext.isBaseLayer, + opacity: layerContext.opacity, + displayInLayerSwitcher: layerContext.displayInLayerSwitcher, + singleTile: layerContext.singleTile, + tileSize: (layerContext.tileSize) ? + new OpenLayers.Size( + layerContext.tileSize.width, + layerContext.tileSize.height + ) : undefined, + minScale: layerContext.minScale || layerContext.maxScaleDenominator, + maxScale: layerContext.maxScale || layerContext.minScaleDenominator, + srs: layerContext.srs, + dimensions: layerContext.dimensions, + metadataURL: layerContext.metadataURL + }; + if (this.layerOptions) { + OpenLayers.Util.applyDefaults(options, this.layerOptions); + } + + var params = { + layers: layerContext.name, + transparent: layerContext.transparent, + version: layerContext.version + }; + if (layerContext.formats && layerContext.formats.length>0) { + // set default value for params if current attribute is not positionned + params.format = layerContext.formats[0].value; + for (i=0, len=layerContext.formats.length; i<len; i++) { + var format = layerContext.formats[i]; + if (format.current == true) { + params.format = format.value; + break; + } + } + } + if (layerContext.styles && layerContext.styles.length>0) { + for (i=0, len=layerContext.styles.length; i<len; i++) { + var style = layerContext.styles[i]; + if (style.current == true) { + // three style types to consider + // 1) linked SLD + // 2) inline SLD + // 3) named style + if(style.href) { + params.sld = style.href; + } else if(style.body) { + params.sld_body = style.body; + } else { + params.styles = style.name; + } + break; + } + } + } + if (this.layerParams) { + OpenLayers.Util.applyDefaults(params, this.layerParams); + } + + var layer = null; + var service = layerContext.service; + if (service == OpenLayers.Format.Context.serviceTypes.WFS) { + options.strategies = [new OpenLayers.Strategy.BBOX()]; + options.protocol = new OpenLayers.Protocol.WFS({ + url: layerContext.url, + // since we do not know featureNS, let the protocol + // determine it automagically using featurePrefix + featurePrefix: layerContext.name.split(":")[0], + featureType: layerContext.name.split(":").pop() + }); + layer = new OpenLayers.Layer.Vector( + layerContext.title || layerContext.name, + options + ); + } else if (service == OpenLayers.Format.Context.serviceTypes.KML) { + // use a vector layer with an HTTP Protcol and a Fixed strategy + options.strategies = [new OpenLayers.Strategy.Fixed()]; + options.protocol = new OpenLayers.Protocol.HTTP({ + url: layerContext.url, + format: new OpenLayers.Format.KML() + }); + layer = new OpenLayers.Layer.Vector( + layerContext.title || layerContext.name, + options + ); + } else if (service == OpenLayers.Format.Context.serviceTypes.GML) { + // use a vector layer with a HTTP Protocol and a Fixed strategy + options.strategies = [new OpenLayers.Strategy.Fixed()]; + options.protocol = new OpenLayers.Protocol.HTTP({ + url: layerContext.url, + format: new OpenLayers.Format.GML() + }); + layer = new OpenLayers.Layer.Vector( + layerContext.title || layerContext.name, + options + ); + } else if (layerContext.features) { + // inline GML or KML features + layer = new OpenLayers.Layer.Vector( + layerContext.title || layerContext.name, + options + ); + layer.addFeatures(layerContext.features); + } else if (layerContext.categoryLayer !== true) { + layer = new OpenLayers.Layer.WMS( + layerContext.title || layerContext.name, + layerContext.url, + params, + options + ); + } + return layer; + }, + + /** + * Method: getLayersFromContext + * Create an array of layers from an array of layerContext objects. + * + * Parameters: + * layersContext - {Array(Object)} An array of objects representing layers. + * + * Returns: + * {Array(<OpenLayers.Layer>)} An array of layers. + */ + getLayersFromContext: function(layersContext) { + var layers = []; + for (var i=0, len=layersContext.length; i<len; i++) { + var layer = this.getLayerFromContext(layersContext[i]); + if (layer !== null) { + layers.push(layer); + } + } + return layers; + }, + + /** + * Method: contextToMap + * Create a map given a context object. + * + * Parameters: + * context - {Object} The context object. + * options - {Object} Default map options. + * + * Returns: + * {<OpenLayers.Map>} A map based on the context object. + */ + contextToMap: function(context, options) { + options = OpenLayers.Util.applyDefaults({ + maxExtent: context.maxExtent, + projection: context.projection, + units: context.units + }, options); + + if (options.maxExtent) { + options.maxResolution = + options.maxExtent.getWidth() / OpenLayers.Map.TILE_WIDTH; + } + + var metadata = { + contactInformation: context.contactInformation, + "abstract": context["abstract"], + keywords: context.keywords, + logo: context.logo, + descriptionURL: context.descriptionURL + }; + + options.metadata = metadata; + + var map = new OpenLayers.Map(options); + map.addLayers(this.getLayersFromContext(context.layersContext)); + map.setCenter( + context.bounds.getCenterLonLat(), + map.getZoomForExtent(context.bounds, true) + ); + return map; + }, + + /** + * Method: mergeContextToMap + * Add layers from a context object to a map. + * + * Parameters: + * context - {Object} The context object. + * map - {<OpenLayers.Map>} The map. + * + * Returns: + * {<OpenLayers.Map>} The same map with layers added. + */ + mergeContextToMap: function(context, map) { + map.addLayers(this.getLayersFromContext(context.layersContext)); + return map; + }, + + /** + * APIMethod: write + * Write a context document given a map. + * + * Parameters: + * obj - {<OpenLayers.Map> | Object} A map or context object. + * options - {Object} Optional configuration object. + * + * Returns: + * {String} A context document string. + */ + write: function(obj, options) { + obj = this.toContext(obj); + return OpenLayers.Format.XML.VersionedOGC.prototype.write.apply(this, + arguments); + }, + + CLASS_NAME: "OpenLayers.Format.Context" +}); + +/** + * Constant: OpenLayers.Format.Context.serviceTypes + * Enumeration for service types + */ +OpenLayers.Format.Context.serviceTypes = { + "WMS": "urn:ogc:serviceType:WMS", + "WFS": "urn:ogc:serviceType:WFS", + "WCS": "urn:ogc:serviceType:WCS", + "GML": "urn:ogc:serviceType:GML", + "SLD": "urn:ogc:serviceType:SLD", + "FES": "urn:ogc:serviceType:FES", + "KML": "urn:ogc:serviceType:KML" +}; diff --git a/misc/openlayers/lib/OpenLayers/Format/EncodedPolyline.js b/misc/openlayers/lib/OpenLayers/Format/EncodedPolyline.js new file mode 100644 index 0000000..e10e8b2 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/EncodedPolyline.js @@ -0,0 +1,557 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format.js + * @requires OpenLayers/Feature/Vector.js + */ + +/** + * Class: OpenLayers.Format.EncodedPolyline + * Class for reading and writing encoded polylines. Create a new instance + * with the <OpenLayers.Format.EncodedPolyline> constructor. + * + * Inherits from: + * - <OpenLayers.Format> + */ +OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { + + /** + * APIProperty: geometryType + * {String} Geometry type to output. One of: linestring (default), + * linearring, point, multipoint or polygon. If the geometryType is + * point, only the first point of the string is returned. + */ + geometryType: "linestring", + + /** + * Constructor: OpenLayers.Format.EncodedPolyline + * Create a new parser for encoded polylines + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance + * + * Returns: + * {<OpenLayers.Format.EncodedPolyline>} A new encoded polylines parser. + */ + initialize: function(options) { + OpenLayers.Format.prototype.initialize.apply(this, [options]); + }, + + /** + * APIMethod: read + * Deserialize an encoded polyline string and return a vector feature. + * + * Parameters: + * encoded - {String} An encoded polyline string + * + * Returns: + * {<OpenLayers.Feature.Vector>} A vector feature with a linestring. + */ + read: function(encoded) { + var geomType; + if (this.geometryType == "linestring") + geomType = OpenLayers.Geometry.LineString; + else if (this.geometryType == "linearring") + geomType = OpenLayers.Geometry.LinearRing; + else if (this.geometryType == "multipoint") + geomType = OpenLayers.Geometry.MultiPoint; + else if (this.geometryType != "point" && this.geometryType != "polygon") + return null; + + var flatPoints = this.decodeDeltas(encoded, 2); + var flatPointsLength = flatPoints.length; + + var pointGeometries = []; + for (var i = 0; i + 1 < flatPointsLength;) { + var y = flatPoints[i++], x = flatPoints[i++]; + pointGeometries.push(new OpenLayers.Geometry.Point(x, y)); + } + + + if (this.geometryType == "point") + return new OpenLayers.Feature.Vector( + pointGeometries[0] + ); + + if (this.geometryType == "polygon") + return new OpenLayers.Feature.Vector( + new OpenLayers.Geometry.Polygon([ + new OpenLayers.Geometry.LinearRing(pointGeometries) + ]) + ); + + return new OpenLayers.Feature.Vector( + new geomType(pointGeometries) + ); + }, + + /** + * APIMethod: decode + * Deserialize an encoded string and return an array of n-dimensional + * points. + * + * Parameters: + * encoded - {String} An encoded string + * dims - {int} The dimension of the points that are returned + * + * Returns: + * {Array(Array(int))} An array containing n-dimensional arrays of + * coordinates. + */ + decode: function(encoded, dims, opt_factor) { + var factor = opt_factor || 1e5; + var flatPoints = this.decodeDeltas(encoded, dims, factor); + var flatPointsLength = flatPoints.length; + + var points = []; + for (var i = 0; i + (dims - 1) < flatPointsLength;) { + var point = []; + + for (var dim = 0; dim < dims; ++dim) { + point.push(flatPoints[i++]) + } + + points.push(point); + } + + return points; + }, + + /** + * APIMethod: write + * Serialize a feature or array of features into a WKT string. + * + * Parameters: + * features - {<OpenLayers.Feature.Vector>|Array} A feature or array of + * features + * + * Returns: + * {String} The WKT string representation of the input geometries + */ + write: function(features) { + var feature; + if (features.constructor == Array) + feature = features[0]; + else + feature = features; + + var geometry = feature.geometry; + var type = geometry.CLASS_NAME.split('.')[2].toLowerCase(); + + var pointGeometries; + if (type == "point") + pointGeometries = new Array(geometry); + else if (type == "linestring" || + type == "linearring" || + type == "multipoint") + pointGeometries = geometry.components; + else if (type == "polygon") + pointGeometries = geometry.components[0].components; + else + return null; + + var flatPoints = []; + + var pointGeometriesLength = pointGeometries.length; + for (var i = 0; i < pointGeometriesLength; ++i) { + var pointGeometry = pointGeometries[i]; + flatPoints.push(pointGeometry.y); + flatPoints.push(pointGeometry.x); + } + + return this.encodeDeltas(flatPoints, 2); + }, + + /** + * APIMethod: encode + * Serialize an array of n-dimensional points and return an encoded string + * + * Parameters: + * points - {Array(Array(int))} An array containing n-dimensional + * arrays of coordinates + * dims - {int} The dimension of the points that should be read + * + * Returns: + * {String} An encoded string + */ + encode: function (points, dims, opt_factor) { + var factor = opt_factor || 1e5; + var flatPoints = []; + + var pointsLength = points.length; + for (var i = 0; i < pointsLength; ++i) { + var point = points[i]; + + for (var dim = 0; dim < dims; ++dim) { + flatPoints.push(point[dim]); + } + } + + return this.encodeDeltas(flatPoints, dims, factor); + }, + + /** + * APIMethod: encodeDeltas + * Encode a list of n-dimensional points and return an encoded string + * + * Attention: This function will modify the passed array! + * + * Parameters: + * numbers - {Array.<number>} A list of n-dimensional points. + * dimension - {number} The dimension of the points in the list. + * opt_factor - {number=} The factor by which the numbers will be + * multiplied. The remaining decimal places will get rounded away. + * + * Returns: + * {string} The encoded string. + */ + encodeDeltas: function(numbers, dimension, opt_factor) { + var factor = opt_factor || 1e5; + var d; + + var lastNumbers = new Array(dimension); + for (d = 0; d < dimension; ++d) { + lastNumbers[d] = 0; + } + + var numbersLength = numbers.length; + for (var i = 0; i < numbersLength;) { + for (d = 0; d < dimension; ++d, ++i) { + var num = numbers[i]; + var delta = num - lastNumbers[d]; + lastNumbers[d] = num; + + numbers[i] = delta; + } + } + + return this.encodeFloats(numbers, factor); + }, + + + /** + * APIMethod: decodeDeltas + * Decode a list of n-dimensional points from an encoded string + * + * Parameters: + * encoded - {string} An encoded string. + * dimension - {number} The dimension of the points in the encoded string. + * opt_factor - {number=} The factor by which the resulting numbers will + * be divided. + * + * Returns: + * {Array.<number>} A list of n-dimensional points. + */ + decodeDeltas: function(encoded, dimension, opt_factor) { + var factor = opt_factor || 1e5; + var d; + + var lastNumbers = new Array(dimension); + for (d = 0; d < dimension; ++d) { + lastNumbers[d] = 0; + } + + var numbers = this.decodeFloats(encoded, factor); + + var numbersLength = numbers.length; + for (var i = 0; i < numbersLength;) { + for (d = 0; d < dimension; ++d, ++i) { + lastNumbers[d] += numbers[i]; + + numbers[i] = lastNumbers[d]; + } + } + + return numbers; + }, + + + /** + * APIMethod: encodeFloats + * Encode a list of floating point numbers and return an encoded string + * + * Attention: This function will modify the passed array! + * + * Parameters: + * numbers - {Array.<number>} A list of floating point numbers. + * opt_factor - {number=} The factor by which the numbers will be + * multiplied. The remaining decimal places will get rounded away. + * + * Returns: + * {string} The encoded string. + */ + encodeFloats: function(numbers, opt_factor) { + var factor = opt_factor || 1e5; + + var numbersLength = numbers.length; + for (var i = 0; i < numbersLength; ++i) { + numbers[i] = Math.round(numbers[i] * factor); + } + + return this.encodeSignedIntegers(numbers); + }, + + + /** + * APIMethod: decodeFloats + * Decode a list of floating point numbers from an encoded string + * + * Parameters: + * encoded - {string} An encoded string. + * opt_factor - {number=} The factor by which the result will be divided. + * + * Returns: + * {Array.<number>} A list of floating point numbers. + */ + decodeFloats: function(encoded, opt_factor) { + var factor = opt_factor || 1e5; + + var numbers = this.decodeSignedIntegers(encoded); + + var numbersLength = numbers.length; + for (var i = 0; i < numbersLength; ++i) { + numbers[i] /= factor; + } + + return numbers; + }, + + + /** + * APIMethod: encodeSignedIntegers + * Encode a list of signed integers and return an encoded string + * + * Attention: This function will modify the passed array! + * + * Parameters: + * numbers - {Array.<number>} A list of signed integers. + * + * Returns: + * {string} The encoded string. + */ + encodeSignedIntegers: function(numbers) { + var numbersLength = numbers.length; + for (var i = 0; i < numbersLength; ++i) { + var num = numbers[i]; + + var signedNum = num << 1; + if (num < 0) { + signedNum = ~(signedNum); + } + + numbers[i] = signedNum; + } + + return this.encodeUnsignedIntegers(numbers); + }, + + + /** + * APIMethod: decodeSignedIntegers + * Decode a list of signed integers from an encoded string + * + * Parameters: + * encoded - {string} An encoded string. + * + * Returns: + * {Array.<number>} A list of signed integers. + */ + decodeSignedIntegers: function(encoded) { + var numbers = this.decodeUnsignedIntegers(encoded); + + var numbersLength = numbers.length; + for (var i = 0; i < numbersLength; ++i) { + var num = numbers[i]; + numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1); + } + + return numbers; + }, + + + /** + * APIMethod: encodeUnsignedIntegers + * Encode a list of unsigned integers and return an encoded string + * + * Parameters: + * numbers - {Array.<number>} A list of unsigned integers. + * + * Returns: + * {string} The encoded string. + */ + encodeUnsignedIntegers: function(numbers) { + var encoded = ''; + + var numbersLength = numbers.length; + for (var i = 0; i < numbersLength; ++i) { + encoded += this.encodeUnsignedInteger(numbers[i]); + } + + return encoded; + }, + + + /** + * APIMethod: decodeUnsignedIntegers + * Decode a list of unsigned integers from an encoded string + * + * Parameters: + * encoded - {string} An encoded string. + * + * Returns: + * {Array.<number>} A list of unsigned integers. + */ + decodeUnsignedIntegers: function(encoded) { + var numbers = []; + + var current = 0; + var shift = 0; + + var encodedLength = encoded.length; + for (var i = 0; i < encodedLength; ++i) { + var b = encoded.charCodeAt(i) - 63; + + current |= (b & 0x1f) << shift; + + if (b < 0x20) { + numbers.push(current); + current = 0; + shift = 0; + } else { + shift += 5; + } + } + + return numbers; + }, + + + /** + * Method: encodeFloat + * Encode one single floating point number and return an encoded string + * + * Parameters: + * num - {number} Floating point number that should be encoded. + * opt_factor - {number=} The factor by which num will be multiplied. + * The remaining decimal places will get rounded away. + * + * Returns: + * {string} The encoded string. + */ + encodeFloat: function(num, opt_factor) { + num = Math.round(num * (opt_factor || 1e5)); + return this.encodeSignedInteger(num); + }, + + + /** + * Method: decodeFloat + * Decode one single floating point number from an encoded string + * + * Parameters: + * encoded - {string} An encoded string. + * opt_factor - {number=} The factor by which the result will be divided. + * + * Returns: + * {number} The decoded floating point number. + */ + decodeFloat: function(encoded, opt_factor) { + var result = this.decodeSignedInteger(encoded); + return result / (opt_factor || 1e5); + }, + + + /** + * Method: encodeSignedInteger + * Encode one single signed integer and return an encoded string + * + * Parameters: + * num - {number} Signed integer that should be encoded. + * + * Returns: + * {string} The encoded string. + */ + encodeSignedInteger: function(num) { + var signedNum = num << 1; + if (num < 0) { + signedNum = ~(signedNum); + } + + return this.encodeUnsignedInteger(signedNum); + }, + + + /** + * Method: decodeSignedInteger + * Decode one single signed integer from an encoded string + * + * Parameters: + * encoded - {string} An encoded string. + * + * Returns: + * {number} The decoded signed integer. + */ + decodeSignedInteger: function(encoded) { + var result = this.decodeUnsignedInteger(encoded); + return ((result & 1) ? ~(result >> 1) : (result >> 1)); + }, + + + /** + * Method: encodeUnsignedInteger + * Encode one single unsigned integer and return an encoded string + * + * Parameters: + * num - {number} Unsigned integer that should be encoded. + * + * Returns: + * {string} The encoded string. + */ + encodeUnsignedInteger: function(num) { + var value, encoded = ''; + while (num >= 0x20) { + value = (0x20 | (num & 0x1f)) + 63; + encoded += (String.fromCharCode(value)); + num >>= 5; + } + value = num + 63; + encoded += (String.fromCharCode(value)); + return encoded; + }, + + + /** + * Method: decodeUnsignedInteger + * Decode one single unsigned integer from an encoded string + * + * Parameters: + * encoded - {string} An encoded string. + * + * Returns: + * {number} The decoded unsigned integer. + */ + decodeUnsignedInteger: function(encoded) { + var result = 0; + var shift = 0; + + var encodedLength = encoded.length; + for (var i = 0; i < encodedLength; ++i) { + var b = encoded.charCodeAt(i) - 63; + + result |= (b & 0x1f) << shift; + + if (b < 0x20) + break; + + shift += 5; + } + + return result; + }, + + CLASS_NAME: "OpenLayers.Format.EncodedPolyline" +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/Filter.js b/misc/openlayers/lib/OpenLayers/Format/Filter.js new file mode 100644 index 0000000..59c06a8 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/Filter.js @@ -0,0 +1,53 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML/VersionedOGC.js + * @requires OpenLayers/Filter/FeatureId.js + * @requires OpenLayers/Filter/Logical.js + * @requires OpenLayers/Filter/Comparison.js + */ + +/** + * Class: OpenLayers.Format.Filter + * Read/Write ogc:Filter. Create a new instance with the <OpenLayers.Format.Filter> + * constructor. + * + * Inherits from: + * - <OpenLayers.Format.XML.VersionedOGC> + */ +OpenLayers.Format.Filter = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { + + /** + * APIProperty: defaultVersion + * {String} Version number to assume if none found. Default is "1.0.0". + */ + defaultVersion: "1.0.0", + + /** + * APIMethod: write + * Write an ogc:Filter given a filter object. + * + * Parameters: + * filter - {<OpenLayers.Filter>} An filter. + * options - {Object} Optional configuration object. + * + * Returns: + * {Elment} An ogc:Filter element node. + */ + + /** + * APIMethod: read + * Read and Filter doc and return an object representing the Filter. + * + * Parameters: + * data - {String | DOMElement} Data to read. + * + * Returns: + * {<OpenLayers.Filter>} A filter object. + */ + + CLASS_NAME: "OpenLayers.Format.Filter" +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/Filter/v1.js b/misc/openlayers/lib/OpenLayers/Format/Filter/v1.js new file mode 100644 index 0000000..539ec0f --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/Filter/v1.js @@ -0,0 +1,504 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ +/** + * @requires OpenLayers/Format/Filter.js + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Filter/Function.js + * @requires OpenLayers/BaseTypes/Date.js + */ + +/** + * Class: OpenLayers.Format.Filter.v1 + * Superclass for Filter version 1 parsers. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.Filter.v1 = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + ogc: "http://www.opengis.net/ogc", + gml: "http://www.opengis.net/gml", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance" + }, + + /** + * Property: defaultPrefix + */ + defaultPrefix: "ogc", + + /** + * Property: schemaLocation + * {String} Schema location for a particular minor version. + */ + schemaLocation: null, + + /** + * Constructor: OpenLayers.Format.Filter.v1 + * Instances of this class are not created directly. Use the + * <OpenLayers.Format.Filter> 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} A Filter document element. + * + * Returns: + * {<OpenLayers.Filter>} A filter object. + */ + read: function(data) { + var obj = {}; + this.readers.ogc["Filter"].apply(this, [data, obj]); + return obj.filter; + }, + + /** + * 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: { + "ogc": { + "_expression": function(node) { + // only the simplest of ogc:expression handled + // "some text and an <PropertyName>attribute</PropertyName>"} + 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 + // create a temporary object and then pass on the filter + // (ogc:Filter) to the parent obj. + var obj = { + fids: [], + filters: [] + }; + this.readChildNodes(node, obj); + if(obj.fids.length > 0) { + parent.filter = new OpenLayers.Filter.FeatureId({ + fids: obj.fids + }); + } else if(obj.filters.length > 0) { + parent.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); + }, + "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); + }, + "Literal": function(node, obj) { + obj.value = OpenLayers.String.numericIf( + this.getChildValue(node), true); + }, + "PropertyName": function(node, filter) { + filter.property = this.getChildValue(node); + }, + "LowerBoundary": function(node, filter) { + filter.lowerBoundary = OpenLayers.String.numericIf( + this.readers.ogc._expression.call(this, node), true); + }, + "UpperBoundary": function(node, filter) { + filter.upperBoundary = OpenLayers.String.numericIf( + this.readers.ogc._expression.call(this, node), true); + }, + "Intersects": function(node, obj) { + this.readSpatial(node, obj, OpenLayers.Filter.Spatial.INTERSECTS); + }, + "Within": function(node, obj) { + this.readSpatial(node, obj, OpenLayers.Filter.Spatial.WITHIN); + }, + "Contains": function(node, obj) { + this.readSpatial(node, obj, OpenLayers.Filter.Spatial.CONTAINS); + }, + "DWithin": function(node, obj) { + this.readSpatial(node, obj, OpenLayers.Filter.Spatial.DWITHIN); + }, + "Distance": function(node, obj) { + obj.distance = parseInt(this.getChildValue(node)); + obj.distanceUnits = node.getAttribute("units"); + }, + "Function": function(node, obj) { + //TODO write decoder for it + return; + }, + "PropertyIsNull": function(node, obj) { + var filter = new OpenLayers.Filter.Comparison({ + type: OpenLayers.Filter.Comparison.IS_NULL + }); + this.readChildNodes(node, filter); + obj.filters.push(filter); + } + } + }, + + /** + * Method: readSpatial + * + * Read a {<OpenLayers.Filter.Spatial>} filter. + * + * Parameters: + * node - {DOMElement} A DOM element that contains an ogc:expression. + * obj - {Object} The target object. + * type - {String} One of the OpenLayers.Filter.Spatial.* constants. + * + * Returns: + * {<OpenLayers.Filter.Spatial>} The created filter. + */ + readSpatial: function(node, obj, type) { + var filter = new OpenLayers.Filter.Spatial({ + type: type + }); + this.readChildNodes(node, filter); + filter.value = filter.components[0]; + delete filter.components; + obj.filters.push(filter); + }, + + /** + * APIMethod: encodeLiteral + * Generates the string representation of a value for use in <Literal> + * elements. The default encoder writes Date values as ISO 8601 + * strings. + * + * Parameters: + * value - {Object} Literal value to encode + * + * Returns: + * {String} String representation of the provided value. + */ + encodeLiteral: function(value) { + if (value instanceof Date) { + value = OpenLayers.Date.toISOString(value); + } + return value; + }, + + /** + * Method: writeOgcExpression + * Limited support for writing OGC expressions. Currently it supports + * (<OpenLayers.Filter.Function> || String || Number) + * + * Parameters: + * value - (<OpenLayers.Filter.Function> || String || Number) + * node - {DOMElement} A parent DOM element + * + * Returns: + * {DOMElement} Updated node element. + */ + writeOgcExpression: function(value, node) { + if (value instanceof OpenLayers.Filter.Function){ + this.writeNode("Function", value, node); + } else { + this.writeNode("Literal", value, node); + } + return node; + }, + + /** + * Method: write + * + * Parameters: + * filter - {<OpenLayers.Filter>} A filter object. + * + * Returns: + * {DOMElement} An ogc:Filter element. + */ + write: function(filter) { + return this.writers.ogc["Filter"].apply(this, [filter]); + }, + + /** + * 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: { + "ogc": { + "Filter": function(filter) { + var node = this.createElementNSPlus("ogc:Filter"); + this.writeNode(this.getFilterType(filter), filter, node); + return node; + }, + "_featureIds": function(filter) { + var node = this.createDocumentFragment(); + for (var i=0, ii=filter.fids.length; i<ii; ++i) { + this.writeNode("ogc:FeatureId", filter.fids[i], node); + } + return node; + }, + "FeatureId": function(fid) { + return this.createElementNSPlus("ogc:FeatureId", { + attributes: {fid: fid} + }); + }, + "And": function(filter) { + var node = this.createElementNSPlus("ogc:And"); + var childFilter; + for (var i=0, ii=filter.filters.length; i<ii; ++i) { + childFilter = filter.filters[i]; + this.writeNode( + this.getFilterType(childFilter), childFilter, node + ); + } + return node; + }, + "Or": function(filter) { + var node = this.createElementNSPlus("ogc:Or"); + var childFilter; + for (var i=0, ii=filter.filters.length; i<ii; ++i) { + childFilter = filter.filters[i]; + this.writeNode( + this.getFilterType(childFilter), childFilter, node + ); + } + return node; + }, + "Not": function(filter) { + var node = this.createElementNSPlus("ogc:Not"); + var childFilter = filter.filters[0]; + this.writeNode( + this.getFilterType(childFilter), childFilter, node + ); + return node; + }, + "PropertyIsLessThan": function(filter) { + var node = this.createElementNSPlus("ogc:PropertyIsLessThan"); + // no ogc:expression handling for PropertyName for now + this.writeNode("PropertyName", filter, node); + // handle Literals or Functions for now + this.writeOgcExpression(filter.value, node); + return node; + }, + "PropertyIsGreaterThan": function(filter) { + var node = this.createElementNSPlus("ogc:PropertyIsGreaterThan"); + // no ogc:expression handling for PropertyName for now + this.writeNode("PropertyName", filter, node); + // handle Literals or Functions for now + this.writeOgcExpression(filter.value, node); + return node; + }, + "PropertyIsLessThanOrEqualTo": function(filter) { + var node = this.createElementNSPlus("ogc:PropertyIsLessThanOrEqualTo"); + // no ogc:expression handling for PropertyName for now + this.writeNode("PropertyName", filter, node); + // handle Literals or Functions for now + this.writeOgcExpression(filter.value, node); + return node; + }, + "PropertyIsGreaterThanOrEqualTo": function(filter) { + var node = this.createElementNSPlus("ogc:PropertyIsGreaterThanOrEqualTo"); + // no ogc:expression handling for PropertyName for now + this.writeNode("PropertyName", filter, node); + // handle Literals or Functions for now + this.writeOgcExpression(filter.value, node); + return node; + }, + "PropertyIsBetween": function(filter) { + var node = this.createElementNSPlus("ogc:PropertyIsBetween"); + // no ogc:expression handling for PropertyName for now + this.writeNode("PropertyName", filter, node); + this.writeNode("LowerBoundary", filter, node); + this.writeNode("UpperBoundary", filter, node); + return node; + }, + "PropertyName": function(filter) { + // no ogc:expression handling for now + return this.createElementNSPlus("ogc:PropertyName", { + value: filter.property + }); + }, + "Literal": function(value) { + var encode = this.encodeLiteral || + OpenLayers.Format.Filter.v1.prototype.encodeLiteral; + return this.createElementNSPlus("ogc:Literal", { + value: encode(value) + }); + }, + "LowerBoundary": function(filter) { + // handle Literals or Functions for now + var node = this.createElementNSPlus("ogc:LowerBoundary"); + this.writeOgcExpression(filter.lowerBoundary, node); + return node; + }, + "UpperBoundary": function(filter) { + // handle Literals or Functions for now + var node = this.createElementNSPlus("ogc:UpperBoundary"); + this.writeNode("Literal", filter.upperBoundary, node); + return node; + }, + "INTERSECTS": function(filter) { + return this.writeSpatial(filter, "Intersects"); + }, + "WITHIN": function(filter) { + return this.writeSpatial(filter, "Within"); + }, + "CONTAINS": function(filter) { + return this.writeSpatial(filter, "Contains"); + }, + "DWITHIN": function(filter) { + var node = this.writeSpatial(filter, "DWithin"); + this.writeNode("Distance", filter, node); + return node; + }, + "Distance": function(filter) { + return this.createElementNSPlus("ogc:Distance", { + attributes: { + units: filter.distanceUnits + }, + value: filter.distance + }); + }, + "Function": function(filter) { + var node = this.createElementNSPlus("ogc:Function", { + attributes: { + name: filter.name + } + }); + var params = filter.params; + for(var i=0, len=params.length; i<len; i++){ + this.writeOgcExpression(params[i], node); + } + return node; + }, + "PropertyIsNull": function(filter) { + var node = this.createElementNSPlus("ogc:PropertyIsNull"); + this.writeNode("PropertyName", filter, node); + return node; + } + } + }, + + /** + * Method: getFilterType + */ + getFilterType: function(filter) { + var filterType = this.filterMap[filter.type]; + if(!filterType) { + throw "Filter writing not supported for rule type: " + filter.type; + } + return filterType; + }, + + /** + * Property: filterMap + * {Object} Contains a member for each filter type. Values are node names + * for corresponding OGC Filter child elements. + */ + filterMap: { + "&&": "And", + "||": "Or", + "!": "Not", + "==": "PropertyIsEqualTo", + "!=": "PropertyIsNotEqualTo", + "<": "PropertyIsLessThan", + ">": "PropertyIsGreaterThan", + "<=": "PropertyIsLessThanOrEqualTo", + ">=": "PropertyIsGreaterThanOrEqualTo", + "..": "PropertyIsBetween", + "~": "PropertyIsLike", + "NULL": "PropertyIsNull", + "BBOX": "BBOX", + "DWITHIN": "DWITHIN", + "WITHIN": "WITHIN", + "CONTAINS": "CONTAINS", + "INTERSECTS": "INTERSECTS", + "FID": "_featureIds" + }, + + CLASS_NAME: "OpenLayers.Format.Filter.v1" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/Filter/v1_0_0.js b/misc/openlayers/lib/OpenLayers/Format/Filter/v1_0_0.js new file mode 100644 index 0000000..52e650e --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/Filter/v1_0_0.js @@ -0,0 +1,184 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/GML/v2.js + * @requires OpenLayers/Format/Filter/v1.js + */ + +/** + * Class: OpenLayers.Format.Filter.v1_0_0 + * Write ogc:Filter version 1.0.0. + * + * Inherits from: + * - <OpenLayers.Format.GML.v2> + * - <OpenLayers.Format.Filter.v1> + */ +OpenLayers.Format.Filter.v1_0_0 = OpenLayers.Class( + OpenLayers.Format.GML.v2, OpenLayers.Format.Filter.v1, { + + /** + * Constant: VERSION + * {String} 1.0.0 + */ + VERSION: "1.0.0", + + /** + * Property: schemaLocation + * {String} http://www.opengis.net/ogc/filter/1.0.0/filter.xsd + */ + schemaLocation: "http://www.opengis.net/ogc/filter/1.0.0/filter.xsd", + + /** + * Constructor: OpenLayers.Format.Filter.v1_0_0 + * Instances of this class are not created directly. Use the + * <OpenLayers.Format.Filter> constructor instead. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + OpenLayers.Format.GML.v2.prototype.initialize.apply( + this, [options] + ); + }, + + /** + * 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: { + "ogc": OpenLayers.Util.applyDefaults({ + "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); + }, + "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); + } + }, OpenLayers.Format.Filter.v1.prototype.readers["ogc"]), + "gml": OpenLayers.Format.GML.v2.prototype.readers["gml"], + "feature": OpenLayers.Format.GML.v2.prototype.readers["feature"] + }, + + /** + * 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: { + "ogc": OpenLayers.Util.applyDefaults({ + "PropertyIsEqualTo": function(filter) { + var node = this.createElementNSPlus("ogc:PropertyIsEqualTo"); + // no ogc:expression handling for PropertyName for now + this.writeNode("PropertyName", filter, node); + // handle Literals or Functions for now + this.writeOgcExpression(filter.value, node); + return node; + }, + "PropertyIsNotEqualTo": function(filter) { + var node = this.createElementNSPlus("ogc:PropertyIsNotEqualTo"); + // no ogc:expression handling for PropertyName for now + this.writeNode("PropertyName", filter, node); + // handle Literals or Functions for now + this.writeOgcExpression(filter.value, node); + return node; + }, + "PropertyIsLike": function(filter) { + var node = this.createElementNSPlus("ogc:PropertyIsLike", { + attributes: { + wildCard: "*", singleChar: ".", escape: "!" + } + }); + // no ogc:expression handling for now + this.writeNode("PropertyName", filter, node); + // convert regex string to ogc string + this.writeNode("Literal", filter.regex2value(), node); + return node; + }, + "BBOX": function(filter) { + var node = this.createElementNSPlus("ogc:BBOX"); + // PropertyName is mandatory in 1.0.0, but e.g. GeoServer also + // accepts filters without it. When this is used with + // OpenLayers.Protocol.WFS, OpenLayers.Format.WFST will set a + // missing filter.property to the geometryName that is + // configured with the protocol, which defaults to "the_geom". + // So the only way to omit this mandatory property is to not + // set the property on the filter and to set the geometryName + // on the WFS protocol to null. The latter also happens when + // the protocol is configured without a geometryName and a + // featureNS. + filter.property && this.writeNode("PropertyName", filter, node); + var box = this.writeNode("gml:Box", filter.value, node); + if(filter.projection) { + box.setAttribute("srsName", filter.projection); + } + return node; + } + }, OpenLayers.Format.Filter.v1.prototype.writers["ogc"]), + "gml": OpenLayers.Format.GML.v2.prototype.writers["gml"], + "feature": OpenLayers.Format.GML.v2.prototype.writers["feature"] + }, + + /** + * Method: writeSpatial + * + * Read a {<OpenLayers.Filter.Spatial>} filter and converts it into XML. + * + * Parameters: + * filter - {<OpenLayers.Filter.Spatial>} The filter. + * name - {String} Name of the generated XML element. + * + * Returns: + * {DOMElement} The created XML element. + */ + writeSpatial: function(filter, name) { + var node = this.createElementNSPlus("ogc:"+name); + this.writeNode("PropertyName", filter, node); + if(filter.value instanceof OpenLayers.Filter.Function) { + this.writeNode("Function", filter.value, node); + } else { + var child; + if(filter.value instanceof OpenLayers.Geometry) { + child = this.writeNode("feature:_geometry", filter.value).firstChild; + } else { + child = this.writeNode("gml:Box", filter.value); + } + if(filter.projection) { + child.setAttribute("srsName", filter.projection); + } + node.appendChild(child); + } + return node; + }, + + + CLASS_NAME: "OpenLayers.Format.Filter.v1_0_0" + +});
\ No newline at end of file diff --git a/misc/openlayers/lib/OpenLayers/Format/Filter/v1_1_0.js b/misc/openlayers/lib/OpenLayers/Format/Filter/v1_1_0.js new file mode 100644 index 0000000..628c489 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/Filter/v1_1_0.js @@ -0,0 +1,222 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/Filter/v1.js + * @requires OpenLayers/Format/GML/v3.js + */ + +/** + * Class: OpenLayers.Format.Filter.v1_1_0 + * Write ogc:Filter version 1.1.0. + * + * Differences from the v1.0.0 parser: + * - uses GML v3 instead of GML v2 + * - reads matchCase attribute on ogc:PropertyIsEqual and + * ogc:PropertyIsNotEqual elements. + * - writes matchCase attribute from comparison filters of type EQUAL_TO, + * NOT_EQUAL_TO and LIKE. + * + * Inherits from: + * - <OpenLayers.Format.GML.v3> + * - <OpenLayers.Format.Filter.v1> + */ +OpenLayers.Format.Filter.v1_1_0 = OpenLayers.Class( + OpenLayers.Format.GML.v3, OpenLayers.Format.Filter.v1, { + + /** + * Constant: VERSION + * {String} 1.1.0 + */ + VERSION: "1.1.0", + + /** + * Property: schemaLocation + * {String} http://www.opengis.net/ogc/filter/1.1.0/filter.xsd + */ + schemaLocation: "http://www.opengis.net/ogc/filter/1.1.0/filter.xsd", + + /** + * Constructor: OpenLayers.Format.Filter.v1_1_0 + * Instances of this class are not created directly. Use the + * <OpenLayers.Format.Filter> constructor instead. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + OpenLayers.Format.GML.v3.prototype.initialize.apply( + this, [options] + ); + }, + + /** + * 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: { + "ogc": OpenLayers.Util.applyDefaults({ + "PropertyIsEqualTo": function(node, obj) { + var matchCase = node.getAttribute("matchCase"); + var filter = new OpenLayers.Filter.Comparison({ + type: OpenLayers.Filter.Comparison.EQUAL_TO, + matchCase: !(matchCase === "false" || matchCase === "0") + }); + this.readChildNodes(node, filter); + obj.filters.push(filter); + }, + "PropertyIsNotEqualTo": function(node, obj) { + var matchCase = node.getAttribute("matchCase"); + var filter = new OpenLayers.Filter.Comparison({ + type: OpenLayers.Filter.Comparison.NOT_EQUAL_TO, + matchCase: !(matchCase === "false" || matchCase === "0") + }); + 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("escapeChar"); + filter.value2regex(wildCard, singleChar, esc); + obj.filters.push(filter); + } + }, OpenLayers.Format.Filter.v1.prototype.readers["ogc"]), + "gml": OpenLayers.Format.GML.v3.prototype.readers["gml"], + "feature": OpenLayers.Format.GML.v3.prototype.readers["feature"] + }, + + /** + * 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: { + "ogc": OpenLayers.Util.applyDefaults({ + "PropertyIsEqualTo": function(filter) { + var node = this.createElementNSPlus("ogc:PropertyIsEqualTo", { + attributes: {matchCase: filter.matchCase} + }); + // no ogc:expression handling for PropertyName for now + this.writeNode("PropertyName", filter, node); + // handle Literals or Functions for now + this.writeOgcExpression(filter.value, node); + return node; + }, + "PropertyIsNotEqualTo": function(filter) { + var node = this.createElementNSPlus("ogc:PropertyIsNotEqualTo", { + attributes: {matchCase: filter.matchCase} + }); + // no ogc:expression handling for PropertyName for now + this.writeNode("PropertyName", filter, node); + // handle Literals or Functions for now + this.writeOgcExpression(filter.value, node); + return node; + }, + "PropertyIsLike": function(filter) { + var node = this.createElementNSPlus("ogc:PropertyIsLike", { + attributes: { + matchCase: filter.matchCase, + wildCard: "*", singleChar: ".", escapeChar: "!" + } + }); + // no ogc:expression handling for now + this.writeNode("PropertyName", filter, node); + // convert regex string to ogc string + this.writeNode("Literal", filter.regex2value(), node); + return node; + }, + "BBOX": function(filter) { + var node = this.createElementNSPlus("ogc:BBOX"); + // PropertyName is optional in 1.1.0 + filter.property && this.writeNode("PropertyName", filter, node); + var box = this.writeNode("gml:Envelope", filter.value); + if(filter.projection) { + box.setAttribute("srsName", filter.projection); + } + node.appendChild(box); + return node; + }, + "SortBy": function(sortProperties) { + var node = this.createElementNSPlus("ogc:SortBy"); + for (var i=0,l=sortProperties.length;i<l;i++) { + this.writeNode( + "ogc:SortProperty", + sortProperties[i], + node + ); + } + return node; + }, + "SortProperty": function(sortProperty) { + var node = this.createElementNSPlus("ogc:SortProperty"); + this.writeNode( + "ogc:PropertyName", + sortProperty, + node + ); + this.writeNode( + "ogc:SortOrder", + (sortProperty.order == 'DESC') ? 'DESC' : 'ASC', + node + ); + return node; + }, + "SortOrder": function(value) { + var node = this.createElementNSPlus("ogc:SortOrder", { + value: value + }); + return node; + } + }, OpenLayers.Format.Filter.v1.prototype.writers["ogc"]), + "gml": OpenLayers.Format.GML.v3.prototype.writers["gml"], + "feature": OpenLayers.Format.GML.v3.prototype.writers["feature"] + }, + + /** + * Method: writeSpatial + * + * Read a {<OpenLayers.Filter.Spatial>} filter and converts it into XML. + * + * Parameters: + * filter - {<OpenLayers.Filter.Spatial>} The filter. + * name - {String} Name of the generated XML element. + * + * Returns: + * {DOMElement} The created XML element. + */ + writeSpatial: function(filter, name) { + var node = this.createElementNSPlus("ogc:"+name); + this.writeNode("PropertyName", filter, node); + if(filter.value instanceof OpenLayers.Filter.Function) { + this.writeNode("Function", filter.value, node); + } else { + var child; + if(filter.value instanceof OpenLayers.Geometry) { + child = this.writeNode("feature:_geometry", filter.value).firstChild; + } else { + child = this.writeNode("gml:Envelope", filter.value); + } + if(filter.projection) { + child.setAttribute("srsName", filter.projection); + } + node.appendChild(child); + } + return node; + }, + + CLASS_NAME: "OpenLayers.Format.Filter.v1_1_0" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/GML.js b/misc/openlayers/lib/OpenLayers/Format/GML.js new file mode 100644 index 0000000..467f875 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/GML.js @@ -0,0 +1,923 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Feature/Vector.js + * @requires OpenLayers/Geometry/Point.js + * @requires OpenLayers/Geometry/MultiPoint.js + * @requires OpenLayers/Geometry/LineString.js + * @requires OpenLayers/Geometry/MultiLineString.js + * @requires OpenLayers/Geometry/Polygon.js + * @requires OpenLayers/Geometry/MultiPolygon.js + */ + +/** + * Class: OpenLayers.Format.GML + * Read/Write GML. Create a new instance with the <OpenLayers.Format.GML> + * constructor. Supports the GML simple features profile. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.GML = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * APIProperty: featureNS + * {String} Namespace used for feature attributes. Default is + * "http://mapserver.gis.umn.edu/mapserver". + */ + featureNS: "http://mapserver.gis.umn.edu/mapserver", + + /** + * APIProperty: featurePrefix + * {String} Namespace alias (or prefix) for feature nodes. Default is + * "feature". + */ + featurePrefix: "feature", + + /** + * APIProperty: featureName + * {String} Element name for features. Default is "featureMember". + */ + featureName: "featureMember", + + /** + * APIProperty: layerName + * {String} Name of data layer. Default is "features". + */ + layerName: "features", + + /** + * APIProperty: geometryName + * {String} Name of geometry element. Defaults to "geometry". + */ + geometryName: "geometry", + + /** + * APIProperty: collectionName + * {String} Name of featureCollection element. + */ + collectionName: "FeatureCollection", + + /** + * APIProperty: gmlns + * {String} GML Namespace. + */ + gmlns: "http://www.opengis.net/gml", + + /** + * APIProperty: extractAttributes + * {Boolean} Extract attributes from GML. + */ + extractAttributes: true, + + /** + * APIProperty: xy + * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x) + * Changing is not recommended, a new Format should be instantiated. + */ + xy: true, + + /** + * Constructor: OpenLayers.Format.GML + * Create a new parser for GML. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + // compile regular expressions once instead of every time they are used + this.regExes = { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g) + }; + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); + }, + + /** + * APIMethod: read + * Read data from a string, and return a list of features. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array(<OpenLayers.Feature.Vector>)} An array of features. + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + var featureNodes = this.getElementsByTagNameNS(data.documentElement, + this.gmlns, + this.featureName); + var features = []; + for(var i=0; i<featureNodes.length; i++) { + var feature = this.parseFeature(featureNodes[i]); + if(feature) { + features.push(feature); + } + } + return features; + }, + + /** + * Method: parseFeature + * This function is the core of the GML parsing code in OpenLayers. + * It creates the geometries that are then attached to the returned + * feature, and calls parseAttributes() to get attribute data out. + * + * Parameters: + * node - {DOMElement} A GML feature node. + */ + parseFeature: function(node) { + // only accept one geometry per feature - look for highest "order" + var order = ["MultiPolygon", "Polygon", + "MultiLineString", "LineString", + "MultiPoint", "Point", "Envelope"]; + // FIXME: In case we parse a feature with no geometry, but boundedBy an Envelope, + // this code creates a geometry derived from the Envelope. This is not correct. + var type, nodeList, geometry, parser; + for(var i=0; i<order.length; ++i) { + type = order[i]; + nodeList = this.getElementsByTagNameNS(node, this.gmlns, type); + if(nodeList.length > 0) { + // only deal with first geometry of this type + parser = this.parseGeometry[type.toLowerCase()]; + if(parser) { + geometry = parser.apply(this, [nodeList[0]]); + if (this.internalProjection && this.externalProjection) { + geometry.transform(this.externalProjection, + this.internalProjection); + } + } else { + throw new TypeError("Unsupported geometry type: " + type); + } + // stop looking for different geometry types + break; + } + } + + var bounds; + var boxNodes = this.getElementsByTagNameNS(node, this.gmlns, "Box"); + for(i=0; i<boxNodes.length; ++i) { + var boxNode = boxNodes[i]; + var box = this.parseGeometry["box"].apply(this, [boxNode]); + var parentNode = boxNode.parentNode; + var parentName = parentNode.localName || + parentNode.nodeName.split(":").pop(); + if(parentName === "boundedBy") { + bounds = box; + } else { + geometry = box.toGeometry(); + } + } + + // construct feature (optionally with attributes) + var attributes; + if(this.extractAttributes) { + attributes = this.parseAttributes(node); + } + var feature = new OpenLayers.Feature.Vector(geometry, attributes); + feature.bounds = bounds; + + feature.gml = { + featureType: node.firstChild.nodeName.split(":")[1], + featureNS: node.firstChild.namespaceURI, + featureNSPrefix: node.firstChild.prefix + }; + + // assign fid - this can come from a "fid" or "id" attribute + var childNode = node.firstChild; + var fid; + while(childNode) { + if(childNode.nodeType == 1) { + fid = childNode.getAttribute("fid") || + childNode.getAttribute("id"); + if(fid) { + break; + } + } + childNode = childNode.nextSibling; + } + feature.fid = fid; + return feature; + }, + + /** + * Property: parseGeometry + * Properties of this object are the functions that parse geometries based + * on their type. + */ + parseGeometry: { + + /** + * Method: parseGeometry.point + * Given a GML node representing a point geometry, create an OpenLayers + * point geometry. + * + * Parameters: + * node - {DOMElement} A GML node. + * + * Returns: + * {<OpenLayers.Geometry.Point>} A point geometry. + */ + point: function(node) { + /** + * Three coordinate variations to consider: + * 1) <gml:pos>x y z</gml:pos> + * 2) <gml:coordinates>x, y, z</gml:coordinates> + * 3) <gml:coord><gml:X>x</gml:X><gml:Y>y</gml:Y></gml:coord> + */ + var nodeList, coordString; + var coords = []; + + // look for <gml:pos> + var nodeList = this.getElementsByTagNameNS(node, this.gmlns, "pos"); + if(nodeList.length > 0) { + coordString = nodeList[0].firstChild.nodeValue; + coordString = coordString.replace(this.regExes.trimSpace, ""); + coords = coordString.split(this.regExes.splitSpace); + } + + // look for <gml:coordinates> + if(coords.length == 0) { + nodeList = this.getElementsByTagNameNS(node, this.gmlns, + "coordinates"); + if(nodeList.length > 0) { + coordString = nodeList[0].firstChild.nodeValue; + coordString = coordString.replace(this.regExes.removeSpace, + ""); + coords = coordString.split(","); + } + } + + // look for <gml:coord> + if(coords.length == 0) { + nodeList = this.getElementsByTagNameNS(node, this.gmlns, + "coord"); + if(nodeList.length > 0) { + var xList = this.getElementsByTagNameNS(nodeList[0], + this.gmlns, "X"); + var yList = this.getElementsByTagNameNS(nodeList[0], + this.gmlns, "Y"); + if(xList.length > 0 && yList.length > 0) { + coords = [xList[0].firstChild.nodeValue, + yList[0].firstChild.nodeValue]; + } + } + } + + // preserve third dimension + if(coords.length == 2) { + coords[2] = null; + } + + if (this.xy) { + return new OpenLayers.Geometry.Point(coords[0], coords[1], + coords[2]); + } + else{ + return new OpenLayers.Geometry.Point(coords[1], coords[0], + coords[2]); + } + }, + + /** + * Method: parseGeometry.multipoint + * Given a GML node representing a multipoint geometry, create an + * OpenLayers multipoint geometry. + * + * Parameters: + * node - {DOMElement} A GML node. + * + * Returns: + * {<OpenLayers.Geometry.MultiPoint>} A multipoint geometry. + */ + multipoint: function(node) { + var nodeList = this.getElementsByTagNameNS(node, this.gmlns, + "Point"); + var components = []; + if(nodeList.length > 0) { + var point; + for(var i=0; i<nodeList.length; ++i) { + point = this.parseGeometry.point.apply(this, [nodeList[i]]); + if(point) { + components.push(point); + } + } + } + return new OpenLayers.Geometry.MultiPoint(components); + }, + + /** + * Method: parseGeometry.linestring + * Given a GML node representing a linestring geometry, create an + * OpenLayers linestring geometry. + * + * Parameters: + * node - {DOMElement} A GML node. + * + * Returns: + * {<OpenLayers.Geometry.LineString>} A linestring geometry. + */ + linestring: function(node, ring) { + /** + * Two coordinate variations to consider: + * 1) <gml:posList dimension="d">x0 y0 z0 x1 y1 z1</gml:posList> + * 2) <gml:coordinates>x0, y0, z0 x1, y1, z1</gml:coordinates> + */ + var nodeList, coordString; + var coords = []; + var points = []; + + // look for <gml:posList> + nodeList = this.getElementsByTagNameNS(node, this.gmlns, "posList"); + if(nodeList.length > 0) { + coordString = this.getChildValue(nodeList[0]); + coordString = coordString.replace(this.regExes.trimSpace, ""); + coords = coordString.split(this.regExes.splitSpace); + var dim = parseInt(nodeList[0].getAttribute("dimension")); + var j, x, y, z; + for(var i=0; i<coords.length/dim; ++i) { + j = i * dim; + x = coords[j]; + y = coords[j+1]; + z = (dim == 2) ? null : coords[j+2]; + if (this.xy) { + points.push(new OpenLayers.Geometry.Point(x, y, z)); + } else { + points.push(new OpenLayers.Geometry.Point(y, x, z)); + } + } + } + + // look for <gml:coordinates> + if(coords.length == 0) { + nodeList = this.getElementsByTagNameNS(node, this.gmlns, + "coordinates"); + if(nodeList.length > 0) { + coordString = this.getChildValue(nodeList[0]); + coordString = coordString.replace(this.regExes.trimSpace, + ""); + coordString = coordString.replace(this.regExes.trimComma, + ","); + var pointList = coordString.split(this.regExes.splitSpace); + for(var i=0; i<pointList.length; ++i) { + coords = pointList[i].split(","); + if(coords.length == 2) { + coords[2] = null; + } + if (this.xy) { + points.push(new OpenLayers.Geometry.Point(coords[0], + coords[1], + coords[2])); + } else { + points.push(new OpenLayers.Geometry.Point(coords[1], + coords[0], + coords[2])); + } + } + } + } + + var line = null; + if(points.length != 0) { + if(ring) { + line = new OpenLayers.Geometry.LinearRing(points); + } else { + line = new OpenLayers.Geometry.LineString(points); + } + } + return line; + }, + + /** + * Method: parseGeometry.multilinestring + * Given a GML node representing a multilinestring geometry, create an + * OpenLayers multilinestring geometry. + * + * Parameters: + * node - {DOMElement} A GML node. + * + * Returns: + * {<OpenLayers.Geometry.MultiLineString>} A multilinestring geometry. + */ + multilinestring: function(node) { + var nodeList = this.getElementsByTagNameNS(node, this.gmlns, + "LineString"); + var components = []; + if(nodeList.length > 0) { + var line; + for(var i=0; i<nodeList.length; ++i) { + line = this.parseGeometry.linestring.apply(this, + [nodeList[i]]); + if(line) { + components.push(line); + } + } + } + return new OpenLayers.Geometry.MultiLineString(components); + }, + + /** + * Method: parseGeometry.polygon + * Given a GML node representing a polygon geometry, create an + * OpenLayers polygon geometry. + * + * Parameters: + * node - {DOMElement} A GML node. + * + * Returns: + * {<OpenLayers.Geometry.Polygon>} A polygon geometry. + */ + polygon: function(node) { + var nodeList = this.getElementsByTagNameNS(node, this.gmlns, + "LinearRing"); + var components = []; + if(nodeList.length > 0) { + // this assumes exterior ring first, inner rings after + var ring; + for(var i=0; i<nodeList.length; ++i) { + ring = this.parseGeometry.linestring.apply(this, + [nodeList[i], true]); + if(ring) { + components.push(ring); + } + } + } + return new OpenLayers.Geometry.Polygon(components); + }, + + /** + * Method: parseGeometry.multipolygon + * Given a GML node representing a multipolygon geometry, create an + * OpenLayers multipolygon geometry. + * + * Parameters: + * node - {DOMElement} A GML node. + * + * Returns: + * {<OpenLayers.Geometry.MultiPolygon>} A multipolygon geometry. + */ + multipolygon: function(node) { + var nodeList = this.getElementsByTagNameNS(node, this.gmlns, + "Polygon"); + var components = []; + if(nodeList.length > 0) { + var polygon; + for(var i=0; i<nodeList.length; ++i) { + polygon = this.parseGeometry.polygon.apply(this, + [nodeList[i]]); + if(polygon) { + components.push(polygon); + } + } + } + return new OpenLayers.Geometry.MultiPolygon(components); + }, + + envelope: function(node) { + var components = []; + var coordString; + var envelope; + + var lpoint = this.getElementsByTagNameNS(node, this.gmlns, "lowerCorner"); + if (lpoint.length > 0) { + var coords = []; + + if(lpoint.length > 0) { + coordString = lpoint[0].firstChild.nodeValue; + coordString = coordString.replace(this.regExes.trimSpace, ""); + coords = coordString.split(this.regExes.splitSpace); + } + + if(coords.length == 2) { + coords[2] = null; + } + if (this.xy) { + var lowerPoint = new OpenLayers.Geometry.Point(coords[0], coords[1],coords[2]); + } else { + var lowerPoint = new OpenLayers.Geometry.Point(coords[1], coords[0],coords[2]); + } + } + + var upoint = this.getElementsByTagNameNS(node, this.gmlns, "upperCorner"); + if (upoint.length > 0) { + var coords = []; + + if(upoint.length > 0) { + coordString = upoint[0].firstChild.nodeValue; + coordString = coordString.replace(this.regExes.trimSpace, ""); + coords = coordString.split(this.regExes.splitSpace); + } + + if(coords.length == 2) { + coords[2] = null; + } + if (this.xy) { + var upperPoint = new OpenLayers.Geometry.Point(coords[0], coords[1],coords[2]); + } else { + var upperPoint = new OpenLayers.Geometry.Point(coords[1], coords[0],coords[2]); + } + } + + if (lowerPoint && upperPoint) { + components.push(new OpenLayers.Geometry.Point(lowerPoint.x, lowerPoint.y)); + components.push(new OpenLayers.Geometry.Point(upperPoint.x, lowerPoint.y)); + components.push(new OpenLayers.Geometry.Point(upperPoint.x, upperPoint.y)); + components.push(new OpenLayers.Geometry.Point(lowerPoint.x, upperPoint.y)); + components.push(new OpenLayers.Geometry.Point(lowerPoint.x, lowerPoint.y)); + + var ring = new OpenLayers.Geometry.LinearRing(components); + envelope = new OpenLayers.Geometry.Polygon([ring]); + } + return envelope; + }, + + /** + * Method: parseGeometry.box + * Given a GML node representing a box geometry, create an + * OpenLayers.Bounds. + * + * Parameters: + * node - {DOMElement} A GML node. + * + * Returns: + * {<OpenLayers.Bounds>} A bounds representing the box. + */ + box: function(node) { + var nodeList = this.getElementsByTagNameNS(node, this.gmlns, + "coordinates"); + var coordString; + var coords, beginPoint = null, endPoint = null; + if (nodeList.length > 0) { + coordString = nodeList[0].firstChild.nodeValue; + coords = coordString.split(" "); + if (coords.length == 2) { + beginPoint = coords[0].split(","); + endPoint = coords[1].split(","); + } + } + if (beginPoint !== null && endPoint !== null) { + return new OpenLayers.Bounds(parseFloat(beginPoint[0]), + parseFloat(beginPoint[1]), + parseFloat(endPoint[0]), + parseFloat(endPoint[1]) ); + } + } + + }, + + /** + * Method: parseAttributes + * + * Parameters: + * node - {DOMElement} + * + * Returns: + * {Object} An attributes object. + */ + parseAttributes: function(node) { + var attributes = {}; + // assume attributes are children of the first type 1 child + var childNode = node.firstChild; + var children, i, child, grandchildren, grandchild, name, value; + while(childNode) { + if(childNode.nodeType == 1) { + // attributes are type 1 children with one type 3 child + children = childNode.childNodes; + for(i=0; i<children.length; ++i) { + child = children[i]; + if(child.nodeType == 1) { + grandchildren = child.childNodes; + if(grandchildren.length == 1) { + grandchild = grandchildren[0]; + if(grandchild.nodeType == 3 || + grandchild.nodeType == 4) { + name = (child.prefix) ? + child.nodeName.split(":")[1] : + child.nodeName; + value = grandchild.nodeValue.replace( + this.regExes.trimSpace, ""); + attributes[name] = value; + } + } else { + // If child has no childNodes (grandchildren), + // set an attribute with null value. + // e.g. <prefix:fieldname/> becomes + // {fieldname: null} + attributes[child.nodeName.split(":").pop()] = null; + } + } + } + break; + } + childNode = childNode.nextSibling; + } + return attributes; + }, + + /** + * APIMethod: write + * Generate a GML document string given a list of features. + * + * Parameters: + * features - {Array(<OpenLayers.Feature.Vector>)} List of features to + * serialize into a string. + * + * Returns: + * {String} A string representing the GML document. + */ + write: function(features) { + if(!(OpenLayers.Util.isArray(features))) { + features = [features]; + } + var gml = this.createElementNS("http://www.opengis.net/wfs", + "wfs:" + this.collectionName); + for(var i=0; i<features.length; i++) { + gml.appendChild(this.createFeatureXML(features[i])); + } + return OpenLayers.Format.XML.prototype.write.apply(this, [gml]); + }, + + /** + * Method: createFeatureXML + * Accept an OpenLayers.Feature.Vector, and build a GML node for it. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} The feature to be built as GML. + * + * Returns: + * {DOMElement} A node reprensting the feature in GML. + */ + createFeatureXML: function(feature) { + var geometry = feature.geometry; + var geometryNode = this.buildGeometryNode(geometry); + var geomContainer = this.createElementNS(this.featureNS, + this.featurePrefix + ":" + + this.geometryName); + geomContainer.appendChild(geometryNode); + var featureNode = this.createElementNS(this.gmlns, + "gml:" + this.featureName); + var featureContainer = this.createElementNS(this.featureNS, + this.featurePrefix + ":" + + this.layerName); + var fid = feature.fid || feature.id; + featureContainer.setAttribute("fid", fid); + featureContainer.appendChild(geomContainer); + for(var attr in feature.attributes) { + var attrText = this.createTextNode(feature.attributes[attr]); + var nodename = attr.substring(attr.lastIndexOf(":") + 1); + var attrContainer = this.createElementNS(this.featureNS, + this.featurePrefix + ":" + + nodename); + attrContainer.appendChild(attrText); + featureContainer.appendChild(attrContainer); + } + featureNode.appendChild(featureContainer); + return featureNode; + }, + + /** + * APIMethod: buildGeometryNode + */ + buildGeometryNode: function(geometry) { + if (this.externalProjection && this.internalProjection) { + geometry = geometry.clone(); + geometry.transform(this.internalProjection, + this.externalProjection); + } + var className = geometry.CLASS_NAME; + var type = className.substring(className.lastIndexOf(".") + 1); + var builder = this.buildGeometry[type.toLowerCase()]; + return builder.apply(this, [geometry]); + }, + + /** + * Property: buildGeometry + * Object containing methods to do the actual geometry node building + * based on geometry type. + */ + buildGeometry: { + // TBD retrieve the srs from layer + // srsName is non-standard, so not including it until it's right. + // gml.setAttribute("srsName", + // "http://www.opengis.net/gml/srs/epsg.xml#4326"); + + /** + * Method: buildGeometry.point + * Given an OpenLayers point geometry, create a GML point. + * + * Parameters: + * geometry - {<OpenLayers.Geometry.Point>} A point geometry. + * + * Returns: + * {DOMElement} A GML point node. + */ + point: function(geometry) { + var gml = this.createElementNS(this.gmlns, "gml:Point"); + gml.appendChild(this.buildCoordinatesNode(geometry)); + return gml; + }, + + /** + * Method: buildGeometry.multipoint + * Given an OpenLayers multipoint geometry, create a GML multipoint. + * + * Parameters: + * geometry - {<OpenLayers.Geometry.MultiPoint>} A multipoint geometry. + * + * Returns: + * {DOMElement} A GML multipoint node. + */ + multipoint: function(geometry) { + var gml = this.createElementNS(this.gmlns, "gml:MultiPoint"); + var points = geometry.components; + var pointMember, pointGeom; + for(var i=0; i<points.length; i++) { + pointMember = this.createElementNS(this.gmlns, + "gml:pointMember"); + pointGeom = this.buildGeometry.point.apply(this, + [points[i]]); + pointMember.appendChild(pointGeom); + gml.appendChild(pointMember); + } + return gml; + }, + + /** + * Method: buildGeometry.linestring + * Given an OpenLayers linestring geometry, create a GML linestring. + * + * Parameters: + * geometry - {<OpenLayers.Geometry.LineString>} A linestring geometry. + * + * Returns: + * {DOMElement} A GML linestring node. + */ + linestring: function(geometry) { + var gml = this.createElementNS(this.gmlns, "gml:LineString"); + gml.appendChild(this.buildCoordinatesNode(geometry)); + return gml; + }, + + /** + * Method: buildGeometry.multilinestring + * Given an OpenLayers multilinestring geometry, create a GML + * multilinestring. + * + * Parameters: + * geometry - {<OpenLayers.Geometry.MultiLineString>} A multilinestring + * geometry. + * + * Returns: + * {DOMElement} A GML multilinestring node. + */ + multilinestring: function(geometry) { + var gml = this.createElementNS(this.gmlns, "gml:MultiLineString"); + var lines = geometry.components; + var lineMember, lineGeom; + for(var i=0; i<lines.length; ++i) { + lineMember = this.createElementNS(this.gmlns, + "gml:lineStringMember"); + lineGeom = this.buildGeometry.linestring.apply(this, + [lines[i]]); + lineMember.appendChild(lineGeom); + gml.appendChild(lineMember); + } + return gml; + }, + + /** + * Method: buildGeometry.linearring + * Given an OpenLayers linearring geometry, create a GML linearring. + * + * Parameters: + * geometry - {<OpenLayers.Geometry.LinearRing>} A linearring geometry. + * + * Returns: + * {DOMElement} A GML linearring node. + */ + linearring: function(geometry) { + var gml = this.createElementNS(this.gmlns, "gml:LinearRing"); + gml.appendChild(this.buildCoordinatesNode(geometry)); + return gml; + }, + + /** + * Method: buildGeometry.polygon + * Given an OpenLayers polygon geometry, create a GML polygon. + * + * Parameters: + * geometry - {<OpenLayers.Geometry.Polygon>} A polygon geometry. + * + * Returns: + * {DOMElement} A GML polygon node. + */ + polygon: function(geometry) { + var gml = this.createElementNS(this.gmlns, "gml:Polygon"); + var rings = geometry.components; + var ringMember, ringGeom, type; + for(var i=0; i<rings.length; ++i) { + type = (i==0) ? "outerBoundaryIs" : "innerBoundaryIs"; + ringMember = this.createElementNS(this.gmlns, + "gml:" + type); + ringGeom = this.buildGeometry.linearring.apply(this, + [rings[i]]); + ringMember.appendChild(ringGeom); + gml.appendChild(ringMember); + } + return gml; + }, + + /** + * Method: buildGeometry.multipolygon + * Given an OpenLayers multipolygon geometry, create a GML multipolygon. + * + * Parameters: + * geometry - {<OpenLayers.Geometry.MultiPolygon>} A multipolygon + * geometry. + * + * Returns: + * {DOMElement} A GML multipolygon node. + */ + multipolygon: function(geometry) { + var gml = this.createElementNS(this.gmlns, "gml:MultiPolygon"); + var polys = geometry.components; + var polyMember, polyGeom; + for(var i=0; i<polys.length; ++i) { + polyMember = this.createElementNS(this.gmlns, + "gml:polygonMember"); + polyGeom = this.buildGeometry.polygon.apply(this, + [polys[i]]); + polyMember.appendChild(polyGeom); + gml.appendChild(polyMember); + } + return gml; + + }, + + /** + * Method: buildGeometry.bounds + * Given an OpenLayers bounds, create a GML box. + * + * Parameters: + * bounds - {<OpenLayers.Geometry.Bounds>} A bounds object. + * + * Returns: + * {DOMElement} A GML box node. + */ + bounds: function(bounds) { + var gml = this.createElementNS(this.gmlns, "gml:Box"); + gml.appendChild(this.buildCoordinatesNode(bounds)); + return gml; + } + }, + + /** + * Method: buildCoordinates + * builds the coordinates XmlNode + * (code) + * <gml:coordinates decimal="." cs="," ts=" ">...</gml:coordinates> + * (end) + * + * Parameters: + * geometry - {<OpenLayers.Geometry>} + * + * Returns: + * {XmlNode} created xmlNode + */ + buildCoordinatesNode: function(geometry) { + var coordinatesNode = this.createElementNS(this.gmlns, + "gml:coordinates"); + coordinatesNode.setAttribute("decimal", "."); + coordinatesNode.setAttribute("cs", ","); + coordinatesNode.setAttribute("ts", " "); + + var parts = []; + + if(geometry instanceof OpenLayers.Bounds){ + parts.push(geometry.left + "," + geometry.bottom); + parts.push(geometry.right + "," + geometry.top); + } else { + var points = (geometry.components) ? geometry.components : [geometry]; + for(var i=0; i<points.length; i++) { + parts.push(points[i].x + "," + points[i].y); + } + } + + var txtNode = this.createTextNode(parts.join(" ")); + coordinatesNode.appendChild(txtNode); + + return coordinatesNode; + }, + + CLASS_NAME: "OpenLayers.Format.GML" +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/GML/Base.js b/misc/openlayers/lib/OpenLayers/Format/GML/Base.js new file mode 100644 index 0000000..6c49969 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/GML/Base.js @@ -0,0 +1,645 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Format/GML.js + */ + +/** + * Though required in the full build, if the GML format is excluded, we set + * the namespace here. + */ +if(!OpenLayers.Format.GML) { + OpenLayers.Format.GML = {}; +} + +/** + * Class: OpenLayers.Format.GML.Base + * Superclass for GML parsers. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.GML.Base = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + gml: "http://www.opengis.net/gml", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance", + wfs: "http://www.opengis.net/wfs" // this is a convenience for reading wfs:FeatureCollection + }, + + /** + * Property: defaultPrefix + */ + defaultPrefix: "gml", + + /** + * Property: schemaLocation + * {String} Schema location for a particular minor version. + */ + schemaLocation: null, + + /** + * APIProperty: featureType + * {Array(String) or String} The local (without prefix) feature typeName(s). + */ + featureType: null, + + /** + * APIProperty: featureNS + * {String} The feature namespace. Must be set in the options at + * construction. + */ + featureNS: null, + + /** + * APIProperty: geometry + * {String} Name of geometry element. Defaults to "geometry". If null, it + * will be set on <read> when the first geometry is parsed. + */ + geometryName: "geometry", + + /** + * APIProperty: extractAttributes + * {Boolean} Extract attributes from GML. Default is true. + */ + extractAttributes: true, + + /** + * APIProperty: srsName + * {String} URI for spatial reference system. This is optional for + * single part geometries and mandatory for collections and multis. + * If set, the srsName attribute will be written for all geometries. + * Default is null. + */ + srsName: null, + + /** + * APIProperty: xy + * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x) + * Changing is not recommended, a new Format should be instantiated. + */ + xy: true, + + /** + * Property: geometryTypes + * {Object} Maps OpenLayers geometry class names to GML element names. + * Use <setGeometryTypes> before accessing this property. + */ + geometryTypes: null, + + /** + * Property: singleFeatureType + * {Boolean} True if there is only 1 featureType, and not an array + * of featuretypes. + */ + singleFeatureType: null, + + /** + * Property: autoConfig + * {Boolean} Indicates if the format was configured without a <featureNS>, + * but auto-configured <featureNS> and <featureType> during read. + * Subclasses making use of <featureType> auto-configuration should make + * the first call to the <readNode> method (usually in the read method) + * with true as 3rd argument, so the auto-configured featureType can be + * reset and the format can be reused for subsequent reads with data from + * different featureTypes. Set to false after read if you want to keep the + * auto-configured values. + */ + + /** + * Property: regExes + * Compiled regular expressions for manipulating strings. + */ + regExes: { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g), + featureMember: (/^(.*:)?featureMembers?$/) + }, + + /** + * Constructor: OpenLayers.Format.GML.Base + * Instances of this class are not created directly. Use the + * <OpenLayers.Format.GML.v2> or <OpenLayers.Format.GML.v3> constructor + * instead. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + * + * Valid options properties: + * featureType - {Array(String) or String} Local (without prefix) feature + * typeName(s) (required for write). + * featureNS - {String} Feature namespace (required for write). + * geometryName - {String} Geometry element name (required for write). + */ + initialize: function(options) { + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); + this.setGeometryTypes(); + if(options && options.featureNS) { + this.setNamespace("feature", options.featureNS); + } + this.singleFeatureType = !options || (typeof options.featureType === "string"); + }, + + /** + * Method: read + * + * Parameters: + * data - {DOMElement} A gml:featureMember element, a gml:featureMembers + * element, or an element containing either of the above at any level. + * + * Returns: + * {Array(<OpenLayers.Feature.Vector>)} An array of features. + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + if(data && data.nodeType == 9) { + data = data.documentElement; + } + var features = []; + this.readNode(data, {features: features}, true); + if(features.length == 0) { + // look for gml:featureMember elements + var elements = this.getElementsByTagNameNS( + data, this.namespaces.gml, "featureMember" + ); + if(elements.length) { + for(var i=0, len=elements.length; i<len; ++i) { + this.readNode(elements[i], {features: features}, true); + } + } else { + // look for gml:featureMembers elements (this is v3, but does no harm here) + var elements = this.getElementsByTagNameNS( + data, this.namespaces.gml, "featureMembers" + ); + if(elements.length) { + // there can be only one + this.readNode(elements[0], {features: features}, true); + } + } + } + return features; + }, + + /** + * Method: readNode + * Shorthand for applying one of the named readers given the node + * namespace and local name. Readers take two args (node, obj) and + * generally extend or modify the second. + * + * Parameters: + * node - {DOMElement} The node to be read (required). + * obj - {Object} The object to be modified (optional). + * first - {Boolean} Should be set to true for the first node read. This + * is usually the readNode call in the read method. Without this being + * set, auto-configured properties will stick on subsequent reads. + * + * Returns: + * {Object} The input object, modified (or a new one if none was provided). + */ + readNode: function(node, obj, first) { + // on subsequent calls of format.read(), we want to reset auto- + // configured properties and auto-configure again. + if (first === true && this.autoConfig === true) { + this.featureType = null; + delete this.namespaceAlias[this.featureNS]; + delete this.namespaces["feature"]; + this.featureNS = null; + } + // featureType auto-configuration + if (!this.featureNS && (!(node.prefix in this.namespaces) && + node.parentNode.namespaceURI == this.namespaces["gml"] && + this.regExes.featureMember.test(node.parentNode.nodeName))) { + this.featureType = node.nodeName.split(":").pop(); + this.setNamespace("feature", node.namespaceURI); + this.featureNS = node.namespaceURI; + this.autoConfig = true; + } + return OpenLayers.Format.XML.prototype.readNode.apply(this, [node, obj]); + }, + + /** + * 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: { + "gml": { + "_inherit": function(node, obj, container) { + // To be implemented by version specific parsers + }, + "featureMember": function(node, obj) { + this.readChildNodes(node, obj); + }, + "featureMembers": function(node, obj) { + this.readChildNodes(node, obj); + }, + "name": function(node, obj) { + obj.name = this.getChildValue(node); + }, + "boundedBy": function(node, obj) { + var container = {}; + this.readChildNodes(node, container); + if(container.components && container.components.length > 0) { + obj.bounds = container.components[0]; + } + }, + "Point": function(node, container) { + var obj = {points: []}; + this.readChildNodes(node, obj); + if(!container.components) { + container.components = []; + } + container.components.push(obj.points[0]); + }, + "coordinates": function(node, obj) { + var str = this.getChildValue(node).replace( + this.regExes.trimSpace, "" + ); + str = str.replace(this.regExes.trimComma, ","); + var pointList = str.split(this.regExes.splitSpace); + var coords; + var numPoints = pointList.length; + var points = new Array(numPoints); + for(var i=0; i<numPoints; ++i) { + coords = pointList[i].split(","); + if (this.xy) { + points[i] = new OpenLayers.Geometry.Point( + coords[0], coords[1], coords[2] + ); + } else { + points[i] = new OpenLayers.Geometry.Point( + coords[1], coords[0], coords[2] + ); + } + } + obj.points = points; + }, + "coord": function(node, obj) { + var coord = {}; + this.readChildNodes(node, coord); + if(!obj.points) { + obj.points = []; + } + obj.points.push(new OpenLayers.Geometry.Point( + coord.x, coord.y, coord.z + )); + }, + "X": function(node, coord) { + coord.x = this.getChildValue(node); + }, + "Y": function(node, coord) { + coord.y = this.getChildValue(node); + }, + "Z": function(node, coord) { + coord.z = this.getChildValue(node); + }, + "MultiPoint": function(node, container) { + var obj = {components: []}; + this.readers.gml._inherit.apply(this, [node, obj, container]); + this.readChildNodes(node, obj); + container.components = [ + new OpenLayers.Geometry.MultiPoint(obj.components) + ]; + }, + "pointMember": function(node, obj) { + this.readChildNodes(node, obj); + }, + "LineString": function(node, container) { + var obj = {}; + this.readers.gml._inherit.apply(this, [node, obj, container]); + this.readChildNodes(node, obj); + if(!container.components) { + container.components = []; + } + container.components.push( + new OpenLayers.Geometry.LineString(obj.points) + ); + }, + "MultiLineString": function(node, container) { + var obj = {components: []}; + this.readers.gml._inherit.apply(this, [node, obj, container]); + this.readChildNodes(node, obj); + container.components = [ + new OpenLayers.Geometry.MultiLineString(obj.components) + ]; + }, + "lineStringMember": function(node, obj) { + this.readChildNodes(node, obj); + }, + "Polygon": function(node, container) { + var obj = {outer: null, inner: []}; + this.readers.gml._inherit.apply(this, [node, obj, container]); + this.readChildNodes(node, obj); + obj.inner.unshift(obj.outer); + if(!container.components) { + container.components = []; + } + container.components.push( + new OpenLayers.Geometry.Polygon(obj.inner) + ); + }, + "LinearRing": function(node, obj) { + var container = {}; + this.readers.gml._inherit.apply(this, [node, container]); + this.readChildNodes(node, container); + obj.components = [new OpenLayers.Geometry.LinearRing( + container.points + )]; + }, + "MultiPolygon": function(node, container) { + var obj = {components: []}; + this.readers.gml._inherit.apply(this, [node, obj, container]); + this.readChildNodes(node, obj); + container.components = [ + new OpenLayers.Geometry.MultiPolygon(obj.components) + ]; + }, + "polygonMember": function(node, obj) { + this.readChildNodes(node, obj); + }, + "GeometryCollection": function(node, container) { + var obj = {components: []}; + this.readers.gml._inherit.apply(this, [node, obj, container]); + this.readChildNodes(node, obj); + container.components = [ + new OpenLayers.Geometry.Collection(obj.components) + ]; + }, + "geometryMember": function(node, obj) { + this.readChildNodes(node, obj); + } + }, + "feature": { + "*": function(node, obj) { + // The node can either be named like the featureType, or it + // can be a child of the feature:featureType. Children can be + // geometry or attributes. + var name; + var local = node.localName || node.nodeName.split(":").pop(); + // Since an attribute can have the same name as the feature type + // we only want to read the node as a feature if the parent + // node can have feature nodes as children. In this case, the + // obj.features property is set. + if (obj.features) { + if (!this.singleFeatureType && + (OpenLayers.Util.indexOf(this.featureType, local) !== -1)) { + name = "_typeName"; + } else if(local === this.featureType) { + name = "_typeName"; + } + } else { + // Assume attribute elements have one child node and that the child + // is a text node. Otherwise assume it is a geometry node. + if(node.childNodes.length == 0 || + (node.childNodes.length == 1 && node.firstChild.nodeType == 3)) { + if(this.extractAttributes) { + name = "_attribute"; + } + } else { + name = "_geometry"; + } + } + if(name) { + this.readers.feature[name].apply(this, [node, obj]); + } + }, + "_typeName": function(node, obj) { + var container = {components: [], attributes: {}}; + this.readChildNodes(node, container); + // look for common gml namespaced elements + if(container.name) { + container.attributes.name = container.name; + } + var feature = new OpenLayers.Feature.Vector( + container.components[0], container.attributes + ); + if (!this.singleFeatureType) { + feature.type = node.nodeName.split(":").pop(); + feature.namespace = node.namespaceURI; + } + var fid = node.getAttribute("fid") || + this.getAttributeNS(node, this.namespaces["gml"], "id"); + if(fid) { + feature.fid = fid; + } + if(this.internalProjection && this.externalProjection && + feature.geometry) { + feature.geometry.transform( + this.externalProjection, this.internalProjection + ); + } + if(container.bounds) { + feature.bounds = container.bounds; + } + obj.features.push(feature); + }, + "_geometry": function(node, obj) { + if (!this.geometryName) { + this.geometryName = node.nodeName.split(":").pop(); + } + this.readChildNodes(node, obj); + }, + "_attribute": function(node, obj) { + var local = node.localName || node.nodeName.split(":").pop(); + var value = this.getChildValue(node); + obj.attributes[local] = value; + } + }, + "wfs": { + "FeatureCollection": function(node, obj) { + this.readChildNodes(node, obj); + } + } + }, + + /** + * Method: write + * + * Parameters: + * features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector} + * An array of features or a single feature. + * + * Returns: + * {String} Given an array of features, a doc with a gml:featureMembers + * element will be returned. Given a single feature, a doc with a + * gml:featureMember element will be returned. + */ + write: function(features) { + var name; + if(OpenLayers.Util.isArray(features)) { + name = "featureMembers"; + } else { + name = "featureMember"; + } + var root = this.writeNode("gml:" + name, features); + this.setAttributeNS( + root, this.namespaces["xsi"], + "xsi:schemaLocation", this.schemaLocation + ); + + return OpenLayers.Format.XML.prototype.write.apply(this, [root]); + }, + + /** + * 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: { + "gml": { + "featureMember": function(feature) { + var node = this.createElementNSPlus("gml:featureMember"); + this.writeNode("feature:_typeName", feature, node); + return node; + }, + "MultiPoint": function(geometry) { + var node = this.createElementNSPlus("gml:MultiPoint"); + var components = geometry.components || [geometry]; + for(var i=0, ii=components.length; i<ii; ++i) { + this.writeNode("pointMember", components[i], node); + } + return node; + }, + "pointMember": function(geometry) { + var node = this.createElementNSPlus("gml:pointMember"); + this.writeNode("Point", geometry, node); + return node; + }, + "MultiLineString": function(geometry) { + var node = this.createElementNSPlus("gml:MultiLineString"); + var components = geometry.components || [geometry]; + for(var i=0, ii=components.length; i<ii; ++i) { + this.writeNode("lineStringMember", components[i], node); + } + return node; + }, + "lineStringMember": function(geometry) { + var node = this.createElementNSPlus("gml:lineStringMember"); + this.writeNode("LineString", geometry, node); + return node; + }, + "MultiPolygon": function(geometry) { + var node = this.createElementNSPlus("gml:MultiPolygon"); + var components = geometry.components || [geometry]; + for(var i=0, ii=components.length; i<ii; ++i) { + this.writeNode( + "polygonMember", components[i], node + ); + } + return node; + }, + "polygonMember": function(geometry) { + var node = this.createElementNSPlus("gml:polygonMember"); + this.writeNode("Polygon", geometry, node); + return node; + }, + "GeometryCollection": function(geometry) { + var node = this.createElementNSPlus("gml:GeometryCollection"); + for(var i=0, len=geometry.components.length; i<len; ++i) { + this.writeNode("geometryMember", geometry.components[i], node); + } + return node; + }, + "geometryMember": function(geometry) { + var node = this.createElementNSPlus("gml:geometryMember"); + var child = this.writeNode("feature:_geometry", geometry); + node.appendChild(child.firstChild); + return node; + } + }, + "feature": { + "_typeName": function(feature) { + var node = this.createElementNSPlus("feature:" + this.featureType, { + attributes: {fid: feature.fid} + }); + if(feature.geometry) { + this.writeNode("feature:_geometry", feature.geometry, node); + } + for(var name in feature.attributes) { + var value = feature.attributes[name]; + if(value != null) { + this.writeNode( + "feature:_attribute", + {name: name, value: value}, node + ); + } + } + return node; + }, + "_geometry": function(geometry) { + if(this.externalProjection && this.internalProjection) { + geometry = geometry.clone().transform( + this.internalProjection, this.externalProjection + ); + } + var node = this.createElementNSPlus( + "feature:" + this.geometryName + ); + var type = this.geometryTypes[geometry.CLASS_NAME]; + var child = this.writeNode("gml:" + type, geometry, node); + if(this.srsName) { + child.setAttribute("srsName", this.srsName); + } + return node; + }, + "_attribute": function(obj) { + return this.createElementNSPlus("feature:" + obj.name, { + value: obj.value + }); + } + }, + "wfs": { + "FeatureCollection": function(features) { + /** + * This is only here because GML2 only describes abstract + * feature collections. Typically, you would not be using + * the GML format to write wfs elements. This just provides + * some way to write out lists of features. GML3 defines the + * featureMembers element, so that is used by default instead. + */ + var node = this.createElementNSPlus("wfs:FeatureCollection"); + for(var i=0, len=features.length; i<len; ++i) { + this.writeNode("gml:featureMember", features[i], node); + } + return node; + } + } + }, + + /** + * Method: setGeometryTypes + * Sets the <geometryTypes> mapping. + */ + setGeometryTypes: function() { + this.geometryTypes = { + "OpenLayers.Geometry.Point": "Point", + "OpenLayers.Geometry.MultiPoint": "MultiPoint", + "OpenLayers.Geometry.LineString": "LineString", + "OpenLayers.Geometry.MultiLineString": "MultiLineString", + "OpenLayers.Geometry.Polygon": "Polygon", + "OpenLayers.Geometry.MultiPolygon": "MultiPolygon", + "OpenLayers.Geometry.Collection": "GeometryCollection" + }; + }, + + CLASS_NAME: "OpenLayers.Format.GML.Base" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/GML/v2.js b/misc/openlayers/lib/OpenLayers/Format/GML/v2.js new file mode 100644 index 0000000..bd26b99 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/GML/v2.js @@ -0,0 +1,193 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/GML/Base.js + */ + +/** + * Class: OpenLayers.Format.GML.v2 + * Parses GML version 2. + * + * Inherits from: + * - <OpenLayers.Format.GML.Base> + */ +OpenLayers.Format.GML.v2 = OpenLayers.Class(OpenLayers.Format.GML.Base, { + + /** + * Property: schemaLocation + * {String} Schema location for a particular minor version. + */ + schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd", + + /** + * Constructor: OpenLayers.Format.GML.v2 + * Create a parser for GML v2. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + * + * Valid options properties: + * featureType - {String} Local (without prefix) feature typeName (required). + * featureNS - {String} Feature namespace (required). + * geometryName - {String} Geometry element name. + */ + initialize: function(options) { + OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]); + }, + + /** + * 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: { + "gml": OpenLayers.Util.applyDefaults({ + "outerBoundaryIs": function(node, container) { + var obj = {}; + this.readChildNodes(node, obj); + container.outer = obj.components[0]; + }, + "innerBoundaryIs": function(node, container) { + var obj = {}; + this.readChildNodes(node, obj); + container.inner.push(obj.components[0]); + }, + "Box": function(node, container) { + var obj = {}; + this.readChildNodes(node, obj); + if(!container.components) { + container.components = []; + } + var min = obj.points[0]; + var max = obj.points[1]; + container.components.push( + new OpenLayers.Bounds(min.x, min.y, max.x, max.y) + ); + } + }, OpenLayers.Format.GML.Base.prototype.readers["gml"]), + "feature": OpenLayers.Format.GML.Base.prototype.readers["feature"], + "wfs": OpenLayers.Format.GML.Base.prototype.readers["wfs"] + }, + + /** + * Method: write + * + * Parameters: + * features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector} + * An array of features or a single feature. + * + * Returns: + * {String} Given an array of features, a doc with a gml:featureMembers + * element will be returned. Given a single feature, a doc with a + * gml:featureMember element will be returned. + */ + write: function(features) { + var name; + if(OpenLayers.Util.isArray(features)) { + // GML2 only has abstract feature collections + // wfs provides a feature collection from a well-known schema + name = "wfs:FeatureCollection"; + } else { + name = "gml:featureMember"; + } + var root = this.writeNode(name, features); + this.setAttributeNS( + root, this.namespaces["xsi"], + "xsi:schemaLocation", this.schemaLocation + ); + + return OpenLayers.Format.XML.prototype.write.apply(this, [root]); + }, + + /** + * 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: { + "gml": OpenLayers.Util.applyDefaults({ + "Point": function(geometry) { + var node = this.createElementNSPlus("gml:Point"); + this.writeNode("coordinates", [geometry], node); + return node; + }, + "coordinates": function(points) { + var numPoints = points.length; + var parts = new Array(numPoints); + var point; + for(var i=0; i<numPoints; ++i) { + point = points[i]; + if(this.xy) { + parts[i] = point.x + "," + point.y; + } else { + parts[i] = point.y + "," + point.x; + } + if(point.z != undefined) { // allow null or undefined + parts[i] += "," + point.z; + } + } + return this.createElementNSPlus("gml:coordinates", { + attributes: { + decimal: ".", cs: ",", ts: " " + }, + value: (numPoints == 1) ? parts[0] : parts.join(" ") + }); + }, + "LineString": function(geometry) { + var node = this.createElementNSPlus("gml:LineString"); + this.writeNode("coordinates", geometry.components, node); + return node; + }, + "Polygon": function(geometry) { + var node = this.createElementNSPlus("gml:Polygon"); + this.writeNode("outerBoundaryIs", geometry.components[0], node); + for(var i=1; i<geometry.components.length; ++i) { + this.writeNode( + "innerBoundaryIs", geometry.components[i], node + ); + } + return node; + }, + "outerBoundaryIs": function(ring) { + var node = this.createElementNSPlus("gml:outerBoundaryIs"); + this.writeNode("LinearRing", ring, node); + return node; + }, + "innerBoundaryIs": function(ring) { + var node = this.createElementNSPlus("gml:innerBoundaryIs"); + this.writeNode("LinearRing", ring, node); + return node; + }, + "LinearRing": function(ring) { + var node = this.createElementNSPlus("gml:LinearRing"); + this.writeNode("coordinates", ring.components, node); + return node; + }, + "Box": function(bounds) { + var node = this.createElementNSPlus("gml:Box"); + this.writeNode("coordinates", [ + {x: bounds.left, y: bounds.bottom}, + {x: bounds.right, y: bounds.top} + ], node); + // srsName attribute is optional for gml:Box + if(this.srsName) { + node.setAttribute("srsName", this.srsName); + } + return node; + } + }, OpenLayers.Format.GML.Base.prototype.writers["gml"]), + "feature": OpenLayers.Format.GML.Base.prototype.writers["feature"], + "wfs": OpenLayers.Format.GML.Base.prototype.writers["wfs"] + }, + + CLASS_NAME: "OpenLayers.Format.GML.v2" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/GML/v3.js b/misc/openlayers/lib/OpenLayers/Format/GML/v3.js new file mode 100644 index 0000000..82c7b1e --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/GML/v3.js @@ -0,0 +1,477 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/GML/Base.js + */ + +/** + * Class: OpenLayers.Format.GML.v3 + * Parses GML version 3. + * + * Inherits from: + * - <OpenLayers.Format.GML.Base> + */ +OpenLayers.Format.GML.v3 = OpenLayers.Class(OpenLayers.Format.GML.Base, { + + /** + * Property: schemaLocation + * {String} Schema location for a particular minor version. The writers + * conform with the Simple Features Profile for GML. + */ + schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/1.0.0/gmlsf.xsd", + + /** + * Property: curve + * {Boolean} Write gml:Curve instead of gml:LineString elements. This also + * affects the elements in multi-part geometries. Default is false. + * To write gml:Curve elements instead of gml:LineString, set curve + * to true in the options to the contstructor (cannot be changed after + * instantiation). + */ + curve: false, + + /** + * Property: multiCurve + * {Boolean} Write gml:MultiCurve instead of gml:MultiLineString. Since + * the latter is deprecated in GML 3, the default is true. To write + * gml:MultiLineString instead of gml:MultiCurve, set multiCurve to + * false in the options to the constructor (cannot be changed after + * instantiation). + */ + multiCurve: true, + + /** + * Property: surface + * {Boolean} Write gml:Surface instead of gml:Polygon elements. This also + * affects the elements in multi-part geometries. Default is false. + * To write gml:Surface elements instead of gml:Polygon, set surface + * to true in the options to the contstructor (cannot be changed after + * instantiation). + */ + surface: false, + + /** + * Property: multiSurface + * {Boolean} Write gml:multiSurface instead of gml:MultiPolygon. Since + * the latter is deprecated in GML 3, the default is true. To write + * gml:MultiPolygon instead of gml:multiSurface, set multiSurface to + * false in the options to the constructor (cannot be changed after + * instantiation). + */ + multiSurface: true, + + /** + * Constructor: OpenLayers.Format.GML.v3 + * Create a parser for GML v3. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + * + * Valid options properties: + * featureType - {String} Local (without prefix) feature typeName (required). + * featureNS - {String} Feature namespace (required). + * geometryName - {String} Geometry element name. + */ + initialize: function(options) { + OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]); + }, + + /** + * 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: { + "gml": OpenLayers.Util.applyDefaults({ + "_inherit": function(node, obj, container) { + // SRSReferenceGroup attributes + var dim = parseInt(node.getAttribute("srsDimension"), 10) || + (container && container.srsDimension); + if (dim) { + obj.srsDimension = dim; + } + }, + "featureMembers": function(node, obj) { + this.readChildNodes(node, obj); + }, + "Curve": function(node, container) { + var obj = {points: []}; + this.readers.gml._inherit.apply(this, [node, obj, container]); + this.readChildNodes(node, obj); + if(!container.components) { + container.components = []; + } + container.components.push( + new OpenLayers.Geometry.LineString(obj.points) + ); + }, + "segments": function(node, obj) { + this.readChildNodes(node, obj); + }, + "LineStringSegment": function(node, container) { + var obj = {}; + this.readChildNodes(node, obj); + if(obj.points) { + Array.prototype.push.apply(container.points, obj.points); + } + }, + "pos": function(node, obj) { + var str = this.getChildValue(node).replace( + this.regExes.trimSpace, "" + ); + var coords = str.split(this.regExes.splitSpace); + var point; + if(this.xy) { + point = new OpenLayers.Geometry.Point( + coords[0], coords[1], coords[2] + ); + } else { + point = new OpenLayers.Geometry.Point( + coords[1], coords[0], coords[2] + ); + } + obj.points = [point]; + }, + "posList": function(node, obj) { + var str = this.getChildValue(node).replace( + this.regExes.trimSpace, "" + ); + var coords = str.split(this.regExes.splitSpace); + // The "dimension" attribute is from the GML 3.0.1 spec. + var dim = obj.srsDimension || + parseInt(node.getAttribute("srsDimension") || node.getAttribute("dimension"), 10) || 2; + var j, x, y, z; + var numPoints = coords.length / dim; + var points = new Array(numPoints); + for(var i=0, len=coords.length; i<len; i += dim) { + x = coords[i]; + y = coords[i+1]; + z = (dim == 2) ? undefined : coords[i+2]; + if (this.xy) { + points[i/dim] = new OpenLayers.Geometry.Point(x, y, z); + } else { + points[i/dim] = new OpenLayers.Geometry.Point(y, x, z); + } + } + obj.points = points; + }, + "Surface": function(node, obj) { + this.readChildNodes(node, obj); + }, + "patches": function(node, obj) { + this.readChildNodes(node, obj); + }, + "PolygonPatch": function(node, obj) { + this.readers.gml.Polygon.apply(this, [node, obj]); + }, + "exterior": function(node, container) { + var obj = {}; + this.readChildNodes(node, obj); + container.outer = obj.components[0]; + }, + "interior": function(node, container) { + var obj = {}; + this.readChildNodes(node, obj); + container.inner.push(obj.components[0]); + }, + "MultiCurve": function(node, container) { + var obj = {components: []}; + this.readers.gml._inherit.apply(this, [node, obj, container]); + this.readChildNodes(node, obj); + if(obj.components.length > 0) { + container.components = [ + new OpenLayers.Geometry.MultiLineString(obj.components) + ]; + } + }, + "curveMember": function(node, obj) { + this.readChildNodes(node, obj); + }, + "MultiSurface": function(node, container) { + var obj = {components: []}; + this.readers.gml._inherit.apply(this, [node, obj, container]); + this.readChildNodes(node, obj); + if(obj.components.length > 0) { + container.components = [ + new OpenLayers.Geometry.MultiPolygon(obj.components) + ]; + } + }, + "surfaceMember": function(node, obj) { + this.readChildNodes(node, obj); + }, + "surfaceMembers": function(node, obj) { + this.readChildNodes(node, obj); + }, + "pointMembers": function(node, obj) { + this.readChildNodes(node, obj); + }, + "lineStringMembers": function(node, obj) { + this.readChildNodes(node, obj); + }, + "polygonMembers": function(node, obj) { + this.readChildNodes(node, obj); + }, + "geometryMembers": function(node, obj) { + this.readChildNodes(node, obj); + }, + "Envelope": function(node, container) { + var obj = {points: new Array(2)}; + this.readChildNodes(node, obj); + if(!container.components) { + container.components = []; + } + var min = obj.points[0]; + var max = obj.points[1]; + container.components.push( + new OpenLayers.Bounds(min.x, min.y, max.x, max.y) + ); + }, + "lowerCorner": function(node, container) { + var obj = {}; + this.readers.gml.pos.apply(this, [node, obj]); + container.points[0] = obj.points[0]; + }, + "upperCorner": function(node, container) { + var obj = {}; + this.readers.gml.pos.apply(this, [node, obj]); + container.points[1] = obj.points[0]; + } + }, OpenLayers.Format.GML.Base.prototype.readers["gml"]), + "feature": OpenLayers.Format.GML.Base.prototype.readers["feature"], + "wfs": OpenLayers.Format.GML.Base.prototype.readers["wfs"] + }, + + /** + * Method: write + * + * Parameters: + * features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector} + * An array of features or a single feature. + * + * Returns: + * {String} Given an array of features, a doc with a gml:featureMembers + * element will be returned. Given a single feature, a doc with a + * gml:featureMember element will be returned. + */ + write: function(features) { + var name; + if(OpenLayers.Util.isArray(features)) { + name = "featureMembers"; + } else { + name = "featureMember"; + } + var root = this.writeNode("gml:" + name, features); + this.setAttributeNS( + root, this.namespaces["xsi"], + "xsi:schemaLocation", this.schemaLocation + ); + + return OpenLayers.Format.XML.prototype.write.apply(this, [root]); + }, + + /** + * 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: { + "gml": OpenLayers.Util.applyDefaults({ + "featureMembers": function(features) { + var node = this.createElementNSPlus("gml:featureMembers"); + for(var i=0, len=features.length; i<len; ++i) { + this.writeNode("feature:_typeName", features[i], node); + } + return node; + }, + "Point": function(geometry) { + var node = this.createElementNSPlus("gml:Point"); + this.writeNode("pos", geometry, node); + return node; + }, + "pos": function(point) { + // only 2d for simple features profile + var pos = (this.xy) ? + (point.x + " " + point.y) : (point.y + " " + point.x); + return this.createElementNSPlus("gml:pos", { + value: pos + }); + }, + "LineString": function(geometry) { + var node = this.createElementNSPlus("gml:LineString"); + this.writeNode("posList", geometry.components, node); + return node; + }, + "Curve": function(geometry) { + var node = this.createElementNSPlus("gml:Curve"); + this.writeNode("segments", geometry, node); + return node; + }, + "segments": function(geometry) { + var node = this.createElementNSPlus("gml:segments"); + this.writeNode("LineStringSegment", geometry, node); + return node; + }, + "LineStringSegment": function(geometry) { + var node = this.createElementNSPlus("gml:LineStringSegment"); + this.writeNode("posList", geometry.components, node); + return node; + }, + "posList": function(points) { + // only 2d for simple features profile + var len = points.length; + var parts = new Array(len); + var point; + for(var i=0; i<len; ++i) { + point = points[i]; + if(this.xy) { + parts[i] = point.x + " " + point.y; + } else { + parts[i] = point.y + " " + point.x; + } + } + return this.createElementNSPlus("gml:posList", { + value: parts.join(" ") + }); + }, + "Surface": function(geometry) { + var node = this.createElementNSPlus("gml:Surface"); + this.writeNode("patches", geometry, node); + return node; + }, + "patches": function(geometry) { + var node = this.createElementNSPlus("gml:patches"); + this.writeNode("PolygonPatch", geometry, node); + return node; + }, + "PolygonPatch": function(geometry) { + var node = this.createElementNSPlus("gml:PolygonPatch", { + attributes: {interpolation: "planar"} + }); + this.writeNode("exterior", geometry.components[0], node); + for(var i=1, len=geometry.components.length; i<len; ++i) { + this.writeNode( + "interior", geometry.components[i], node + ); + } + return node; + }, + "Polygon": function(geometry) { + var node = this.createElementNSPlus("gml:Polygon"); + this.writeNode("exterior", geometry.components[0], node); + for(var i=1, len=geometry.components.length; i<len; ++i) { + this.writeNode( + "interior", geometry.components[i], node + ); + } + return node; + }, + "exterior": function(ring) { + var node = this.createElementNSPlus("gml:exterior"); + this.writeNode("LinearRing", ring, node); + return node; + }, + "interior": function(ring) { + var node = this.createElementNSPlus("gml:interior"); + this.writeNode("LinearRing", ring, node); + return node; + }, + "LinearRing": function(ring) { + var node = this.createElementNSPlus("gml:LinearRing"); + this.writeNode("posList", ring.components, node); + return node; + }, + "MultiCurve": function(geometry) { + var node = this.createElementNSPlus("gml:MultiCurve"); + var components = geometry.components || [geometry]; + for(var i=0, len=components.length; i<len; ++i) { + this.writeNode("curveMember", components[i], node); + } + return node; + }, + "curveMember": function(geometry) { + var node = this.createElementNSPlus("gml:curveMember"); + if(this.curve) { + this.writeNode("Curve", geometry, node); + } else { + this.writeNode("LineString", geometry, node); + } + return node; + }, + "MultiSurface": function(geometry) { + var node = this.createElementNSPlus("gml:MultiSurface"); + var components = geometry.components || [geometry]; + for(var i=0, len=components.length; i<len; ++i) { + this.writeNode("surfaceMember", components[i], node); + } + return node; + }, + "surfaceMember": function(polygon) { + var node = this.createElementNSPlus("gml:surfaceMember"); + if(this.surface) { + this.writeNode("Surface", polygon, node); + } else { + this.writeNode("Polygon", polygon, node); + } + return node; + }, + "Envelope": function(bounds) { + var node = this.createElementNSPlus("gml:Envelope"); + this.writeNode("lowerCorner", bounds, node); + this.writeNode("upperCorner", bounds, node); + // srsName attribute is required for gml:Envelope + if(this.srsName) { + node.setAttribute("srsName", this.srsName); + } + return node; + }, + "lowerCorner": function(bounds) { + // only 2d for simple features profile + var pos = (this.xy) ? + (bounds.left + " " + bounds.bottom) : + (bounds.bottom + " " + bounds.left); + return this.createElementNSPlus("gml:lowerCorner", { + value: pos + }); + }, + "upperCorner": function(bounds) { + // only 2d for simple features profile + var pos = (this.xy) ? + (bounds.right + " " + bounds.top) : + (bounds.top + " " + bounds.right); + return this.createElementNSPlus("gml:upperCorner", { + value: pos + }); + } + }, OpenLayers.Format.GML.Base.prototype.writers["gml"]), + "feature": OpenLayers.Format.GML.Base.prototype.writers["feature"], + "wfs": OpenLayers.Format.GML.Base.prototype.writers["wfs"] + }, + + /** + * Method: setGeometryTypes + * Sets the <geometryTypes> mapping. + */ + setGeometryTypes: function() { + this.geometryTypes = { + "OpenLayers.Geometry.Point": "Point", + "OpenLayers.Geometry.MultiPoint": "MultiPoint", + "OpenLayers.Geometry.LineString": (this.curve === true) ? "Curve": "LineString", + "OpenLayers.Geometry.MultiLineString": (this.multiCurve === false) ? "MultiLineString" : "MultiCurve", + "OpenLayers.Geometry.Polygon": (this.surface === true) ? "Surface" : "Polygon", + "OpenLayers.Geometry.MultiPolygon": (this.multiSurface === false) ? "MultiPolygon" : "MultiSurface", + "OpenLayers.Geometry.Collection": "GeometryCollection" + }; + }, + + CLASS_NAME: "OpenLayers.Format.GML.v3" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/GPX.js b/misc/openlayers/lib/OpenLayers/Format/GPX.js new file mode 100644 index 0000000..16a8056 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/GPX.js @@ -0,0 +1,385 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Feature/Vector.js + * @requires OpenLayers/Geometry/Point.js + * @requires OpenLayers/Geometry/LineString.js + * @requires OpenLayers/Projection.js + */ + +/** + * Class: OpenLayers.Format.GPX + * Read/write GPX parser. Create a new instance with the + * <OpenLayers.Format.GPX> constructor. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.GPX = OpenLayers.Class(OpenLayers.Format.XML, { + + + /** + * APIProperty: defaultDesc + * {String} Default description for the waypoints/tracks in the case + * where the feature has no "description" attribute. + * Default is "No description available". + */ + defaultDesc: "No description available", + + /** + * APIProperty: extractWaypoints + * {Boolean} Extract waypoints from GPX. (default: true) + */ + extractWaypoints: true, + + /** + * APIProperty: extractTracks + * {Boolean} Extract tracks from GPX. (default: true) + */ + extractTracks: true, + + /** + * APIProperty: extractRoutes + * {Boolean} Extract routes from GPX. (default: true) + */ + extractRoutes: true, + + /** + * APIProperty: extractAttributes + * {Boolean} Extract feature attributes from GPX. (default: true) + * NOTE: Attributes as part of extensions to the GPX standard may not + * be extracted. + */ + extractAttributes: true, + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + gpx: "http://www.topografix.com/GPX/1/1", + xsi: "http://www.w3.org/2001/XMLSchema-instance" + }, + + /** + * Property: schemaLocation + * {String} Schema location. Defaults to + * "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd" + */ + schemaLocation: "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd", + + /** + * APIProperty: creator + * {String} The creator attribute to be added to the written GPX files. + * Defaults to "OpenLayers" + */ + creator: "OpenLayers", + + /** + * Constructor: OpenLayers.Format.GPX + * Create a new parser for GPX. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + // GPX coordinates are always in longlat WGS84 + this.externalProjection = new OpenLayers.Projection("EPSG:4326"); + + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); + }, + + /** + * APIMethod: read + * Return a list of features from a GPX doc + * + * Parameters: + * doc - {Element} + * + * Returns: + * Array({<OpenLayers.Feature.Vector>}) + */ + read: function(doc) { + if (typeof doc == "string") { + doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]); + } + var features = []; + + if(this.extractTracks) { + var tracks = doc.getElementsByTagName("trk"); + for (var i=0, len=tracks.length; i<len; i++) { + // Attributes are only in trk nodes, not trkseg nodes + var attrs = {}; + if(this.extractAttributes) { + attrs = this.parseAttributes(tracks[i]); + } + + var segs = this.getElementsByTagNameNS(tracks[i], tracks[i].namespaceURI, "trkseg"); + for (var j = 0, seglen = segs.length; j < seglen; j++) { + // We don't yet support extraction of trkpt attributes + // All trksegs of a trk get that trk's attributes + var track = this.extractSegment(segs[j], "trkpt"); + features.push(new OpenLayers.Feature.Vector(track, attrs)); + } + } + } + + if(this.extractRoutes) { + var routes = doc.getElementsByTagName("rte"); + for (var k=0, klen=routes.length; k<klen; k++) { + var attrs = {}; + if(this.extractAttributes) { + attrs = this.parseAttributes(routes[k]); + } + var route = this.extractSegment(routes[k], "rtept"); + features.push(new OpenLayers.Feature.Vector(route, attrs)); + } + } + + if(this.extractWaypoints) { + var waypoints = doc.getElementsByTagName("wpt"); + for (var l = 0, len = waypoints.length; l < len; l++) { + var attrs = {}; + if(this.extractAttributes) { + attrs = this.parseAttributes(waypoints[l]); + } + var wpt = new OpenLayers.Geometry.Point(waypoints[l].getAttribute("lon"), waypoints[l].getAttribute("lat")); + features.push(new OpenLayers.Feature.Vector(wpt, attrs)); + } + } + + if (this.internalProjection && this.externalProjection) { + for (var g = 0, featLength = features.length; g < featLength; g++) { + features[g].geometry.transform(this.externalProjection, + this.internalProjection); + } + } + + return features; + }, + + /** + * Method: extractSegment + * + * Parameters: + * segment - {DOMElement} a trkseg or rte node to parse + * segmentType - {String} nodeName of waypoints that form the line + * + * Returns: + * {<OpenLayers.Geometry.LineString>} A linestring geometry + */ + extractSegment: function(segment, segmentType) { + var points = this.getElementsByTagNameNS(segment, segment.namespaceURI, segmentType); + var point_features = []; + for (var i = 0, len = points.length; i < len; i++) { + point_features.push(new OpenLayers.Geometry.Point(points[i].getAttribute("lon"), points[i].getAttribute("lat"))); + } + return new OpenLayers.Geometry.LineString(point_features); + }, + + /** + * Method: parseAttributes + * + * Parameters: + * node - {<DOMElement>} + * + * Returns: + * {Object} An attributes object. + */ + parseAttributes: function(node) { + // node is either a wpt, trk or rte + // attributes are children of the form <attr>value</attr> + var attributes = {}; + var attrNode = node.firstChild, value, name; + while(attrNode) { + if(attrNode.nodeType == 1 && attrNode.firstChild) { + value = attrNode.firstChild; + if(value.nodeType == 3 || value.nodeType == 4) { + name = (attrNode.prefix) ? + attrNode.nodeName.split(":")[1] : + attrNode.nodeName; + if(name != "trkseg" && name != "rtept") { + attributes[name] = value.nodeValue; + } + } + } + attrNode = attrNode.nextSibling; + } + return attributes; + }, + + /** + * APIMethod: write + * Accepts Feature Collection, and returns a string. + * + * Parameters: + * features - {Array(<OpenLayers.Feature.Vector>)} List of features to serialize into a string. + * metadata - {Object} A key/value pairs object to build a metadata node to + * add to the gpx. Supported keys are 'name', 'desc', 'author'. + */ + write: function(features, metadata) { + features = OpenLayers.Util.isArray(features) ? + features : [features]; + var gpx = this.createElementNS(this.namespaces.gpx, "gpx"); + gpx.setAttribute("version", "1.1"); + gpx.setAttribute("creator", this.creator); + this.setAttributes(gpx, { + "xsi:schemaLocation": this.schemaLocation + }); + + if (metadata && typeof metadata == 'object') { + gpx.appendChild(this.buildMetadataNode(metadata)); + } + for(var i=0, len=features.length; i<len; i++) { + gpx.appendChild(this.buildFeatureNode(features[i])); + } + return OpenLayers.Format.XML.prototype.write.apply(this, [gpx]); + }, + + /** + * Method: buildMetadataNode + * Creates a "metadata" node. + * + * Returns: + * {DOMElement} + */ + buildMetadataNode: function(metadata) { + var types = ['name', 'desc', 'author'], + node = this.createElementNS(this.namespaces.gpx, 'metadata'); + for (var i=0; i < types.length; i++) { + var type = types[i]; + if (metadata[type]) { + var n = this.createElementNS(this.namespaces.gpx, type); + n.appendChild(this.createTextNode(metadata[type])); + node.appendChild(n); + } + } + return node; + }, + + /** + * Method: buildFeatureNode + * Accepts an <OpenLayers.Feature.Vector>, and builds a node for it. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} + * + * Returns: + * {DOMElement} - The created node, either a 'wpt' or a 'trk'. + */ + buildFeatureNode: function(feature) { + var geometry = feature.geometry; + geometry = geometry.clone(); + if (this.internalProjection && this.externalProjection) { + geometry.transform(this.internalProjection, + this.externalProjection); + } + if (geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { + var wpt = this.buildWptNode(geometry); + this.appendAttributesNode(wpt, feature); + return wpt; + } else { + var trkNode = this.createElementNS(this.namespaces.gpx, "trk"); + this.appendAttributesNode(trkNode, feature); + var trkSegNodes = this.buildTrkSegNode(geometry); + trkSegNodes = OpenLayers.Util.isArray(trkSegNodes) ? + trkSegNodes : [trkSegNodes]; + for (var i = 0, len = trkSegNodes.length; i < len; i++) { + trkNode.appendChild(trkSegNodes[i]); + } + return trkNode; + } + }, + + /** + * Method: buildTrkSegNode + * Builds trkseg node(s) given a geometry + * + * Parameters: + * trknode + * geometry - {<OpenLayers.Geometry>} + */ + buildTrkSegNode: function(geometry) { + var node, + i, + len, + point, + nodes; + if (geometry.CLASS_NAME == "OpenLayers.Geometry.LineString" || + geometry.CLASS_NAME == "OpenLayers.Geometry.LinearRing") { + node = this.createElementNS(this.namespaces.gpx, "trkseg"); + for (i = 0, len=geometry.components.length; i < len; i++) { + point = geometry.components[i]; + node.appendChild(this.buildTrkPtNode(point)); + } + return node; + } else { + nodes = []; + for (i = 0, len = geometry.components.length; i < len; i++) { + nodes.push(this.buildTrkSegNode(geometry.components[i])); + } + return nodes; + } + }, + + /** + * Method: buildTrkPtNode + * Builds a trkpt node given a point + * + * Parameters: + * point - {<OpenLayers.Geometry.Point>} + * + * Returns: + * {DOMElement} A trkpt node + */ + buildTrkPtNode: function(point) { + var node = this.createElementNS(this.namespaces.gpx, "trkpt"); + node.setAttribute("lon", point.x); + node.setAttribute("lat", point.y); + return node; + }, + + /** + * Method: buildWptNode + * Builds a wpt node given a point + * + * Parameters: + * geometry - {<OpenLayers.Geometry.Point>} + * + * Returns: + * {DOMElement} A wpt node + */ + buildWptNode: function(geometry) { + var node = this.createElementNS(this.namespaces.gpx, "wpt"); + node.setAttribute("lon", geometry.x); + node.setAttribute("lat", geometry.y); + return node; + }, + + /** + * Method: appendAttributesNode + * Adds some attributes node. + * + * Parameters: + * node - {DOMElement} the node to append the attribute nodes to. + * feature - {<OpenLayers.Feature.Vector>} + */ + appendAttributesNode: function(node, feature) { + var name = this.createElementNS(this.namespaces.gpx, 'name'); + name.appendChild(this.createTextNode( + feature.attributes.name || feature.id)); + node.appendChild(name); + var desc = this.createElementNS(this.namespaces.gpx, 'desc'); + desc.appendChild(this.createTextNode( + feature.attributes.description || this.defaultDesc)); + node.appendChild(desc); + // TBD - deal with remaining (non name/description) attributes. + }, + + CLASS_NAME: "OpenLayers.Format.GPX" +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/GeoJSON.js b/misc/openlayers/lib/OpenLayers/Format/GeoJSON.js new file mode 100644 index 0000000..0e02377 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/GeoJSON.js @@ -0,0 +1,716 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/JSON.js + * @requires OpenLayers/Feature/Vector.js + * @requires OpenLayers/Geometry/Point.js + * @requires OpenLayers/Geometry/MultiPoint.js + * @requires OpenLayers/Geometry/LineString.js + * @requires OpenLayers/Geometry/MultiLineString.js + * @requires OpenLayers/Geometry/Polygon.js + * @requires OpenLayers/Geometry/MultiPolygon.js + * @requires OpenLayers/Console.js + */ + +/** + * Class: OpenLayers.Format.GeoJSON + * Read and write GeoJSON. Create a new parser with the + * <OpenLayers.Format.GeoJSON> constructor. + * + * Inherits from: + * - <OpenLayers.Format.JSON> + */ +OpenLayers.Format.GeoJSON = OpenLayers.Class(OpenLayers.Format.JSON, { + + /** + * APIProperty: ignoreExtraDims + * {Boolean} Ignore dimensions higher than 2 when reading geometry + * coordinates. + */ + ignoreExtraDims: false, + + /** + * Constructor: OpenLayers.Format.GeoJSON + * Create a new parser for GeoJSON. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Deserialize a GeoJSON string. + * + * Parameters: + * json - {String} A GeoJSON string + * type - {String} Optional string that determines the structure of + * the output. Supported values are "Geometry", "Feature", and + * "FeatureCollection". If absent or null, a default of + * "FeatureCollection" is assumed. + * filter - {Function} A function which will be called for every key and + * value at every level of the final result. Each value will be + * replaced by the result of the filter function. This can be used to + * reform generic objects into instances of classes, or to transform + * date strings into Date objects. + * + * Returns: + * {Object} The return depends on the value of the type argument. If type + * is "FeatureCollection" (the default), the return will be an array + * of <OpenLayers.Feature.Vector>. If type is "Geometry", the input json + * must represent a single geometry, and the return will be an + * <OpenLayers.Geometry>. If type is "Feature", the input json must + * represent a single feature, and the return will be an + * <OpenLayers.Feature.Vector>. + */ + read: function(json, type, filter) { + type = (type) ? type : "FeatureCollection"; + var results = null; + var obj = null; + if (typeof json == "string") { + obj = OpenLayers.Format.JSON.prototype.read.apply(this, + [json, filter]); + } else { + obj = json; + } + if(!obj) { + OpenLayers.Console.error("Bad JSON: " + json); + } else if(typeof(obj.type) != "string") { + OpenLayers.Console.error("Bad GeoJSON - no type: " + json); + } else if(this.isValidType(obj, type)) { + switch(type) { + case "Geometry": + try { + results = this.parseGeometry(obj); + } catch(err) { + OpenLayers.Console.error(err); + } + break; + case "Feature": + try { + results = this.parseFeature(obj); + results.type = "Feature"; + } catch(err) { + OpenLayers.Console.error(err); + } + break; + case "FeatureCollection": + // for type FeatureCollection, we allow input to be any type + results = []; + switch(obj.type) { + case "Feature": + try { + results.push(this.parseFeature(obj)); + } catch(err) { + results = null; + OpenLayers.Console.error(err); + } + break; + case "FeatureCollection": + for(var i=0, len=obj.features.length; i<len; ++i) { + try { + results.push(this.parseFeature(obj.features[i])); + } catch(err) { + results = null; + OpenLayers.Console.error(err); + } + } + break; + default: + try { + var geom = this.parseGeometry(obj); + results.push(new OpenLayers.Feature.Vector(geom)); + } catch(err) { + results = null; + OpenLayers.Console.error(err); + } + } + break; + } + } + return results; + }, + + /** + * Method: isValidType + * Check if a GeoJSON object is a valid representative of the given type. + * + * Returns: + * {Boolean} The object is valid GeoJSON object of the given type. + */ + isValidType: function(obj, type) { + var valid = false; + switch(type) { + case "Geometry": + if(OpenLayers.Util.indexOf( + ["Point", "MultiPoint", "LineString", "MultiLineString", + "Polygon", "MultiPolygon", "Box", "GeometryCollection"], + obj.type) == -1) { + // unsupported geometry type + OpenLayers.Console.error("Unsupported geometry type: " + + obj.type); + } else { + valid = true; + } + break; + case "FeatureCollection": + // allow for any type to be converted to a feature collection + valid = true; + break; + default: + // for Feature types must match + if(obj.type == type) { + valid = true; + } else { + OpenLayers.Console.error("Cannot convert types from " + + obj.type + " to " + type); + } + } + return valid; + }, + + /** + * Method: parseFeature + * Convert a feature object from GeoJSON into an + * <OpenLayers.Feature.Vector>. + * + * Parameters: + * obj - {Object} An object created from a GeoJSON object + * + * Returns: + * {<OpenLayers.Feature.Vector>} A feature. + */ + parseFeature: function(obj) { + var feature, geometry, attributes, bbox; + attributes = (obj.properties) ? obj.properties : {}; + bbox = (obj.geometry && obj.geometry.bbox) || obj.bbox; + try { + geometry = this.parseGeometry(obj.geometry); + } catch(err) { + // deal with bad geometries + throw err; + } + feature = new OpenLayers.Feature.Vector(geometry, attributes); + if(bbox) { + feature.bounds = OpenLayers.Bounds.fromArray(bbox); + } + if(obj.id) { + feature.fid = obj.id; + } + return feature; + }, + + /** + * Method: parseGeometry + * Convert a geometry object from GeoJSON into an <OpenLayers.Geometry>. + * + * Parameters: + * obj - {Object} An object created from a GeoJSON object + * + * Returns: + * {<OpenLayers.Geometry>} A geometry. + */ + parseGeometry: function(obj) { + if (obj == null) { + return null; + } + var geometry, collection = false; + if(obj.type == "GeometryCollection") { + if(!(OpenLayers.Util.isArray(obj.geometries))) { + throw "GeometryCollection must have geometries array: " + obj; + } + var numGeom = obj.geometries.length; + var components = new Array(numGeom); + for(var i=0; i<numGeom; ++i) { + components[i] = this.parseGeometry.apply( + this, [obj.geometries[i]] + ); + } + geometry = new OpenLayers.Geometry.Collection(components); + collection = true; + } else { + if(!(OpenLayers.Util.isArray(obj.coordinates))) { + throw "Geometry must have coordinates array: " + obj; + } + if(!this.parseCoords[obj.type.toLowerCase()]) { + throw "Unsupported geometry type: " + obj.type; + } + try { + geometry = this.parseCoords[obj.type.toLowerCase()].apply( + this, [obj.coordinates] + ); + } catch(err) { + // deal with bad coordinates + throw err; + } + } + // We don't reproject collections because the children are reprojected + // for us when they are created. + if (this.internalProjection && this.externalProjection && !collection) { + geometry.transform(this.externalProjection, + this.internalProjection); + } + return geometry; + }, + + /** + * Property: parseCoords + * Object with properties corresponding to the GeoJSON geometry types. + * Property values are functions that do the actual parsing. + */ + parseCoords: { + /** + * Method: parseCoords.point + * Convert a coordinate array from GeoJSON into an + * <OpenLayers.Geometry>. + * + * Parameters: + * array - {Object} The coordinates array from the GeoJSON fragment. + * + * Returns: + * {<OpenLayers.Geometry>} A geometry. + */ + "point": function(array) { + if (this.ignoreExtraDims == false && + array.length != 2) { + throw "Only 2D points are supported: " + array; + } + return new OpenLayers.Geometry.Point(array[0], array[1]); + }, + + /** + * Method: parseCoords.multipoint + * Convert a coordinate array from GeoJSON into an + * <OpenLayers.Geometry>. + * + * Parameters: + * array - {Object} The coordinates array from the GeoJSON fragment. + * + * Returns: + * {<OpenLayers.Geometry>} A geometry. + */ + "multipoint": function(array) { + var points = []; + var p = null; + for(var i=0, len=array.length; i<len; ++i) { + try { + p = this.parseCoords["point"].apply(this, [array[i]]); + } catch(err) { + throw err; + } + points.push(p); + } + return new OpenLayers.Geometry.MultiPoint(points); + }, + + /** + * Method: parseCoords.linestring + * Convert a coordinate array from GeoJSON into an + * <OpenLayers.Geometry>. + * + * Parameters: + * array - {Object} The coordinates array from the GeoJSON fragment. + * + * Returns: + * {<OpenLayers.Geometry>} A geometry. + */ + "linestring": function(array) { + var points = []; + var p = null; + for(var i=0, len=array.length; i<len; ++i) { + try { + p = this.parseCoords["point"].apply(this, [array[i]]); + } catch(err) { + throw err; + } + points.push(p); + } + return new OpenLayers.Geometry.LineString(points); + }, + + /** + * Method: parseCoords.multilinestring + * Convert a coordinate array from GeoJSON into an + * <OpenLayers.Geometry>. + * + * Parameters: + * array - {Object} The coordinates array from the GeoJSON fragment. + * + * Returns: + * {<OpenLayers.Geometry>} A geometry. + */ + "multilinestring": function(array) { + var lines = []; + var l = null; + for(var i=0, len=array.length; i<len; ++i) { + try { + l = this.parseCoords["linestring"].apply(this, [array[i]]); + } catch(err) { + throw err; + } + lines.push(l); + } + return new OpenLayers.Geometry.MultiLineString(lines); + }, + + /** + * Method: parseCoords.polygon + * Convert a coordinate array from GeoJSON into an + * <OpenLayers.Geometry>. + * + * Returns: + * {<OpenLayers.Geometry>} A geometry. + */ + "polygon": function(array) { + var rings = []; + var r, l; + for(var i=0, len=array.length; i<len; ++i) { + try { + l = this.parseCoords["linestring"].apply(this, [array[i]]); + } catch(err) { + throw err; + } + r = new OpenLayers.Geometry.LinearRing(l.components); + rings.push(r); + } + return new OpenLayers.Geometry.Polygon(rings); + }, + + /** + * Method: parseCoords.multipolygon + * Convert a coordinate array from GeoJSON into an + * <OpenLayers.Geometry>. + * + * Parameters: + * array - {Object} The coordinates array from the GeoJSON fragment. + * + * Returns: + * {<OpenLayers.Geometry>} A geometry. + */ + "multipolygon": function(array) { + var polys = []; + var p = null; + for(var i=0, len=array.length; i<len; ++i) { + try { + p = this.parseCoords["polygon"].apply(this, [array[i]]); + } catch(err) { + throw err; + } + polys.push(p); + } + return new OpenLayers.Geometry.MultiPolygon(polys); + }, + + /** + * Method: parseCoords.box + * Convert a coordinate array from GeoJSON into an + * <OpenLayers.Geometry>. + * + * Parameters: + * array - {Object} The coordinates array from the GeoJSON fragment. + * + * Returns: + * {<OpenLayers.Geometry>} A geometry. + */ + "box": function(array) { + if(array.length != 2) { + throw "GeoJSON box coordinates must have 2 elements"; + } + return new OpenLayers.Geometry.Polygon([ + new OpenLayers.Geometry.LinearRing([ + new OpenLayers.Geometry.Point(array[0][0], array[0][1]), + new OpenLayers.Geometry.Point(array[1][0], array[0][1]), + new OpenLayers.Geometry.Point(array[1][0], array[1][1]), + new OpenLayers.Geometry.Point(array[0][0], array[1][1]), + new OpenLayers.Geometry.Point(array[0][0], array[0][1]) + ]) + ]); + } + + }, + + /** + * APIMethod: write + * Serialize a feature, geometry, array of features into a GeoJSON string. + * + * Parameters: + * obj - {Object} An <OpenLayers.Feature.Vector>, <OpenLayers.Geometry>, + * or an array of features. + * pretty - {Boolean} Structure the output with newlines and indentation. + * Default is false. + * + * Returns: + * {String} The GeoJSON string representation of the input geometry, + * features, or array of features. + */ + write: function(obj, pretty) { + var geojson = { + "type": null + }; + if(OpenLayers.Util.isArray(obj)) { + geojson.type = "FeatureCollection"; + var numFeatures = obj.length; + geojson.features = new Array(numFeatures); + for(var i=0; i<numFeatures; ++i) { + var element = obj[i]; + if(!element instanceof OpenLayers.Feature.Vector) { + var msg = "FeatureCollection only supports collections " + + "of features: " + element; + throw msg; + } + geojson.features[i] = this.extract.feature.apply( + this, [element] + ); + } + } else if (obj.CLASS_NAME.indexOf("OpenLayers.Geometry") == 0) { + geojson = this.extract.geometry.apply(this, [obj]); + } else if (obj instanceof OpenLayers.Feature.Vector) { + geojson = this.extract.feature.apply(this, [obj]); + if(obj.layer && obj.layer.projection) { + geojson.crs = this.createCRSObject(obj); + } + } + return OpenLayers.Format.JSON.prototype.write.apply(this, + [geojson, pretty]); + }, + + /** + * Method: createCRSObject + * Create the CRS object for an object. + * + * Parameters: + * object - {<OpenLayers.Feature.Vector>} + * + * Returns: + * {Object} An object which can be assigned to the crs property + * of a GeoJSON object. + */ + createCRSObject: function(object) { + var proj = object.layer.projection.toString(); + var crs = {}; + if (proj.match(/epsg:/i)) { + var code = parseInt(proj.substring(proj.indexOf(":") + 1)); + if (code == 4326) { + crs = { + "type": "name", + "properties": { + "name": "urn:ogc:def:crs:OGC:1.3:CRS84" + } + }; + } else { + crs = { + "type": "name", + "properties": { + "name": "EPSG:" + code + } + }; + } + } + return crs; + }, + + /** + * Property: extract + * Object with properties corresponding to the GeoJSON types. + * Property values are functions that do the actual value extraction. + */ + extract: { + /** + * Method: extract.feature + * Return a partial GeoJSON object representing a single feature. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} + * + * Returns: + * {Object} An object representing the point. + */ + 'feature': function(feature) { + var geom = this.extract.geometry.apply(this, [feature.geometry]); + var json = { + "type": "Feature", + "properties": feature.attributes, + "geometry": geom + }; + if (feature.fid != null) { + json.id = feature.fid; + } + return json; + }, + + /** + * Method: extract.geometry + * Return a GeoJSON object representing a single geometry. + * + * Parameters: + * geometry - {<OpenLayers.Geometry>} + * + * Returns: + * {Object} An object representing the geometry. + */ + 'geometry': function(geometry) { + if (geometry == null) { + return null; + } + if (this.internalProjection && this.externalProjection) { + geometry = geometry.clone(); + geometry.transform(this.internalProjection, + this.externalProjection); + } + var geometryType = geometry.CLASS_NAME.split('.')[2]; + var data = this.extract[geometryType.toLowerCase()].apply(this, [geometry]); + var json; + if(geometryType == "Collection") { + json = { + "type": "GeometryCollection", + "geometries": data + }; + } else { + json = { + "type": geometryType, + "coordinates": data + }; + } + + return json; + }, + + /** + * Method: extract.point + * Return an array of coordinates from a point. + * + * Parameters: + * point - {<OpenLayers.Geometry.Point>} + * + * Returns: + * {Array} An array of coordinates representing the point. + */ + 'point': function(point) { + return [point.x, point.y]; + }, + + /** + * Method: extract.multipoint + * Return an array of point coordinates from a multipoint. + * + * Parameters: + * multipoint - {<OpenLayers.Geometry.MultiPoint>} + * + * Returns: + * {Array} An array of point coordinate arrays representing + * the multipoint. + */ + 'multipoint': function(multipoint) { + var array = []; + for(var i=0, len=multipoint.components.length; i<len; ++i) { + array.push(this.extract.point.apply(this, [multipoint.components[i]])); + } + return array; + }, + + /** + * Method: extract.linestring + * Return an array of coordinate arrays from a linestring. + * + * Parameters: + * linestring - {<OpenLayers.Geometry.LineString>} + * + * Returns: + * {Array} An array of coordinate arrays representing + * the linestring. + */ + 'linestring': function(linestring) { + var array = []; + for(var i=0, len=linestring.components.length; i<len; ++i) { + array.push(this.extract.point.apply(this, [linestring.components[i]])); + } + return array; + }, + + /** + * Method: extract.multilinestring + * Return an array of linestring arrays from a linestring. + * + * Parameters: + * multilinestring - {<OpenLayers.Geometry.MultiLineString>} + * + * Returns: + * {Array} An array of linestring arrays representing + * the multilinestring. + */ + 'multilinestring': function(multilinestring) { + var array = []; + for(var i=0, len=multilinestring.components.length; i<len; ++i) { + array.push(this.extract.linestring.apply(this, [multilinestring.components[i]])); + } + return array; + }, + + /** + * Method: extract.polygon + * Return an array of linear ring arrays from a polygon. + * + * Parameters: + * polygon - {<OpenLayers.Geometry.Polygon>} + * + * Returns: + * {Array} An array of linear ring arrays representing the polygon. + */ + 'polygon': function(polygon) { + var array = []; + for(var i=0, len=polygon.components.length; i<len; ++i) { + array.push(this.extract.linestring.apply(this, [polygon.components[i]])); + } + return array; + }, + + /** + * Method: extract.multipolygon + * Return an array of polygon arrays from a multipolygon. + * + * Parameters: + * multipolygon - {<OpenLayers.Geometry.MultiPolygon>} + * + * Returns: + * {Array} An array of polygon arrays representing + * the multipolygon + */ + 'multipolygon': function(multipolygon) { + var array = []; + for(var i=0, len=multipolygon.components.length; i<len; ++i) { + array.push(this.extract.polygon.apply(this, [multipolygon.components[i]])); + } + return array; + }, + + /** + * Method: extract.collection + * Return an array of geometries from a geometry collection. + * + * Parameters: + * collection - {<OpenLayers.Geometry.Collection>} + * + * Returns: + * {Array} An array of geometry objects representing the geometry + * collection. + */ + 'collection': function(collection) { + var len = collection.components.length; + var array = new Array(len); + for(var i=0; i<len; ++i) { + array[i] = this.extract.geometry.apply( + this, [collection.components[i]] + ); + } + return array; + } + + + }, + + CLASS_NAME: "OpenLayers.Format.GeoJSON" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/GeoRSS.js b/misc/openlayers/lib/OpenLayers/Format/GeoRSS.js new file mode 100644 index 0000000..cbbb4d8 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/GeoRSS.js @@ -0,0 +1,409 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Feature/Vector.js + * @requires OpenLayers/Geometry/Point.js + * @requires OpenLayers/Geometry/LineString.js + * @requires OpenLayers/Geometry/Polygon.js + */ + +/** + * Class: OpenLayers.Format.GeoRSS + * Read/write GeoRSS parser. Create a new instance with the + * <OpenLayers.Format.GeoRSS> constructor. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.GeoRSS = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * APIProperty: rssns + * {String} RSS namespace to use. Defaults to + * "http://backend.userland.com/rss2" + */ + rssns: "http://backend.userland.com/rss2", + + /** + * APIProperty: featurens + * {String} Feature Attributes namespace. Defaults to + * "http://mapserver.gis.umn.edu/mapserver" + */ + featureNS: "http://mapserver.gis.umn.edu/mapserver", + + /** + * APIProperty: georssns + * {String} GeoRSS namespace to use. Defaults to + * "http://www.georss.org/georss" + */ + georssns: "http://www.georss.org/georss", + + /** + * APIProperty: geons + * {String} W3C Geo namespace to use. Defaults to + * "http://www.w3.org/2003/01/geo/wgs84_pos#" + */ + geons: "http://www.w3.org/2003/01/geo/wgs84_pos#", + + /** + * APIProperty: featureTitle + * {String} Default title for features. Defaults to "Untitled" + */ + featureTitle: "Untitled", + + /** + * APIProperty: featureDescription + * {String} Default description for features. Defaults to "No Description" + */ + featureDescription: "No Description", + + /** + * Property: gmlParse + * {Object} GML Format object for parsing features + * Non-API and only created if necessary + */ + gmlParser: null, + + /** + * APIProperty: xy + * {Boolean} Order of the GML coordinate: true:(x,y) or false:(y,x) + * For GeoRSS the default is (y,x), therefore: false + */ + xy: false, + + /** + * Constructor: OpenLayers.Format.GeoRSS + * Create a new parser for GeoRSS. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * Method: createGeometryFromItem + * Return a geometry from a GeoRSS Item. + * + * Parameters: + * item - {DOMElement} A GeoRSS item node. + * + * Returns: + * {<OpenLayers.Geometry>} A geometry representing the node. + */ + createGeometryFromItem: function(item) { + var point = this.getElementsByTagNameNS(item, this.georssns, "point"); + var lat = this.getElementsByTagNameNS(item, this.geons, 'lat'); + var lon = this.getElementsByTagNameNS(item, this.geons, 'long'); + + var line = this.getElementsByTagNameNS(item, + this.georssns, + "line"); + var polygon = this.getElementsByTagNameNS(item, + this.georssns, + "polygon"); + var where = this.getElementsByTagNameNS(item, + this.georssns, + "where"); + var box = this.getElementsByTagNameNS(item, + this.georssns, + "box"); + + if (point.length > 0 || (lat.length > 0 && lon.length > 0)) { + var location; + if (point.length > 0) { + location = OpenLayers.String.trim( + point[0].firstChild.nodeValue).split(/\s+/); + if (location.length !=2) { + location = OpenLayers.String.trim( + point[0].firstChild.nodeValue).split(/\s*,\s*/); + } + } else { + location = [parseFloat(lat[0].firstChild.nodeValue), + parseFloat(lon[0].firstChild.nodeValue)]; + } + + var geometry = new OpenLayers.Geometry.Point(location[1], location[0]); + + } else if (line.length > 0) { + var coords = OpenLayers.String.trim(this.getChildValue(line[0])).split(/\s+/); + var components = []; + var point; + for (var i=0, len=coords.length; i<len; i+=2) { + point = new OpenLayers.Geometry.Point(coords[i+1], coords[i]); + components.push(point); + } + geometry = new OpenLayers.Geometry.LineString(components); + } else if (polygon.length > 0) { + var coords = OpenLayers.String.trim(this.getChildValue(polygon[0])).split(/\s+/); + var components = []; + var point; + for (var i=0, len=coords.length; i<len; i+=2) { + point = new OpenLayers.Geometry.Point(coords[i+1], coords[i]); + components.push(point); + } + geometry = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]); + } else if (where.length > 0) { + if (!this.gmlParser) { + this.gmlParser = new OpenLayers.Format.GML({'xy': this.xy}); + } + var feature = this.gmlParser.parseFeature(where[0]); + geometry = feature.geometry; + } else if (box.length > 0) { + var coords = OpenLayers.String.trim(box[0].firstChild.nodeValue).split(/\s+/); + var components = []; + var point; + if (coords.length > 3) { + point = new OpenLayers.Geometry.Point(coords[1], coords[0]); + components.push(point); + point = new OpenLayers.Geometry.Point(coords[1], coords[2]); + components.push(point); + point = new OpenLayers.Geometry.Point(coords[3], coords[2]); + components.push(point); + point = new OpenLayers.Geometry.Point(coords[3], coords[0]); + components.push(point); + point = new OpenLayers.Geometry.Point(coords[1], coords[0]); + components.push(point); + } + geometry = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]); + } + + if (geometry && this.internalProjection && this.externalProjection) { + geometry.transform(this.externalProjection, + this.internalProjection); + } + + return geometry; + }, + + /** + * Method: createFeatureFromItem + * Return a feature from a GeoRSS Item. + * + * Parameters: + * item - {DOMElement} A GeoRSS item node. + * + * Returns: + * {<OpenLayers.Feature.Vector>} A feature representing the item. + */ + createFeatureFromItem: function(item) { + var geometry = this.createGeometryFromItem(item); + + /* Provide defaults for title and description */ + var title = this._getChildValue(item, "*", "title", this.featureTitle); + + /* First try RSS descriptions, then Atom summaries */ + var description = this._getChildValue( + item, "*", "description", + this._getChildValue(item, "*", "content", + this._getChildValue(item, "*", "summary", this.featureDescription))); + + /* If no link URL is found in the first child node, try the + href attribute */ + var link = this._getChildValue(item, "*", "link"); + if(!link) { + try { + link = this.getElementsByTagNameNS(item, "*", "link")[0].getAttribute("href"); + } catch(e) { + link = null; + } + } + + var id = this._getChildValue(item, "*", "id", null); + + var data = { + "title": title, + "description": description, + "link": link + }; + var feature = new OpenLayers.Feature.Vector(geometry, data); + feature.fid = id; + return feature; + }, + + /** + * Method: _getChildValue + * + * Parameters: + * node - {DOMElement} + * nsuri - {String} Child node namespace uri ("*" for any). + * name - {String} Child node name. + * def - {String} Optional string default to return if no child found. + * + * Returns: + * {String} The value of the first child with the given tag name. Returns + * default value or empty string if none found. + */ + _getChildValue: function(node, nsuri, name, def) { + var value; + var eles = this.getElementsByTagNameNS(node, nsuri, name); + if(eles && eles[0] && eles[0].firstChild + && eles[0].firstChild.nodeValue) { + value = this.getChildValue(eles[0]); + } else { + value = (def == undefined) ? "" : def; + } + return value; + }, + + /** + * APIMethod: read + * Return a list of features from a GeoRSS doc + * + * Parameters: + * doc - {Element} + * + * Returns: + * {Array(<OpenLayers.Feature.Vector>)} + */ + read: function(doc) { + if (typeof doc == "string") { + doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]); + } + + /* Try RSS items first, then Atom entries */ + var itemlist = null; + itemlist = this.getElementsByTagNameNS(doc, '*', 'item'); + if (itemlist.length == 0) { + itemlist = this.getElementsByTagNameNS(doc, '*', 'entry'); + } + + var numItems = itemlist.length; + var features = new Array(numItems); + for(var i=0; i<numItems; i++) { + features[i] = this.createFeatureFromItem(itemlist[i]); + } + return features; + }, + + + /** + * APIMethod: write + * Accept Feature Collection, and return a string. + * + * Parameters: + * features - {Array(<OpenLayers.Feature.Vector>)} List of features to serialize into a string. + */ + write: function(features) { + var georss; + if(OpenLayers.Util.isArray(features)) { + georss = this.createElementNS(this.rssns, "rss"); + for(var i=0, len=features.length; i<len; i++) { + georss.appendChild(this.createFeatureXML(features[i])); + } + } else { + georss = this.createFeatureXML(features); + } + return OpenLayers.Format.XML.prototype.write.apply(this, [georss]); + }, + + /** + * Method: createFeatureXML + * Accept an <OpenLayers.Feature.Vector>, and build a geometry for it. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} + * + * Returns: + * {DOMElement} + */ + createFeatureXML: function(feature) { + var geometryNode = this.buildGeometryNode(feature.geometry); + var featureNode = this.createElementNS(this.rssns, "item"); + var titleNode = this.createElementNS(this.rssns, "title"); + titleNode.appendChild(this.createTextNode(feature.attributes.title ? feature.attributes.title : "")); + var descNode = this.createElementNS(this.rssns, "description"); + descNode.appendChild(this.createTextNode(feature.attributes.description ? feature.attributes.description : "")); + featureNode.appendChild(titleNode); + featureNode.appendChild(descNode); + if (feature.attributes.link) { + var linkNode = this.createElementNS(this.rssns, "link"); + linkNode.appendChild(this.createTextNode(feature.attributes.link)); + featureNode.appendChild(linkNode); + } + for(var attr in feature.attributes) { + if (attr == "link" || attr == "title" || attr == "description") { continue; } + var attrText = this.createTextNode(feature.attributes[attr]); + var nodename = attr; + if (attr.search(":") != -1) { + nodename = attr.split(":")[1]; + } + var attrContainer = this.createElementNS(this.featureNS, "feature:"+nodename); + attrContainer.appendChild(attrText); + featureNode.appendChild(attrContainer); + } + featureNode.appendChild(geometryNode); + return featureNode; + }, + + /** + * Method: buildGeometryNode + * builds a GeoRSS node with a given geometry + * + * Parameters: + * geometry - {<OpenLayers.Geometry>} + * + * Returns: + * {DOMElement} A gml node. + */ + buildGeometryNode: function(geometry) { + if (this.internalProjection && this.externalProjection) { + geometry = geometry.clone(); + geometry.transform(this.internalProjection, + this.externalProjection); + } + var node; + // match Polygon + if (geometry.CLASS_NAME == "OpenLayers.Geometry.Polygon") { + node = this.createElementNS(this.georssns, 'georss:polygon'); + + node.appendChild(this.buildCoordinatesNode(geometry.components[0])); + } + // match LineString + else if (geometry.CLASS_NAME == "OpenLayers.Geometry.LineString") { + node = this.createElementNS(this.georssns, 'georss:line'); + + node.appendChild(this.buildCoordinatesNode(geometry)); + } + // match Point + else if (geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { + node = this.createElementNS(this.georssns, 'georss:point'); + node.appendChild(this.buildCoordinatesNode(geometry)); + } else { + throw "Couldn't parse " + geometry.CLASS_NAME; + } + return node; + }, + + /** + * Method: buildCoordinatesNode + * + * Parameters: + * geometry - {<OpenLayers.Geometry>} + */ + buildCoordinatesNode: function(geometry) { + var points = null; + + if (geometry.components) { + points = geometry.components; + } + + var path; + if (points) { + var numPoints = points.length; + var parts = new Array(numPoints); + for (var i = 0; i < numPoints; i++) { + parts[i] = points[i].y + " " + points[i].x; + } + path = parts.join(" "); + } else { + path = geometry.y + " " + geometry.x; + } + return this.createTextNode(path); + }, + + CLASS_NAME: "OpenLayers.Format.GeoRSS" +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/JSON.js b/misc/openlayers/lib/OpenLayers/Format/JSON.js new file mode 100644 index 0000000..5b25e6a --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/JSON.js @@ -0,0 +1,398 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * Note: + * This work draws heavily from the public domain JSON serializer/deserializer + * at http://www.json.org/json.js. Rewritten so that it doesn't modify + * basic data prototypes. + */ + +/** + * @requires OpenLayers/Format.js + */ + +/** + * Class: OpenLayers.Format.JSON + * A parser to read/write JSON safely. Create a new instance with the + * <OpenLayers.Format.JSON> constructor. + * + * Inherits from: + * - <OpenLayers.Format> + */ +OpenLayers.Format.JSON = OpenLayers.Class(OpenLayers.Format, { + + /** + * APIProperty: indent + * {String} For "pretty" printing, the indent string will be used once for + * each indentation level. + */ + indent: " ", + + /** + * APIProperty: space + * {String} For "pretty" printing, the space string will be used after + * the ":" separating a name/value pair. + */ + space: " ", + + /** + * APIProperty: newline + * {String} For "pretty" printing, the newline string will be used at the + * end of each name/value pair or array item. + */ + newline: "\n", + + /** + * Property: level + * {Integer} For "pretty" printing, this is incremented/decremented during + * serialization. + */ + level: 0, + + /** + * Property: pretty + * {Boolean} Serialize with extra whitespace for structure. This is set + * by the <write> method. + */ + pretty: false, + + /** + * Property: nativeJSON + * {Boolean} Does the browser support native json? + */ + nativeJSON: (function() { + return !!(window.JSON && typeof JSON.parse == "function" && typeof JSON.stringify == "function"); + })(), + + /** + * Constructor: OpenLayers.Format.JSON + * Create a new parser for JSON. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Deserialize a json string. + * + * Parameters: + * json - {String} A JSON string + * filter - {Function} A function which will be called for every key and + * value at every level of the final result. Each value will be + * replaced by the result of the filter function. This can be used to + * reform generic objects into instances of classes, or to transform + * date strings into Date objects. + * + * Returns: + * {Object} An object, array, string, or number . + */ + read: function(json, filter) { + var object; + if (this.nativeJSON) { + object = JSON.parse(json, filter); + } else try { + /** + * Parsing happens in three stages. In the first stage, we run the + * text against a regular expression which looks for non-JSON + * characters. We are especially concerned with '()' and 'new' + * because they can cause invocation, and '=' because it can + * cause mutation. But just to be safe, we will reject all + * unexpected characters. + */ + if (/^[\],:{}\s]*$/.test(json.replace(/\\["\\\/bfnrtu]/g, '@'). + replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). + replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + + /** + * In the second stage we use the eval function to compile the + * text into a JavaScript structure. The '{' operator is + * subject to a syntactic ambiguity in JavaScript - it can + * begin a block or an object literal. We wrap the text in + * parens to eliminate the ambiguity. + */ + object = eval('(' + json + ')'); + + /** + * In the optional third stage, we recursively walk the new + * structure, passing each name/value pair to a filter + * function for possible transformation. + */ + if(typeof filter === 'function') { + function walk(k, v) { + if(v && typeof v === 'object') { + for(var i in v) { + if(v.hasOwnProperty(i)) { + v[i] = walk(i, v[i]); + } + } + } + return filter(k, v); + } + object = walk('', object); + } + } + } catch(e) { + // Fall through if the regexp test fails. + } + + if(this.keepData) { + this.data = object; + } + + return object; + }, + + /** + * APIMethod: write + * Serialize an object into a JSON string. + * + * Parameters: + * value - {String} The object, array, string, number, boolean or date + * to be serialized. + * pretty - {Boolean} Structure the output with newlines and indentation. + * Default is false. + * + * Returns: + * {String} The JSON string representation of the input value. + */ + write: function(value, pretty) { + this.pretty = !!pretty; + var json = null; + var type = typeof value; + if(this.serialize[type]) { + try { + json = (!this.pretty && this.nativeJSON) ? + JSON.stringify(value) : + this.serialize[type].apply(this, [value]); + } catch(err) { + OpenLayers.Console.error("Trouble serializing: " + err); + } + } + return json; + }, + + /** + * Method: writeIndent + * Output an indentation string depending on the indentation level. + * + * Returns: + * {String} An appropriate indentation string. + */ + writeIndent: function() { + var pieces = []; + if(this.pretty) { + for(var i=0; i<this.level; ++i) { + pieces.push(this.indent); + } + } + return pieces.join(''); + }, + + /** + * Method: writeNewline + * Output a string representing a newline if in pretty printing mode. + * + * Returns: + * {String} A string representing a new line. + */ + writeNewline: function() { + return (this.pretty) ? this.newline : ''; + }, + + /** + * Method: writeSpace + * Output a string representing a space if in pretty printing mode. + * + * Returns: + * {String} A space. + */ + writeSpace: function() { + return (this.pretty) ? this.space : ''; + }, + + /** + * Property: serialize + * Object with properties corresponding to the serializable data types. + * Property values are functions that do the actual serializing. + */ + serialize: { + /** + * Method: serialize.object + * Transform an object into a JSON string. + * + * Parameters: + * object - {Object} The object to be serialized. + * + * Returns: + * {String} A JSON string representing the object. + */ + 'object': function(object) { + // three special objects that we want to treat differently + if(object == null) { + return "null"; + } + if(object.constructor == Date) { + return this.serialize.date.apply(this, [object]); + } + if(object.constructor == Array) { + return this.serialize.array.apply(this, [object]); + } + var pieces = ['{']; + this.level += 1; + var key, keyJSON, valueJSON; + + var addComma = false; + for(key in object) { + if(object.hasOwnProperty(key)) { + // recursive calls need to allow for sub-classing + keyJSON = OpenLayers.Format.JSON.prototype.write.apply(this, + [key, this.pretty]); + valueJSON = OpenLayers.Format.JSON.prototype.write.apply(this, + [object[key], this.pretty]); + if(keyJSON != null && valueJSON != null) { + if(addComma) { + pieces.push(','); + } + pieces.push(this.writeNewline(), this.writeIndent(), + keyJSON, ':', this.writeSpace(), valueJSON); + addComma = true; + } + } + } + + this.level -= 1; + pieces.push(this.writeNewline(), this.writeIndent(), '}'); + return pieces.join(''); + }, + + /** + * Method: serialize.array + * Transform an array into a JSON string. + * + * Parameters: + * array - {Array} The array to be serialized + * + * Returns: + * {String} A JSON string representing the array. + */ + 'array': function(array) { + var json; + var pieces = ['[']; + this.level += 1; + + for(var i=0, len=array.length; i<len; ++i) { + // recursive calls need to allow for sub-classing + json = OpenLayers.Format.JSON.prototype.write.apply(this, + [array[i], this.pretty]); + if(json != null) { + if(i > 0) { + pieces.push(','); + } + pieces.push(this.writeNewline(), this.writeIndent(), json); + } + } + + this.level -= 1; + pieces.push(this.writeNewline(), this.writeIndent(), ']'); + return pieces.join(''); + }, + + /** + * Method: serialize.string + * Transform a string into a JSON string. + * + * Parameters: + * string - {String} The string to be serialized + * + * Returns: + * {String} A JSON string representing the string. + */ + 'string': function(string) { + // If the string contains no control characters, no quote characters, and no + // backslash characters, then we can simply slap some quotes around it. + // Otherwise we must also replace the offending characters with safe + // sequences. + var m = { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }; + if(/["\\\x00-\x1f]/.test(string)) { + return '"' + string.replace(/([\x00-\x1f\\"])/g, function(a, b) { + var c = m[b]; + if(c) { + return c; + } + c = b.charCodeAt(); + return '\\u00' + + Math.floor(c / 16).toString(16) + + (c % 16).toString(16); + }) + '"'; + } + return '"' + string + '"'; + }, + + /** + * Method: serialize.number + * Transform a number into a JSON string. + * + * Parameters: + * number - {Number} The number to be serialized. + * + * Returns: + * {String} A JSON string representing the number. + */ + 'number': function(number) { + return isFinite(number) ? String(number) : "null"; + }, + + /** + * Method: serialize.boolean + * Transform a boolean into a JSON string. + * + * Parameters: + * bool - {Boolean} The boolean to be serialized. + * + * Returns: + * {String} A JSON string representing the boolean. + */ + 'boolean': function(bool) { + return String(bool); + }, + + /** + * Method: serialize.object + * Transform a date into a JSON string. + * + * Parameters: + * date - {Date} The date to be serialized. + * + * Returns: + * {String} A JSON string representing the date. + */ + 'date': function(date) { + function format(number) { + // Format integers to have at least two digits. + return (number < 10) ? '0' + number : number; + } + return '"' + date.getFullYear() + '-' + + format(date.getMonth() + 1) + '-' + + format(date.getDate()) + 'T' + + format(date.getHours()) + ':' + + format(date.getMinutes()) + ':' + + format(date.getSeconds()) + '"'; + } + }, + + CLASS_NAME: "OpenLayers.Format.JSON" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/KML.js b/misc/openlayers/lib/OpenLayers/Format/KML.js new file mode 100644 index 0000000..e10bce7 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/KML.js @@ -0,0 +1,1517 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/BaseTypes/Date.js + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Feature/Vector.js + * @requires OpenLayers/Geometry/Point.js + * @requires OpenLayers/Geometry/LineString.js + * @requires OpenLayers/Geometry/Polygon.js + * @requires OpenLayers/Geometry/Collection.js + * @requires OpenLayers/Request/XMLHttpRequest.js + * @requires OpenLayers/Projection.js + */ + +/** + * Class: OpenLayers.Format.KML + * Read/Write KML. Create a new instance with the <OpenLayers.Format.KML> + * constructor. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + kml: "http://www.opengis.net/kml/2.2", + gx: "http://www.google.com/kml/ext/2.2" + }, + + /** + * APIProperty: kmlns + * {String} KML Namespace to use. Defaults to 2.0 namespace. + */ + kmlns: "http://earth.google.com/kml/2.0", + + /** + * APIProperty: placemarksDesc + * {String} Name of the placemarks. Default is "No description available". + */ + placemarksDesc: "No description available", + + /** + * APIProperty: foldersName + * {String} Name of the folders. Default is "OpenLayers export". + * If set to null, no name element will be created. + */ + foldersName: "OpenLayers export", + + /** + * APIProperty: foldersDesc + * {String} Description of the folders. Default is "Exported on [date]." + * If set to null, no description element will be created. + */ + foldersDesc: "Exported on " + new Date(), + + /** + * APIProperty: extractAttributes + * {Boolean} Extract attributes from KML. Default is true. + * Extracting styleUrls requires this to be set to true + * Note that currently only Data and SimpleData + * elements are handled. + */ + extractAttributes: true, + + /** + * APIProperty: kvpAttributes + * {Boolean} Only used if extractAttributes is true. + * If set to true, attributes will be simple + * key-value pairs, compatible with other formats, + * Any displayName elements will be ignored. + * If set to false, attributes will be objects, + * retaining any displayName elements, but not + * compatible with other formats. Any CDATA in + * displayName will be read in as a string value. + * Default is false. + */ + kvpAttributes: false, + + /** + * Property: extractStyles + * {Boolean} Extract styles from KML. Default is false. + * Extracting styleUrls also requires extractAttributes to be + * set to true + */ + extractStyles: false, + + /** + * APIProperty: extractTracks + * {Boolean} Extract gx:Track elements from Placemark elements. Default + * is false. If true, features will be generated for all points in + * all gx:Track elements. Features will have a when (Date) attribute + * based on when elements in the track. If tracks include angle + * elements, features will have heading, tilt, and roll attributes. + * If track point coordinates have three values, features will have + * an altitude attribute with the third coordinate value. + */ + extractTracks: false, + + /** + * APIProperty: trackAttributes + * {Array} If <extractTracks> is true, points within gx:Track elements will + * be parsed as features with when, heading, tilt, and roll attributes. + * Any additional attribute names can be provided in <trackAttributes>. + */ + trackAttributes: null, + + /** + * Property: internalns + * {String} KML Namespace to use -- defaults to the namespace of the + * Placemark node being parsed, but falls back to kmlns. + */ + internalns: null, + + /** + * Property: features + * {Array} Array of features + * + */ + features: null, + + /** + * Property: styles + * {Object} Storage of style objects + * + */ + styles: null, + + /** + * Property: styleBaseUrl + * {String} + */ + styleBaseUrl: "", + + /** + * Property: fetched + * {Object} Storage of KML URLs that have been fetched before + * in order to prevent reloading them. + */ + fetched: null, + + /** + * APIProperty: maxDepth + * {Integer} Maximum depth for recursive loading external KML URLs + * Defaults to 0: do no external fetching + */ + maxDepth: 0, + + /** + * Constructor: OpenLayers.Format.KML + * Create a new parser for KML. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + // compile regular expressions once instead of every time they are used + this.regExes = { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g), + kmlColor: (/(\w{2})(\w{2})(\w{2})(\w{2})/), + kmlIconPalette: (/root:\/\/icons\/palette-(\d+)(\.\w+)/), + straightBracket: (/\$\[(.*?)\]/g) + }; + // KML coordinates are always in longlat WGS84 + this.externalProjection = new OpenLayers.Projection("EPSG:4326"); + + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); + }, + + /** + * APIMethod: read + * Read data from a string, and return a list of features. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array(<OpenLayers.Feature.Vector>)} List of features. + */ + read: function(data) { + this.features = []; + this.styles = {}; + this.fetched = {}; + + // Set default options + var options = { + depth: 0, + styleBaseUrl: this.styleBaseUrl + }; + + return this.parseData(data, options); + }, + + /** + * Method: parseData + * Read data from a string, and return a list of features. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * options - {Object} Hash of options + * + * Returns: + * {Array(<OpenLayers.Feature.Vector>)} List of features. + */ + parseData: function(data, options) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + + // Loop throught the following node types in this order and + // process the nodes found + var types = ["Link", "NetworkLink", "Style", "StyleMap", "Placemark"]; + for(var i=0, len=types.length; i<len; ++i) { + var type = types[i]; + + var nodes = this.getElementsByTagNameNS(data, "*", type); + + // skip to next type if no nodes are found + if(nodes.length == 0) { + continue; + } + + switch (type.toLowerCase()) { + + // Fetch external links + case "link": + case "networklink": + this.parseLinks(nodes, options); + break; + + // parse style information + case "style": + if (this.extractStyles) { + this.parseStyles(nodes, options); + } + break; + case "stylemap": + if (this.extractStyles) { + this.parseStyleMaps(nodes, options); + } + break; + + // parse features + case "placemark": + this.parseFeatures(nodes, options); + break; + } + } + + return this.features; + }, + + /** + * Method: parseLinks + * Finds URLs of linked KML documents and fetches them + * + * Parameters: + * nodes - {Array} of {DOMElement} data to read/parse. + * options - {Object} Hash of options + * + */ + parseLinks: function(nodes, options) { + + // Fetch external links <NetworkLink> and <Link> + // Don't do anything if we have reached our maximum depth for recursion + if (options.depth >= this.maxDepth) { + return false; + } + + // increase depth + var newOptions = OpenLayers.Util.extend({}, options); + newOptions.depth++; + + for(var i=0, len=nodes.length; i<len; i++) { + var href = this.parseProperty(nodes[i], "*", "href"); + if(href && !this.fetched[href]) { + this.fetched[href] = true; // prevent reloading the same urls + var data = this.fetchLink(href); + if (data) { + this.parseData(data, newOptions); + } + } + } + + }, + + /** + * Method: fetchLink + * Fetches a URL and returns the result + * + * Parameters: + * href - {String} url to be fetched + * + */ + fetchLink: function(href) { + var request = OpenLayers.Request.GET({url: href, async: false}); + if (request) { + return request.responseText; + } + }, + + /** + * Method: parseStyles + * Parses <Style> nodes + * + * Parameters: + * nodes - {Array} of {DOMElement} data to read/parse. + * options - {Object} Hash of options + * + */ + parseStyles: function(nodes, options) { + for(var i=0, len=nodes.length; i<len; i++) { + var style = this.parseStyle(nodes[i]); + if(style) { + var styleName = (options.styleBaseUrl || "") + "#" + style.id; + + this.styles[styleName] = style; + } + } + }, + + /** + * Method: parseKmlColor + * Parses a kml color (in 'aabbggrr' format) and returns the corresponding + * color and opacity or null if the color is invalid. + * + * Parameters: + * kmlColor - {String} a kml formated color + * + * Returns: + * {Object} + */ + parseKmlColor: function(kmlColor) { + var color = null; + if (kmlColor) { + var matches = kmlColor.match(this.regExes.kmlColor); + if (matches) { + color = { + color: '#' + matches[4] + matches[3] + matches[2], + opacity: parseInt(matches[1], 16) / 255 + }; + } + } + return color; + }, + + /** + * Method: parseStyle + * Parses the children of a <Style> node and builds the style hash + * accordingly + * + * Parameters: + * node - {DOMElement} <Style> node + * + */ + parseStyle: function(node) { + var style = {}; + + var types = ["LineStyle", "PolyStyle", "IconStyle", "BalloonStyle", + "LabelStyle"]; + var type, styleTypeNode, nodeList, geometry, parser; + for(var i=0, len=types.length; i<len; ++i) { + type = types[i]; + styleTypeNode = this.getElementsByTagNameNS(node, "*", type)[0]; + if(!styleTypeNode) { + continue; + } + + // only deal with first geometry of this type + switch (type.toLowerCase()) { + case "linestyle": + var kmlColor = this.parseProperty(styleTypeNode, "*", "color"); + var color = this.parseKmlColor(kmlColor); + if (color) { + style["strokeColor"] = color.color; + style["strokeOpacity"] = color.opacity; + } + + var width = this.parseProperty(styleTypeNode, "*", "width"); + if (width) { + style["strokeWidth"] = width; + } + break; + + case "polystyle": + var kmlColor = this.parseProperty(styleTypeNode, "*", "color"); + var color = this.parseKmlColor(kmlColor); + if (color) { + style["fillOpacity"] = color.opacity; + style["fillColor"] = color.color; + } + // Check if fill is disabled + var fill = this.parseProperty(styleTypeNode, "*", "fill"); + if (fill == "0") { + style["fillColor"] = "none"; + } + // Check if outline is disabled + var outline = this.parseProperty(styleTypeNode, "*", "outline"); + if (outline == "0") { + style["strokeWidth"] = "0"; + } + + break; + + case "iconstyle": + // set scale + var scale = parseFloat(this.parseProperty(styleTypeNode, + "*", "scale") || 1); + + // set default width and height of icon + var width = 32 * scale; + var height = 32 * scale; + + var iconNode = this.getElementsByTagNameNS(styleTypeNode, + "*", + "Icon")[0]; + if (iconNode) { + var href = this.parseProperty(iconNode, "*", "href"); + if (href) { + + var w = this.parseProperty(iconNode, "*", "w"); + var h = this.parseProperty(iconNode, "*", "h"); + + // Settings for Google specific icons that are 64x64 + // We set the width and height to 64 and halve the + // scale to prevent icons from being too big + var google = "http://maps.google.com/mapfiles/kml"; + if (OpenLayers.String.startsWith( + href, google) && !w && !h) { + w = 64; + h = 64; + scale = scale / 2; + } + + // if only dimension is defined, make sure the + // other one has the same value + w = w || h; + h = h || w; + + if (w) { + width = parseInt(w) * scale; + } + + if (h) { + height = parseInt(h) * scale; + } + + // support for internal icons + // (/root://icons/palette-x.png) + // x and y tell the position on the palette: + // - in pixels + // - starting from the left bottom + // We translate that to a position in the list + // and request the appropriate icon from the + // google maps website + var matches = href.match(this.regExes.kmlIconPalette); + if (matches) { + var palette = matches[1]; + var file_extension = matches[2]; + + var x = this.parseProperty(iconNode, "*", "x"); + var y = this.parseProperty(iconNode, "*", "y"); + + var posX = x ? x/32 : 0; + var posY = y ? (7 - y/32) : 7; + + var pos = posY * 8 + posX; + href = "http://maps.google.com/mapfiles/kml/pal" + + palette + "/icon" + pos + file_extension; + } + + style["graphicOpacity"] = 1; // fully opaque + style["externalGraphic"] = href; + } + + } + + + // hotSpots define the offset for an Icon + var hotSpotNode = this.getElementsByTagNameNS(styleTypeNode, + "*", + "hotSpot")[0]; + if (hotSpotNode) { + var x = parseFloat(hotSpotNode.getAttribute("x")); + var y = parseFloat(hotSpotNode.getAttribute("y")); + + var xUnits = hotSpotNode.getAttribute("xunits"); + if (xUnits == "pixels") { + style["graphicXOffset"] = -x * scale; + } + else if (xUnits == "insetPixels") { + style["graphicXOffset"] = -width + (x * scale); + } + else if (xUnits == "fraction") { + style["graphicXOffset"] = -width * x; + } + + var yUnits = hotSpotNode.getAttribute("yunits"); + if (yUnits == "pixels") { + style["graphicYOffset"] = -height + (y * scale) + 1; + } + else if (yUnits == "insetPixels") { + style["graphicYOffset"] = -(y * scale) + 1; + } + else if (yUnits == "fraction") { + style["graphicYOffset"] = -height * (1 - y) + 1; + } + } + + style["graphicWidth"] = width; + style["graphicHeight"] = height; + break; + + case "balloonstyle": + var balloonStyle = OpenLayers.Util.getXmlNodeValue( + styleTypeNode); + if (balloonStyle) { + style["balloonStyle"] = balloonStyle.replace( + this.regExes.straightBracket, "${$1}"); + } + break; + case "labelstyle": + var kmlColor = this.parseProperty(styleTypeNode, "*", "color"); + var color = this.parseKmlColor(kmlColor); + if (color) { + style["fontColor"] = color.color; + style["fontOpacity"] = color.opacity; + } + break; + + default: + } + } + + // Some polygons have no line color, so we use the fillColor for that + if (!style["strokeColor"] && style["fillColor"]) { + style["strokeColor"] = style["fillColor"]; + } + + var id = node.getAttribute("id"); + if (id && style) { + style.id = id; + } + + return style; + }, + + /** + * Method: parseStyleMaps + * Parses <StyleMap> nodes, but only uses the 'normal' key + * + * Parameters: + * nodes - {Array} of {DOMElement} data to read/parse. + * options - {Object} Hash of options + * + */ + parseStyleMaps: function(nodes, options) { + // Only the default or "normal" part of the StyleMap is processed now + // To do the select or "highlight" bit, we'd need to change lots more + + for(var i=0, len=nodes.length; i<len; i++) { + var node = nodes[i]; + var pairs = this.getElementsByTagNameNS(node, "*", + "Pair"); + + var id = node.getAttribute("id"); + for (var j=0, jlen=pairs.length; j<jlen; j++) { + var pair = pairs[j]; + // Use the shortcut in the SLD format to quickly retrieve the + // value of a node. Maybe it's good to have a method in + // Format.XML to do this + var key = this.parseProperty(pair, "*", "key"); + var styleUrl = this.parseProperty(pair, "*", "styleUrl"); + + if (styleUrl && key == "normal") { + this.styles[(options.styleBaseUrl || "") + "#" + id] = + this.styles[(options.styleBaseUrl || "") + styleUrl]; + } + + // TODO: implement the "select" part + //if (styleUrl && key == "highlight") { + //} + + } + } + + }, + + + /** + * Method: parseFeatures + * Loop through all Placemark nodes and parse them. + * Will create a list of features + * + * Parameters: + * nodes - {Array} of {DOMElement} data to read/parse. + * options - {Object} Hash of options + * + */ + parseFeatures: function(nodes, options) { + var features = []; + for(var i=0, len=nodes.length; i<len; i++) { + var featureNode = nodes[i]; + var feature = this.parseFeature.apply(this,[featureNode]) ; + if(feature) { + + // Create reference to styleUrl + if (this.extractStyles && feature.attributes && + feature.attributes.styleUrl) { + feature.style = this.getStyle(feature.attributes.styleUrl, options); + } + + if (this.extractStyles) { + // Make sure that <Style> nodes within a placemark are + // processed as well + var inlineStyleNode = this.getElementsByTagNameNS(featureNode, + "*", + "Style")[0]; + if (inlineStyleNode) { + var inlineStyle= this.parseStyle(inlineStyleNode); + if (inlineStyle) { + feature.style = OpenLayers.Util.extend( + feature.style, inlineStyle + ); + } + } + } + + // check if gx:Track elements should be parsed + if (this.extractTracks) { + var tracks = this.getElementsByTagNameNS( + featureNode, this.namespaces.gx, "Track" + ); + if (tracks && tracks.length > 0) { + var track = tracks[0]; + var container = { + features: [], + feature: feature + }; + this.readNode(track, container); + if (container.features.length > 0) { + features.push.apply(features, container.features); + } + } + } else { + // add feature to list of features + features.push(feature); + } + } else { + throw "Bad Placemark: " + i; + } + } + + // add new features to existing feature list + this.features = this.features.concat(features); + }, + + /** + * 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: { + "kml": { + "when": function(node, container) { + container.whens.push(OpenLayers.Date.parse( + this.getChildValue(node) + )); + }, + "_trackPointAttribute": function(node, container) { + var name = node.nodeName.split(":").pop(); + container.attributes[name].push(this.getChildValue(node)); + } + }, + "gx": { + "Track": function(node, container) { + var obj = { + whens: [], + points: [], + angles: [] + }; + if (this.trackAttributes) { + var name; + obj.attributes = {}; + for (var i=0, ii=this.trackAttributes.length; i<ii; ++i) { + name = this.trackAttributes[i]; + obj.attributes[name] = []; + if (!(name in this.readers.kml)) { + this.readers.kml[name] = this.readers.kml._trackPointAttribute; + } + } + } + this.readChildNodes(node, obj); + if (obj.whens.length !== obj.points.length) { + throw new Error("gx:Track with unequal number of when (" + + obj.whens.length + ") and gx:coord (" + + obj.points.length + ") elements."); + } + var hasAngles = obj.angles.length > 0; + if (hasAngles && obj.whens.length !== obj.angles.length) { + throw new Error("gx:Track with unequal number of when (" + + obj.whens.length + ") and gx:angles (" + + obj.angles.length + ") elements."); + } + var feature, point, angles; + for (var i=0, ii=obj.whens.length; i<ii; ++i) { + feature = container.feature.clone(); + feature.fid = container.feature.fid || container.feature.id; + point = obj.points[i]; + feature.geometry = point; + if ("z" in point) { + feature.attributes.altitude = point.z; + } + if (this.internalProjection && this.externalProjection) { + feature.geometry.transform( + this.externalProjection, this.internalProjection + ); + } + if (this.trackAttributes) { + for (var j=0, jj=this.trackAttributes.length; j<jj; ++j) { + var name = this.trackAttributes[j]; + feature.attributes[name] = obj.attributes[name][i]; + } + } + feature.attributes.when = obj.whens[i]; + feature.attributes.trackId = container.feature.id; + if (hasAngles) { + angles = obj.angles[i]; + feature.attributes.heading = parseFloat(angles[0]); + feature.attributes.tilt = parseFloat(angles[1]); + feature.attributes.roll = parseFloat(angles[2]); + } + container.features.push(feature); + } + }, + "coord": function(node, container) { + var str = this.getChildValue(node); + var coords = str.replace(this.regExes.trimSpace, "").split(/\s+/); + var point = new OpenLayers.Geometry.Point(coords[0], coords[1]); + if (coords.length > 2) { + point.z = parseFloat(coords[2]); + } + container.points.push(point); + }, + "angles": function(node, container) { + var str = this.getChildValue(node); + var parts = str.replace(this.regExes.trimSpace, "").split(/\s+/); + container.angles.push(parts); + } + } + }, + + /** + * Method: parseFeature + * This function is the core of the KML parsing code in OpenLayers. + * It creates the geometries that are then attached to the returned + * feature, and calls parseAttributes() to get attribute data out. + * + * Parameters: + * node - {DOMElement} + * + * Returns: + * {<OpenLayers.Feature.Vector>} A vector feature. + */ + parseFeature: function(node) { + // only accept one geometry per feature - look for highest "order" + var order = ["MultiGeometry", "Polygon", "LineString", "Point"]; + var type, nodeList, geometry, parser; + for(var i=0, len=order.length; i<len; ++i) { + type = order[i]; + this.internalns = node.namespaceURI ? + node.namespaceURI : this.kmlns; + nodeList = this.getElementsByTagNameNS(node, + this.internalns, type); + if(nodeList.length > 0) { + // only deal with first geometry of this type + var parser = this.parseGeometry[type.toLowerCase()]; + if(parser) { + geometry = parser.apply(this, [nodeList[0]]); + if (this.internalProjection && this.externalProjection) { + geometry.transform(this.externalProjection, + this.internalProjection); + } + } else { + throw new TypeError("Unsupported geometry type: " + type); + } + // stop looking for different geometry types + break; + } + } + + // construct feature (optionally with attributes) + var attributes; + if(this.extractAttributes) { + attributes = this.parseAttributes(node); + } + var feature = new OpenLayers.Feature.Vector(geometry, attributes); + + var fid = node.getAttribute("id") || node.getAttribute("name"); + if(fid != null) { + feature.fid = fid; + } + + return feature; + }, + + /** + * Method: getStyle + * Retrieves a style from a style hash using styleUrl as the key + * If the styleUrl doesn't exist yet, we try to fetch it + * Internet + * + * Parameters: + * styleUrl - {String} URL of style + * options - {Object} Hash of options + * + * Returns: + * {Object} - (reference to) Style hash + */ + getStyle: function(styleUrl, options) { + + var styleBaseUrl = OpenLayers.Util.removeTail(styleUrl); + + var newOptions = OpenLayers.Util.extend({}, options); + newOptions.depth++; + newOptions.styleBaseUrl = styleBaseUrl; + + // Fetch remote Style URLs (if not fetched before) + if (!this.styles[styleUrl] + && !OpenLayers.String.startsWith(styleUrl, "#") + && newOptions.depth <= this.maxDepth + && !this.fetched[styleBaseUrl] ) { + + var data = this.fetchLink(styleBaseUrl); + if (data) { + this.parseData(data, newOptions); + } + + } + + // return requested style + var style = OpenLayers.Util.extend({}, this.styles[styleUrl]); + return style; + }, + + /** + * Property: parseGeometry + * Properties of this object are the functions that parse geometries based + * on their type. + */ + parseGeometry: { + + /** + * Method: parseGeometry.point + * Given a KML node representing a point geometry, create an OpenLayers + * point geometry. + * + * Parameters: + * node - {DOMElement} A KML Point node. + * + * Returns: + * {<OpenLayers.Geometry.Point>} A point geometry. + */ + point: function(node) { + var nodeList = this.getElementsByTagNameNS(node, this.internalns, + "coordinates"); + var coords = []; + if(nodeList.length > 0) { + var coordString = nodeList[0].firstChild.nodeValue; + coordString = coordString.replace(this.regExes.removeSpace, ""); + coords = coordString.split(","); + } + + var point = null; + if(coords.length > 1) { + // preserve third dimension + if(coords.length == 2) { + coords[2] = null; + } + point = new OpenLayers.Geometry.Point(coords[0], coords[1], + coords[2]); + } else { + throw "Bad coordinate string: " + coordString; + } + return point; + }, + + /** + * Method: parseGeometry.linestring + * Given a KML node representing a linestring geometry, create an + * OpenLayers linestring geometry. + * + * Parameters: + * node - {DOMElement} A KML LineString node. + * + * Returns: + * {<OpenLayers.Geometry.LineString>} A linestring geometry. + */ + linestring: function(node, ring) { + var nodeList = this.getElementsByTagNameNS(node, this.internalns, + "coordinates"); + var line = null; + if(nodeList.length > 0) { + var coordString = this.getChildValue(nodeList[0]); + + coordString = coordString.replace(this.regExes.trimSpace, + ""); + coordString = coordString.replace(this.regExes.trimComma, + ","); + var pointList = coordString.split(this.regExes.splitSpace); + var numPoints = pointList.length; + var points = new Array(numPoints); + var coords, numCoords; + for(var i=0; i<numPoints; ++i) { + coords = pointList[i].split(","); + numCoords = coords.length; + if(numCoords > 1) { + if(coords.length == 2) { + coords[2] = null; + } + points[i] = new OpenLayers.Geometry.Point(coords[0], + coords[1], + coords[2]); + } else { + throw "Bad LineString point coordinates: " + + pointList[i]; + } + } + if(numPoints) { + if(ring) { + line = new OpenLayers.Geometry.LinearRing(points); + } else { + line = new OpenLayers.Geometry.LineString(points); + } + } else { + throw "Bad LineString coordinates: " + coordString; + } + } + + return line; + }, + + /** + * Method: parseGeometry.polygon + * Given a KML node representing a polygon geometry, create an + * OpenLayers polygon geometry. + * + * Parameters: + * node - {DOMElement} A KML Polygon node. + * + * Returns: + * {<OpenLayers.Geometry.Polygon>} A polygon geometry. + */ + polygon: function(node) { + var nodeList = this.getElementsByTagNameNS(node, this.internalns, + "LinearRing"); + var numRings = nodeList.length; + var components = new Array(numRings); + if(numRings > 0) { + // this assumes exterior ring first, inner rings after + var ring; + for(var i=0, len=nodeList.length; i<len; ++i) { + ring = this.parseGeometry.linestring.apply(this, + [nodeList[i], true]); + if(ring) { + components[i] = ring; + } else { + throw "Bad LinearRing geometry: " + i; + } + } + } + return new OpenLayers.Geometry.Polygon(components); + }, + + /** + * Method: parseGeometry.multigeometry + * Given a KML node representing a multigeometry, create an + * OpenLayers geometry collection. + * + * Parameters: + * node - {DOMElement} A KML MultiGeometry node. + * + * Returns: + * {<OpenLayers.Geometry.Collection>} A geometry collection. + */ + multigeometry: function(node) { + var child, parser; + var parts = []; + var children = node.childNodes; + for(var i=0, len=children.length; i<len; ++i ) { + child = children[i]; + if(child.nodeType == 1) { + var type = (child.prefix) ? + child.nodeName.split(":")[1] : + child.nodeName; + var parser = this.parseGeometry[type.toLowerCase()]; + if(parser) { + parts.push(parser.apply(this, [child])); + } + } + } + return new OpenLayers.Geometry.Collection(parts); + } + + }, + + /** + * Method: parseAttributes + * + * Parameters: + * node - {DOMElement} + * + * Returns: + * {Object} An attributes object. + */ + parseAttributes: function(node) { + var attributes = {}; + + // Extended Data is parsed first. + var edNodes = node.getElementsByTagName("ExtendedData"); + if (edNodes.length) { + attributes = this.parseExtendedData(edNodes[0]); + } + + // assume attribute nodes are type 1 children with a type 3 or 4 child + var child, grandchildren, grandchild; + var children = node.childNodes; + + for(var i=0, len=children.length; i<len; ++i) { + child = children[i]; + if(child.nodeType == 1) { + grandchildren = child.childNodes; + if(grandchildren.length >= 1 && grandchildren.length <= 3) { + var grandchild; + switch (grandchildren.length) { + case 1: + grandchild = grandchildren[0]; + break; + case 2: + var c1 = grandchildren[0]; + var c2 = grandchildren[1]; + grandchild = (c1.nodeType == 3 || c1.nodeType == 4) ? + c1 : c2; + break; + case 3: + default: + grandchild = grandchildren[1]; + break; + } + if(grandchild.nodeType == 3 || grandchild.nodeType == 4) { + var name = (child.prefix) ? + child.nodeName.split(":")[1] : + child.nodeName; + var value = OpenLayers.Util.getXmlNodeValue(grandchild); + if (value) { + value = value.replace(this.regExes.trimSpace, ""); + attributes[name] = value; + } + } + } + } + } + return attributes; + }, + + /** + * Method: parseExtendedData + * Parse ExtendedData from KML. Limited support for schemas/datatypes. + * See http://code.google.com/apis/kml/documentation/kmlreference.html#extendeddata + * for more information on extendeddata. + */ + parseExtendedData: function(node) { + var attributes = {}; + var i, len, data, key; + var dataNodes = node.getElementsByTagName("Data"); + for (i = 0, len = dataNodes.length; i < len; i++) { + data = dataNodes[i]; + key = data.getAttribute("name"); + var ed = {}; + var valueNode = data.getElementsByTagName("value"); + if (valueNode.length) { + ed['value'] = this.getChildValue(valueNode[0]); + } + if (this.kvpAttributes) { + attributes[key] = ed['value']; + } else { + var nameNode = data.getElementsByTagName("displayName"); + if (nameNode.length) { + ed['displayName'] = this.getChildValue(nameNode[0]); + } + attributes[key] = ed; + } + } + var simpleDataNodes = node.getElementsByTagName("SimpleData"); + for (i = 0, len = simpleDataNodes.length; i < len; i++) { + var ed = {}; + data = simpleDataNodes[i]; + key = data.getAttribute("name"); + ed['value'] = this.getChildValue(data); + if (this.kvpAttributes) { + attributes[key] = ed['value']; + } else { + ed['displayName'] = key; + attributes[key] = ed; + } + } + + return attributes; + }, + + /** + * Method: parseProperty + * Convenience method to find a node and return its value + * + * Parameters: + * xmlNode - {<DOMElement>} + * namespace - {String} namespace of the node to find + * tagName - {String} name of the property to parse + * + * Returns: + * {String} The value for the requested property (defaults to null) + */ + parseProperty: function(xmlNode, namespace, tagName) { + var value; + var nodeList = this.getElementsByTagNameNS(xmlNode, namespace, tagName); + try { + value = OpenLayers.Util.getXmlNodeValue(nodeList[0]); + } catch(e) { + value = null; + } + + return value; + }, + + /** + * APIMethod: write + * Accept Feature Collection, and return a string. + * + * Parameters: + * features - {Array(<OpenLayers.Feature.Vector>)} An array of features. + * + * Returns: + * {String} A KML string. + */ + write: function(features) { + if(!(OpenLayers.Util.isArray(features))) { + features = [features]; + } + var kml = this.createElementNS(this.kmlns, "kml"); + var folder = this.createFolderXML(); + for(var i=0, len=features.length; i<len; ++i) { + folder.appendChild(this.createPlacemarkXML(features[i])); + } + kml.appendChild(folder); + return OpenLayers.Format.XML.prototype.write.apply(this, [kml]); + }, + + /** + * Method: createFolderXML + * Creates and returns a KML folder node + * + * Returns: + * {DOMElement} + */ + createFolderXML: function() { + // Folder + var folder = this.createElementNS(this.kmlns, "Folder"); + + // Folder name + if (this.foldersName) { + var folderName = this.createElementNS(this.kmlns, "name"); + var folderNameText = this.createTextNode(this.foldersName); + folderName.appendChild(folderNameText); + folder.appendChild(folderName); + } + + // Folder description + if (this.foldersDesc) { + var folderDesc = this.createElementNS(this.kmlns, "description"); + var folderDescText = this.createTextNode(this.foldersDesc); + folderDesc.appendChild(folderDescText); + folder.appendChild(folderDesc); + } + + return folder; + }, + + /** + * Method: createPlacemarkXML + * Creates and returns a KML placemark node representing the given feature. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} + * + * Returns: + * {DOMElement} + */ + createPlacemarkXML: function(feature) { + // Placemark name + var placemarkName = this.createElementNS(this.kmlns, "name"); + var label = (feature.style && feature.style.label) ? feature.style.label : feature.id; + var name = feature.attributes.name || label; + placemarkName.appendChild(this.createTextNode(name)); + + // Placemark description + var placemarkDesc = this.createElementNS(this.kmlns, "description"); + var desc = feature.attributes.description || this.placemarksDesc; + placemarkDesc.appendChild(this.createTextNode(desc)); + + // Placemark + var placemarkNode = this.createElementNS(this.kmlns, "Placemark"); + if(feature.fid != null) { + placemarkNode.setAttribute("id", feature.fid); + } + placemarkNode.appendChild(placemarkName); + placemarkNode.appendChild(placemarkDesc); + + // Geometry node (Point, LineString, etc. nodes) + var geometryNode = this.buildGeometryNode(feature.geometry); + placemarkNode.appendChild(geometryNode); + + // output attributes as extendedData + if (feature.attributes) { + var edNode = this.buildExtendedData(feature.attributes); + if (edNode) { + placemarkNode.appendChild(edNode); + } + } + + return placemarkNode; + }, + + /** + * Method: buildGeometryNode + * Builds and returns a KML geometry node with the given geometry. + * + * Parameters: + * geometry - {<OpenLayers.Geometry>} + * + * Returns: + * {DOMElement} + */ + buildGeometryNode: function(geometry) { + var className = geometry.CLASS_NAME; + var type = className.substring(className.lastIndexOf(".") + 1); + var builder = this.buildGeometry[type.toLowerCase()]; + var node = null; + if(builder) { + node = builder.apply(this, [geometry]); + } + return node; + }, + + /** + * Property: buildGeometry + * Object containing methods to do the actual geometry node building + * based on geometry type. + */ + buildGeometry: { + // TBD: Anybody care about namespace aliases here (these nodes have + // no prefixes)? + + /** + * Method: buildGeometry.point + * Given an OpenLayers point geometry, create a KML point. + * + * Parameters: + * geometry - {<OpenLayers.Geometry.Point>} A point geometry. + * + * Returns: + * {DOMElement} A KML point node. + */ + point: function(geometry) { + var kml = this.createElementNS(this.kmlns, "Point"); + kml.appendChild(this.buildCoordinatesNode(geometry)); + return kml; + }, + + /** + * Method: buildGeometry.multipoint + * Given an OpenLayers multipoint geometry, create a KML + * GeometryCollection. + * + * Parameters: + * geometry - {<OpenLayers.Geometry.Point>} A multipoint geometry. + * + * Returns: + * {DOMElement} A KML GeometryCollection node. + */ + multipoint: function(geometry) { + return this.buildGeometry.collection.apply(this, [geometry]); + }, + + /** + * Method: buildGeometry.linestring + * Given an OpenLayers linestring geometry, create a KML linestring. + * + * Parameters: + * geometry - {<OpenLayers.Geometry.LineString>} A linestring geometry. + * + * Returns: + * {DOMElement} A KML linestring node. + */ + linestring: function(geometry) { + var kml = this.createElementNS(this.kmlns, "LineString"); + kml.appendChild(this.buildCoordinatesNode(geometry)); + return kml; + }, + + /** + * Method: buildGeometry.multilinestring + * Given an OpenLayers multilinestring geometry, create a KML + * GeometryCollection. + * + * Parameters: + * geometry - {<OpenLayers.Geometry.Point>} A multilinestring geometry. + * + * Returns: + * {DOMElement} A KML GeometryCollection node. + */ + multilinestring: function(geometry) { + return this.buildGeometry.collection.apply(this, [geometry]); + }, + + /** + * Method: buildGeometry.linearring + * Given an OpenLayers linearring geometry, create a KML linearring. + * + * Parameters: + * geometry - {<OpenLayers.Geometry.LinearRing>} A linearring geometry. + * + * Returns: + * {DOMElement} A KML linearring node. + */ + linearring: function(geometry) { + var kml = this.createElementNS(this.kmlns, "LinearRing"); + kml.appendChild(this.buildCoordinatesNode(geometry)); + return kml; + }, + + /** + * Method: buildGeometry.polygon + * Given an OpenLayers polygon geometry, create a KML polygon. + * + * Parameters: + * geometry - {<OpenLayers.Geometry.Polygon>} A polygon geometry. + * + * Returns: + * {DOMElement} A KML polygon node. + */ + polygon: function(geometry) { + var kml = this.createElementNS(this.kmlns, "Polygon"); + var rings = geometry.components; + var ringMember, ringGeom, type; + for(var i=0, len=rings.length; i<len; ++i) { + type = (i==0) ? "outerBoundaryIs" : "innerBoundaryIs"; + ringMember = this.createElementNS(this.kmlns, type); + ringGeom = this.buildGeometry.linearring.apply(this, + [rings[i]]); + ringMember.appendChild(ringGeom); + kml.appendChild(ringMember); + } + return kml; + }, + + /** + * Method: buildGeometry.multipolygon + * Given an OpenLayers multipolygon geometry, create a KML + * GeometryCollection. + * + * Parameters: + * geometry - {<OpenLayers.Geometry.Point>} A multipolygon geometry. + * + * Returns: + * {DOMElement} A KML GeometryCollection node. + */ + multipolygon: function(geometry) { + return this.buildGeometry.collection.apply(this, [geometry]); + }, + + /** + * Method: buildGeometry.collection + * Given an OpenLayers geometry collection, create a KML MultiGeometry. + * + * Parameters: + * geometry - {<OpenLayers.Geometry.Collection>} A geometry collection. + * + * Returns: + * {DOMElement} A KML MultiGeometry node. + */ + collection: function(geometry) { + var kml = this.createElementNS(this.kmlns, "MultiGeometry"); + var child; + for(var i=0, len=geometry.components.length; i<len; ++i) { + child = this.buildGeometryNode.apply(this, + [geometry.components[i]]); + if(child) { + kml.appendChild(child); + } + } + return kml; + } + }, + + /** + * Method: buildCoordinatesNode + * Builds and returns the KML coordinates node with the given geometry + * <coordinates>...</coordinates> + * + * Parameters: + * geometry - {<OpenLayers.Geometry>} + * + * Returns: + * {DOMElement} + */ + buildCoordinatesNode: function(geometry) { + var coordinatesNode = this.createElementNS(this.kmlns, "coordinates"); + + var path; + var points = geometry.components; + if(points) { + // LineString or LinearRing + var point; + var numPoints = points.length; + var parts = new Array(numPoints); + for(var i=0; i<numPoints; ++i) { + point = points[i]; + parts[i] = this.buildCoordinates(point); + } + path = parts.join(" "); + } else { + // Point + path = this.buildCoordinates(geometry); + } + + var txtNode = this.createTextNode(path); + coordinatesNode.appendChild(txtNode); + + return coordinatesNode; + }, + + /** + * Method: buildCoordinates + * + * Parameters: + * point - {<OpenLayers.Geometry.Point>} + * + * Returns + * {String} a coordinate pair + */ + buildCoordinates: function(point) { + if (this.internalProjection && this.externalProjection) { + point = point.clone(); + point.transform(this.internalProjection, + this.externalProjection); + } + return point.x + "," + point.y; + }, + + /** + * Method: buildExtendedData + * + * Parameters: + * attributes - {Object} + * + * Returns + * {DOMElement} A KML ExtendedData node or {null} if no attributes. + */ + buildExtendedData: function(attributes) { + var extendedData = this.createElementNS(this.kmlns, "ExtendedData"); + for (var attributeName in attributes) { + // empty, name, description, styleUrl attributes ignored + if (attributes[attributeName] && attributeName != "name" && attributeName != "description" && attributeName != "styleUrl") { + var data = this.createElementNS(this.kmlns, "Data"); + data.setAttribute("name", attributeName); + var value = this.createElementNS(this.kmlns, "value"); + if (typeof attributes[attributeName] == "object") { + // cater for object attributes with 'value' properties + // other object properties will output an empty node + if (attributes[attributeName].value) { + value.appendChild(this.createTextNode(attributes[attributeName].value)); + } + if (attributes[attributeName].displayName) { + var displayName = this.createElementNS(this.kmlns, "displayName"); + // displayName always written as CDATA + displayName.appendChild(this.getXMLDoc().createCDATASection(attributes[attributeName].displayName)); + data.appendChild(displayName); + } + } else { + value.appendChild(this.createTextNode(attributes[attributeName])); + } + data.appendChild(value); + extendedData.appendChild(data); + } + } + if (this.isSimpleContent(extendedData)) { + return null; + } else { + return extendedData; + } + }, + + CLASS_NAME: "OpenLayers.Format.KML" +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/OGCExceptionReport.js b/misc/openlayers/lib/OpenLayers/Format/OGCExceptionReport.js new file mode 100644 index 0000000..61a9da5 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/OGCExceptionReport.js @@ -0,0 +1,108 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + */ + +/** + * Class: OpenLayers.Format.OGCExceptionReport + * Class to read exception reports for various OGC services and versions. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.OGCExceptionReport = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + ogc: "http://www.opengis.net/ogc" + }, + + /** + * Property: regExes + * Compiled regular expressions for manipulating strings. + */ + regExes: { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g) + }, + + /** + * Property: defaultPrefix + */ + defaultPrefix: "ogc", + + /** + * Constructor: OpenLayers.Format.OGCExceptionReport + * Create a new parser for OGC exception reports. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Read OGC exception report data from a string, and return an object with + * information about the exceptions. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Object} Information about the exceptions that occurred. + */ + read: function(data) { + var result; + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + var root = data.documentElement; + var exceptionInfo = {exceptionReport: null}; + if (root) { + this.readChildNodes(data, exceptionInfo); + if (exceptionInfo.exceptionReport === null) { + // fall-back to OWSCommon since this is a common output format for exceptions + // we cannot easily use the ows readers directly since they differ for 1.0 and 1.1 + exceptionInfo = new OpenLayers.Format.OWSCommon().read(data); + } + } + return exceptionInfo; + }, + + /** + * 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: { + "ogc": { + "ServiceExceptionReport": function(node, obj) { + obj.exceptionReport = {exceptions: []}; + this.readChildNodes(node, obj.exceptionReport); + }, + "ServiceException": function(node, exceptionReport) { + var exception = { + code: node.getAttribute("code"), + locator: node.getAttribute("locator"), + text: this.getChildValue(node) + }; + exceptionReport.exceptions.push(exception); + } + } + }, + + CLASS_NAME: "OpenLayers.Format.OGCExceptionReport" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/OSM.js b/misc/openlayers/lib/OpenLayers/Format/OSM.js new file mode 100644 index 0000000..7283348 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/OSM.js @@ -0,0 +1,465 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Feature/Vector.js + * @requires OpenLayers/Geometry/Point.js + * @requires OpenLayers/Geometry/LineString.js + * @requires OpenLayers/Geometry/Polygon.js + * @requires OpenLayers/Projection.js + */ + +/** + * Class: OpenLayers.Format.OSM + * OSM parser. Create a new instance with the + * <OpenLayers.Format.OSM> constructor. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.OSM = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * APIProperty: checkTags + * {Boolean} Should tags be checked to determine whether something + * should be treated as a seperate node. Will slow down parsing. + * Default is false. + */ + checkTags: false, + + /** + * Property: interestingTagsExclude + * {Array} List of tags to exclude from 'interesting' checks on nodes. + * Must be set when creating the format. Will only be used if checkTags + * is set. + */ + interestingTagsExclude: null, + + /** + * APIProperty: areaTags + * {Array} List of tags indicating that something is an area. + * Must be set when creating the format. Will only be used if + * checkTags is true. + */ + areaTags: null, + + /** + * Constructor: OpenLayers.Format.OSM + * Create a new parser for OSM. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + var layer_defaults = { + 'interestingTagsExclude': ['source', 'source_ref', + 'source:ref', 'history', 'attribution', 'created_by'], + 'areaTags': ['area', 'building', 'leisure', 'tourism', 'ruins', + 'historic', 'landuse', 'military', 'natural', 'sport'] + }; + + layer_defaults = OpenLayers.Util.extend(layer_defaults, options); + + var interesting = {}; + for (var i = 0; i < layer_defaults.interestingTagsExclude.length; i++) { + interesting[layer_defaults.interestingTagsExclude[i]] = true; + } + layer_defaults.interestingTagsExclude = interesting; + + var area = {}; + for (var i = 0; i < layer_defaults.areaTags.length; i++) { + area[layer_defaults.areaTags[i]] = true; + } + layer_defaults.areaTags = area; + + // OSM coordinates are always in longlat WGS84 + this.externalProjection = new OpenLayers.Projection("EPSG:4326"); + + OpenLayers.Format.XML.prototype.initialize.apply(this, [layer_defaults]); + }, + + /** + * APIMethod: read + * Return a list of features from a OSM doc + + * Parameters: + * doc - {Element} + * + * Returns: + * Array({<OpenLayers.Feature.Vector>}) + */ + read: function(doc) { + if (typeof doc == "string") { + doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]); + } + + var nodes = this.getNodes(doc); + var ways = this.getWays(doc); + + // Geoms will contain at least ways.length entries. + var feat_list = new Array(ways.length); + + for (var i = 0; i < ways.length; i++) { + // We know the minimal of this one ahead of time. (Could be -1 + // due to areas/polygons) + var point_list = new Array(ways[i].nodes.length); + + var poly = this.isWayArea(ways[i]) ? 1 : 0; + for (var j = 0; j < ways[i].nodes.length; j++) { + var node = nodes[ways[i].nodes[j]]; + + var point = new OpenLayers.Geometry.Point(node.lon, node.lat); + + // Since OSM is topological, we stash the node ID internally. + point.osm_id = parseInt(ways[i].nodes[j]); + point_list[j] = point; + + // We don't display nodes if they're used inside other + // elements. + node.used = true; + } + var geometry = null; + if (poly) { + geometry = new OpenLayers.Geometry.Polygon( + new OpenLayers.Geometry.LinearRing(point_list)); + } else { + geometry = new OpenLayers.Geometry.LineString(point_list); + } + if (this.internalProjection && this.externalProjection) { + geometry.transform(this.externalProjection, + this.internalProjection); + } + var feat = new OpenLayers.Feature.Vector(geometry, + ways[i].tags); + feat.osm_id = parseInt(ways[i].id); + feat.fid = "way." + feat.osm_id; + feat_list[i] = feat; + } + for (var node_id in nodes) { + var node = nodes[node_id]; + if (!node.used || this.checkTags) { + var tags = null; + + if (this.checkTags) { + var result = this.getTags(node.node, true); + if (node.used && !result[1]) { + continue; + } + tags = result[0]; + } else { + tags = this.getTags(node.node); + } + + var feat = new OpenLayers.Feature.Vector( + new OpenLayers.Geometry.Point(node['lon'], node['lat']), + tags); + if (this.internalProjection && this.externalProjection) { + feat.geometry.transform(this.externalProjection, + this.internalProjection); + } + feat.osm_id = parseInt(node_id); + feat.fid = "node." + feat.osm_id; + feat_list.push(feat); + } + // Memory cleanup + node.node = null; + } + return feat_list; + }, + + /** + * Method: getNodes + * Return the node items from a doc. + * + * Parameters: + * doc - {DOMElement} node to parse tags from + */ + getNodes: function(doc) { + var node_list = doc.getElementsByTagName("node"); + var nodes = {}; + for (var i = 0; i < node_list.length; i++) { + var node = node_list[i]; + var id = node.getAttribute("id"); + nodes[id] = { + 'lat': node.getAttribute("lat"), + 'lon': node.getAttribute("lon"), + 'node': node + }; + } + return nodes; + }, + + /** + * Method: getWays + * Return the way items from a doc. + * + * Parameters: + * doc - {DOMElement} node to parse tags from + */ + getWays: function(doc) { + var way_list = doc.getElementsByTagName("way"); + var return_ways = []; + for (var i = 0; i < way_list.length; i++) { + var way = way_list[i]; + var way_object = { + id: way.getAttribute("id") + }; + + way_object.tags = this.getTags(way); + + var node_list = way.getElementsByTagName("nd"); + + way_object.nodes = new Array(node_list.length); + + for (var j = 0; j < node_list.length; j++) { + way_object.nodes[j] = node_list[j].getAttribute("ref"); + } + return_ways.push(way_object); + } + return return_ways; + + }, + + /** + * Method: getTags + * Return the tags list attached to a specific DOM element. + * + * Parameters: + * dom_node - {DOMElement} node to parse tags from + * interesting_tags - {Boolean} whether the return from this function should + * return a boolean indicating that it has 'interesting tags' -- + * tags like attribution and source are ignored. (To change the list + * of tags, see interestingTagsExclude) + * + * Returns: + * tags - {Object} hash of tags + * interesting - {Boolean} if interesting_tags is passed, returns + * whether there are any interesting tags on this element. + */ + getTags: function(dom_node, interesting_tags) { + var tag_list = dom_node.getElementsByTagName("tag"); + var tags = {}; + var interesting = false; + for (var j = 0; j < tag_list.length; j++) { + var key = tag_list[j].getAttribute("k"); + tags[key] = tag_list[j].getAttribute("v"); + if (interesting_tags) { + if (!this.interestingTagsExclude[key]) { + interesting = true; + } + } + } + return interesting_tags ? [tags, interesting] : tags; + }, + + /** + * Method: isWayArea + * Given a way object from getWays, check whether the tags and geometry + * indicate something is an area. + * + * Returns: + * {Boolean} + */ + isWayArea: function(way) { + var poly_shaped = false; + var poly_tags = false; + + if (way.nodes[0] == way.nodes[way.nodes.length - 1]) { + poly_shaped = true; + } + if (this.checkTags) { + for(var key in way.tags) { + if (this.areaTags[key]) { + poly_tags = true; + break; + } + } + } + return poly_shaped && (this.checkTags ? poly_tags : true); + }, + + /** + * APIMethod: write + * Takes a list of features, returns a serialized OSM format file for use + * in tools like JOSM. + * + * Parameters: + * features - {Array(<OpenLayers.Feature.Vector>)} + */ + write: function(features) { + if (!(OpenLayers.Util.isArray(features))) { + features = [features]; + } + + this.osm_id = 1; + this.created_nodes = {}; + var root_node = this.createElementNS(null, "osm"); + root_node.setAttribute("version", "0.5"); + root_node.setAttribute("generator", "OpenLayers "+ OpenLayers.VERSION_NUMBER); + + // Loop backwards, because the deserializer puts nodes last, and + // we want them first if possible + for(var i = features.length - 1; i >= 0; i--) { + var nodes = this.createFeatureNodes(features[i]); + for (var j = 0; j < nodes.length; j++) { + root_node.appendChild(nodes[j]); + } + } + return OpenLayers.Format.XML.prototype.write.apply(this, [root_node]); + }, + + /** + * Method: createFeatureNodes + * Takes a feature, returns a list of nodes from size 0->n. + * Will include all pieces of the serialization that are required which + * have not already been created. Calls out to createXML based on geometry + * type. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} + */ + createFeatureNodes: function(feature) { + var nodes = []; + var className = feature.geometry.CLASS_NAME; + var type = className.substring(className.lastIndexOf(".") + 1); + type = type.toLowerCase(); + var builder = this.createXML[type]; + if (builder) { + nodes = builder.apply(this, [feature]); + } + return nodes; + }, + + /** + * Method: createXML + * Takes a feature, returns a list of nodes from size 0->n. + * Will include all pieces of the serialization that are required which + * have not already been created. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} + */ + createXML: { + 'point': function(point) { + var id = null; + var geometry = point.geometry ? point.geometry : point; + + if (this.internalProjection && this.externalProjection) { + geometry = geometry.clone(); + geometry.transform(this.internalProjection, + this.externalProjection); + } + + var already_exists = false; // We don't return anything if the node + // has already been created + if (point.osm_id) { + id = point.osm_id; + if (this.created_nodes[id]) { + already_exists = true; + } + } else { + id = -this.osm_id; + this.osm_id++; + } + if (already_exists) { + node = this.created_nodes[id]; + } else { + var node = this.createElementNS(null, "node"); + } + this.created_nodes[id] = node; + node.setAttribute("id", id); + node.setAttribute("lon", geometry.x); + node.setAttribute("lat", geometry.y); + if (point.attributes) { + this.serializeTags(point, node); + } + this.setState(point, node); + return already_exists ? [] : [node]; + }, + linestring: function(feature) { + var id; + var nodes = []; + var geometry = feature.geometry; + if (feature.osm_id) { + id = feature.osm_id; + } else { + id = -this.osm_id; + this.osm_id++; + } + var way = this.createElementNS(null, "way"); + way.setAttribute("id", id); + for (var i = 0; i < geometry.components.length; i++) { + var node = this.createXML['point'].apply(this, [geometry.components[i]]); + if (node.length) { + node = node[0]; + var node_ref = node.getAttribute("id"); + nodes.push(node); + } else { + node_ref = geometry.components[i].osm_id; + node = this.created_nodes[node_ref]; + } + this.setState(feature, node); + var nd_dom = this.createElementNS(null, "nd"); + nd_dom.setAttribute("ref", node_ref); + way.appendChild(nd_dom); + } + this.serializeTags(feature, way); + nodes.push(way); + + return nodes; + }, + polygon: function(feature) { + var attrs = OpenLayers.Util.extend({'area':'yes'}, feature.attributes); + var feat = new OpenLayers.Feature.Vector(feature.geometry.components[0], attrs); + feat.osm_id = feature.osm_id; + return this.createXML['linestring'].apply(this, [feat]); + } + }, + + /** + * Method: serializeTags + * Given a feature, serialize the attributes onto the given node. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} + * node - {DOMNode} + */ + serializeTags: function(feature, node) { + for (var key in feature.attributes) { + var tag = this.createElementNS(null, "tag"); + tag.setAttribute("k", key); + tag.setAttribute("v", feature.attributes[key]); + node.appendChild(tag); + } + }, + + /** + * Method: setState + * OpenStreetMap has a convention that 'state' is stored for modification or deletion. + * This allows the file to be uploaded via JOSM or the bulk uploader tool. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} + * node - {DOMNode} + */ + setState: function(feature, node) { + if (feature.state) { + var state = null; + switch(feature.state) { + case OpenLayers.State.UPDATE: + state = "modify"; + case OpenLayers.State.DELETE: + state = "delete"; + } + if (state) { + node.setAttribute("action", state); + } + } + }, + + CLASS_NAME: "OpenLayers.Format.OSM" +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/OWSCommon.js b/misc/openlayers/lib/OpenLayers/Format/OWSCommon.js new file mode 100644 index 0000000..fd71820 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/OWSCommon.js @@ -0,0 +1,78 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML/VersionedOGC.js + */ + +/** + * Class: OpenLayers.Format.OWSCommon + * Read OWSCommon. Create a new instance with the <OpenLayers.Format.OWSCommon> + * constructor. + * + * Inherits from: + * - <OpenLayers.Format.XML.VersionedOGC> + */ +OpenLayers.Format.OWSCommon = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { + + /** + * APIProperty: defaultVersion + * {String} Version number to assume if none found. Default is "1.0.0". + */ + defaultVersion: "1.0.0", + + /** + * Constructor: OpenLayers.Format.OWSCommon + * Create a new parser for OWSCommon. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * Method: getVersion + * Returns the version to use. Subclasses can override this function + * if a different version detection is needed. + * + * Parameters: + * root - {DOMElement} + * options - {Object} Optional configuration object. + * + * Returns: + * {String} The version to use. + */ + getVersion: function(root, options) { + var version = this.version; + if(!version) { + // remember version does not correspond to the OWS version + // it corresponds to the WMS/WFS/WCS etc. request version + var uri = root.getAttribute("xmlns:ows"); + // the above will fail if the namespace prefix is different than + // ows and if the namespace is declared on a different element + if (uri && uri.substring(uri.lastIndexOf("/")+1) === "1.1") { + version ="1.1.0"; + } + if(!version) { + version = this.defaultVersion; + } + } + return version; + }, + + /** + * APIMethod: read + * Read an OWSCommon document and return an object. + * + * Parameters: + * data - {String | DOMElement} Data to read. + * options - {Object} Options for the reader. + * + * Returns: + * {Object} An object representing the structure of the document. + */ + + CLASS_NAME: "OpenLayers.Format.OWSCommon" +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/OWSCommon/v1.js b/misc/openlayers/lib/OpenLayers/Format/OWSCommon/v1.js new file mode 100644 index 0000000..57ae9d2 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/OWSCommon/v1.js @@ -0,0 +1,318 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/OWSCommon.js + */ + +/** + * Class: OpenLayers.Format.OWSCommon.v1 + * Common readers and writers for OWSCommon v1.X formats + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.OWSCommon.v1 = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * Property: regExes + * Compiled regular expressions for manipulating strings. + */ + regExes: { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g) + }, + + /** + * Method: read + * + * Parameters: + * data - {DOMElement} An OWSCommon document element. + * options - {Object} Options for the reader. + * + * Returns: + * {Object} An object representing the OWSCommon document. + */ + read: function(data, options) { + options = OpenLayers.Util.applyDefaults(options, this.options); + var ows = {}; + this.readChildNodes(data, ows); + return ows; + }, + + /** + * 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: { + "ows": { + "Exception": function(node, exceptionReport) { + var exception = { + code: node.getAttribute('exceptionCode'), + locator: node.getAttribute('locator'), + texts: [] + }; + exceptionReport.exceptions.push(exception); + this.readChildNodes(node, exception); + }, + "ExceptionText": function(node, exception) { + var text = this.getChildValue(node); + exception.texts.push(text); + }, + "ServiceIdentification": function(node, obj) { + obj.serviceIdentification = {}; + this.readChildNodes(node, obj.serviceIdentification); + }, + "Title": function(node, obj) { + obj.title = this.getChildValue(node); + }, + "Abstract": function(node, serviceIdentification) { + serviceIdentification["abstract"] = this.getChildValue(node); + }, + "Keywords": function(node, serviceIdentification) { + serviceIdentification.keywords = {}; + this.readChildNodes(node, serviceIdentification.keywords); + }, + "Keyword": function(node, keywords) { + keywords[this.getChildValue(node)] = true; + }, + "ServiceType": function(node, serviceIdentification) { + serviceIdentification.serviceType = { + codeSpace: node.getAttribute('codeSpace'), + value: this.getChildValue(node)}; + }, + "ServiceTypeVersion": function(node, serviceIdentification) { + serviceIdentification.serviceTypeVersion = this.getChildValue(node); + }, + "Fees": function(node, serviceIdentification) { + serviceIdentification.fees = this.getChildValue(node); + }, + "AccessConstraints": function(node, serviceIdentification) { + serviceIdentification.accessConstraints = + this.getChildValue(node); + }, + "ServiceProvider": function(node, obj) { + obj.serviceProvider = {}; + this.readChildNodes(node, obj.serviceProvider); + }, + "ProviderName": function(node, serviceProvider) { + serviceProvider.providerName = this.getChildValue(node); + }, + "ProviderSite": function(node, serviceProvider) { + serviceProvider.providerSite = this.getAttributeNS(node, + this.namespaces.xlink, "href"); + }, + "ServiceContact": function(node, serviceProvider) { + serviceProvider.serviceContact = {}; + this.readChildNodes(node, serviceProvider.serviceContact); + }, + "IndividualName": function(node, serviceContact) { + serviceContact.individualName = this.getChildValue(node); + }, + "PositionName": function(node, serviceContact) { + serviceContact.positionName = this.getChildValue(node); + }, + "ContactInfo": function(node, serviceContact) { + serviceContact.contactInfo = {}; + this.readChildNodes(node, serviceContact.contactInfo); + }, + "Phone": function(node, contactInfo) { + contactInfo.phone = {}; + this.readChildNodes(node, contactInfo.phone); + }, + "Voice": function(node, phone) { + phone.voice = this.getChildValue(node); + }, + "Address": function(node, contactInfo) { + contactInfo.address = {}; + this.readChildNodes(node, contactInfo.address); + }, + "DeliveryPoint": function(node, address) { + address.deliveryPoint = this.getChildValue(node); + }, + "City": function(node, address) { + address.city = this.getChildValue(node); + }, + "AdministrativeArea": function(node, address) { + address.administrativeArea = this.getChildValue(node); + }, + "PostalCode": function(node, address) { + address.postalCode = this.getChildValue(node); + }, + "Country": function(node, address) { + address.country = this.getChildValue(node); + }, + "ElectronicMailAddress": function(node, address) { + address.electronicMailAddress = this.getChildValue(node); + }, + "Role": function(node, serviceContact) { + serviceContact.role = this.getChildValue(node); + }, + "OperationsMetadata": function(node, obj) { + obj.operationsMetadata = {}; + this.readChildNodes(node, obj.operationsMetadata); + }, + "Operation": function(node, operationsMetadata) { + var name = node.getAttribute("name"); + operationsMetadata[name] = {}; + this.readChildNodes(node, operationsMetadata[name]); + }, + "DCP": function(node, operation) { + operation.dcp = {}; + this.readChildNodes(node, operation.dcp); + }, + "HTTP": function(node, dcp) { + dcp.http = {}; + this.readChildNodes(node, dcp.http); + }, + "Get": function(node, http) { + if (!http.get) { + http.get = []; + } + var obj = { + url: this.getAttributeNS(node, this.namespaces.xlink, "href") + }; + this.readChildNodes(node, obj); + http.get.push(obj); + }, + "Post": function(node, http) { + if (!http.post) { + http.post = []; + } + var obj = { + url: this.getAttributeNS(node, this.namespaces.xlink, "href") + }; + this.readChildNodes(node, obj); + http.post.push(obj); + }, + "Parameter": function(node, operation) { + if (!operation.parameters) { + operation.parameters = {}; + } + var name = node.getAttribute("name"); + operation.parameters[name] = {}; + this.readChildNodes(node, operation.parameters[name]); + }, + "Constraint": function(node, obj) { + if (!obj.constraints) { + obj.constraints = {}; + } + var name = node.getAttribute("name"); + obj.constraints[name] = {}; + this.readChildNodes(node, obj.constraints[name]); + }, + "Value": function(node, allowedValues) { + allowedValues[this.getChildValue(node)] = true; + }, + "OutputFormat": function(node, obj) { + obj.formats.push({value: this.getChildValue(node)}); + this.readChildNodes(node, obj); + }, + "WGS84BoundingBox": function(node, obj) { + var boundingBox = {}; + boundingBox.crs = node.getAttribute("crs"); + if (obj.BoundingBox) { + obj.BoundingBox.push(boundingBox); + } else { + obj.projection = boundingBox.crs; + boundingBox = obj; + } + this.readChildNodes(node, boundingBox); + }, + "BoundingBox": function(node, obj) { + // FIXME: We consider that BoundingBox is the same as WGS84BoundingBox + // LowerCorner = "min_x min_y" + // UpperCorner = "max_x max_y" + // It should normally depend on the projection + this.readers['ows']['WGS84BoundingBox'].apply(this, [node, obj]); + }, + "LowerCorner": function(node, obj) { + var str = this.getChildValue(node).replace( + this.regExes.trimSpace, ""); + str = str.replace(this.regExes.trimComma, ","); + var pointList = str.split(this.regExes.splitSpace); + obj.left = pointList[0]; + obj.bottom = pointList[1]; + }, + "UpperCorner": function(node, obj) { + var str = this.getChildValue(node).replace( + this.regExes.trimSpace, ""); + str = str.replace(this.regExes.trimComma, ","); + var pointList = str.split(this.regExes.splitSpace); + obj.right = pointList[0]; + obj.top = pointList[1]; + obj.bounds = new OpenLayers.Bounds(obj.left, obj.bottom, + obj.right, obj.top); + delete obj.left; + delete obj.bottom; + delete obj.right; + delete obj.top; + }, + "Language": function(node, obj) { + obj.language = this.getChildValue(node); + } + } + }, + + /** + * 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: { + "ows": { + "BoundingBox": function(options, nodeName) { + var node = this.createElementNSPlus(nodeName || "ows:BoundingBox", { + attributes: { + crs: options.projection + } + }); + this.writeNode("ows:LowerCorner", options, node); + this.writeNode("ows:UpperCorner", options, node); + return node; + }, + "LowerCorner": function(options) { + var node = this.createElementNSPlus("ows:LowerCorner", { + value: options.bounds.left + " " + options.bounds.bottom }); + return node; + }, + "UpperCorner": function(options) { + var node = this.createElementNSPlus("ows:UpperCorner", { + value: options.bounds.right + " " + options.bounds.top }); + return node; + }, + "Identifier": function(identifier) { + var node = this.createElementNSPlus("ows:Identifier", { + value: identifier }); + return node; + }, + "Title": function(title) { + var node = this.createElementNSPlus("ows:Title", { + value: title }); + return node; + }, + "Abstract": function(abstractValue) { + var node = this.createElementNSPlus("ows:Abstract", { + value: abstractValue }); + return node; + }, + "OutputFormat": function(format) { + var node = this.createElementNSPlus("ows:OutputFormat", { + value: format }); + return node; + } + } + }, + + CLASS_NAME: "OpenLayers.Format.OWSCommon.v1" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/OWSCommon/v1_0_0.js b/misc/openlayers/lib/OpenLayers/Format/OWSCommon/v1_0_0.js new file mode 100644 index 0000000..bc9852d --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/OWSCommon/v1_0_0.js @@ -0,0 +1,62 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/OWSCommon/v1.js + */ + +/** + * Class: OpenLayers.Format.OWSCommon.v1_0_0 + * Parser for OWS Common version 1.0.0. + * + * Inherits from: + * - <OpenLayers.Format.OWSCommon.v1> + */ +OpenLayers.Format.OWSCommon.v1_0_0 = OpenLayers.Class(OpenLayers.Format.OWSCommon.v1, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + ows: "http://www.opengis.net/ows", + xlink: "http://www.w3.org/1999/xlink" + }, + + /** + * 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: { + "ows": OpenLayers.Util.applyDefaults({ + "ExceptionReport": function(node, obj) { + obj.success = false; + obj.exceptionReport = { + version: node.getAttribute('version'), + language: node.getAttribute('language'), + exceptions: [] + }; + this.readChildNodes(node, obj.exceptionReport); + } + }, OpenLayers.Format.OWSCommon.v1.prototype.readers.ows) + }, + + /** + * 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: { + "ows": OpenLayers.Format.OWSCommon.v1.prototype.writers.ows + }, + + CLASS_NAME: "OpenLayers.Format.OWSCommon.v1_0_0" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/OWSCommon/v1_1_0.js b/misc/openlayers/lib/OpenLayers/Format/OWSCommon/v1_1_0.js new file mode 100644 index 0000000..9da216c --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/OWSCommon/v1_1_0.js @@ -0,0 +1,116 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/OWSCommon/v1.js + */ + +/** + * Class: OpenLayers.Format.OWSCommon.v1_1_0 + * Parser for OWS Common version 1.1.0. + * + * Inherits from: + * - <OpenLayers.Format.OWSCommon.v1> + */ +OpenLayers.Format.OWSCommon.v1_1_0 = OpenLayers.Class(OpenLayers.Format.OWSCommon.v1, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + ows: "http://www.opengis.net/ows/1.1", + xlink: "http://www.w3.org/1999/xlink" + }, + + /** + * 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: { + "ows": OpenLayers.Util.applyDefaults({ + "ExceptionReport": function(node, obj) { + obj.exceptionReport = { + version: node.getAttribute('version'), + language: node.getAttribute('xml:lang'), + exceptions: [] + }; + this.readChildNodes(node, obj.exceptionReport); + }, + "AllowedValues": function(node, parameter) { + parameter.allowedValues = {}; + this.readChildNodes(node, parameter.allowedValues); + }, + "AnyValue": function(node, parameter) { + parameter.anyValue = true; + }, + "DataType": function(node, parameter) { + parameter.dataType = this.getChildValue(node); + }, + "Range": function(node, allowedValues) { + allowedValues.range = {}; + this.readChildNodes(node, allowedValues.range); + }, + "MinimumValue": function(node, range) { + range.minValue = this.getChildValue(node); + }, + "MaximumValue": function(node, range) { + range.maxValue = this.getChildValue(node); + }, + "Identifier": function(node, obj) { + obj.identifier = this.getChildValue(node); + }, + "SupportedCRS": function(node, obj) { + obj.supportedCRS = this.getChildValue(node); + } + }, OpenLayers.Format.OWSCommon.v1.prototype.readers["ows"]) + }, + + /** + * 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: { + "ows": OpenLayers.Util.applyDefaults({ + "Range": function(range) { + var node = this.createElementNSPlus("ows:Range", { + attributes: { + 'ows:rangeClosure': range.closure + } + }); + this.writeNode("ows:MinimumValue", range.minValue, node); + this.writeNode("ows:MaximumValue", range.maxValue, node); + return node; + }, + "MinimumValue": function(minValue) { + var node = this.createElementNSPlus("ows:MinimumValue", { + value: minValue + }); + return node; + }, + "MaximumValue": function(maxValue) { + var node = this.createElementNSPlus("ows:MaximumValue", { + value: maxValue + }); + return node; + }, + "Value": function(value) { + var node = this.createElementNSPlus("ows:Value", { + value: value + }); + return node; + } + }, OpenLayers.Format.OWSCommon.v1.prototype.writers["ows"]) + }, + + CLASS_NAME: "OpenLayers.Format.OWSCommon.v1_1_0" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/OWSContext.js b/misc/openlayers/lib/OpenLayers/Format/OWSContext.js new file mode 100644 index 0000000..ab38734 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/OWSContext.js @@ -0,0 +1,86 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/Context.js + */ + +/** + * Class: OpenLayers.Format.OWSContext + * Read and write OWS Context documents. OWS Context documents are a + * preliminary OGC (Open Geospatial Consortium) standard for storing the + * state of a web mapping application. In a way it is the successor to + * Web Map Context (WMC), since it is more generic and more types of layers + * can be stored. Also, nesting of layers is supported since version 0.3.1. + * For more information see: http://www.ogcnetwork.net/context + * + * Inherits from: + * - <OpenLayers.Format.Context> + */ +OpenLayers.Format.OWSContext = OpenLayers.Class(OpenLayers.Format.Context,{ + + /** + * APIProperty: defaultVersion + * {String} Version number to assume if none found. Default is "0.3.1". + */ + defaultVersion: "0.3.1", + + /** + * Constructor: OpenLayers.Format.OWSContext + * Create a new parser for OWS Context documents. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * Method: getVersion + * Returns the version to use. Subclasses can override this function + * if a different version detection is needed. + * + * Parameters: + * root - {DOMElement} + * options - {Object} Optional configuration object. + * + * Returns: + * {String} The version to use. + */ + getVersion: function(root, options) { + var version = OpenLayers.Format.XML.VersionedOGC.prototype.getVersion.apply( + this, arguments); + // 0.3.1 is backwards compatible with 0.3.0 + if (version === "0.3.0") { + version = this.defaultVersion; + } + return version; + }, + + /** + * Method: toContext + * Create a context object free from layer given a map or a + * context object. + * + * Parameters: + * obj - {<OpenLayers.Map> | Object} The map or context. + * + * Returns: + * {Object} A context object. + */ + toContext: function(obj) { + var context = {}; + if(obj.CLASS_NAME == "OpenLayers.Map") { + context.bounds = obj.getExtent(); + context.maxExtent = obj.maxExtent; + context.projection = obj.projection; + context.size = obj.getSize(); + context.layers = obj.layers; + } + return context; + }, + + CLASS_NAME: "OpenLayers.Format.OWSContext" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/OWSContext/v0_3_1.js b/misc/openlayers/lib/OpenLayers/Format/OWSContext/v0_3_1.js new file mode 100644 index 0000000..d6487e8 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/OWSContext/v0_3_1.js @@ -0,0 +1,595 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Format/KML.js + * @requires OpenLayers/Format/GML.js + * @requires OpenLayers/Format/GML/v2.js + * @requires OpenLayers/Format/SLD/v1_0_0.js + * @requires OpenLayers/Format/OWSContext.js + * @requires OpenLayers/Format/OWSCommon/v1_0_0.js + */ + +/** + * Class: OpenLayers.Format.OWSContext.v0_3_1 + * Read and write OWSContext version 0.3.1. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.OWSContext.v0_3_1 = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + owc: "http://www.opengis.net/ows-context", + gml: "http://www.opengis.net/gml", + kml: "http://www.opengis.net/kml/2.2", + ogc: "http://www.opengis.net/ogc", + ows: "http://www.opengis.net/ows", + sld: "http://www.opengis.net/sld", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance" + }, + + /** + * Constant: VERSION + * {String} 0.3.1 + */ + VERSION: "0.3.1", + + /** + * Property: schemaLocation + * {String} Schema location + */ + schemaLocation: "http://www.opengis.net/ows-context http://www.ogcnetwork.net/schemas/owc/0.3.1/owsContext.xsd", + + /** + * Property: defaultPrefix + * {String} Default namespace prefix to use. + */ + defaultPrefix: "owc", + + /** + * APIProperty: extractAttributes + * {Boolean} Extract attributes from GML. Default is true. + */ + extractAttributes: true, + + /** + * APIProperty: xy + * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x) + * Changing is not recommended, a new Format should be instantiated. + */ + xy: true, + + /** + * Property: regExes + * Compiled regular expressions for manipulating strings. + */ + regExes: { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g) + }, + + /** + * Property: featureNS + * {String} The namespace uri to use for writing InlineGeometry + */ + featureNS: "http://mapserver.gis.umn.edu/mapserver", + + /** + * Property: featureType + * {String} The name to use as the feature type when writing out + * InlineGeometry + */ + featureType: 'vector', + + /** + * Property: geometryName + * {String} The name to use for the geometry attribute when writing out + * InlineGeometry + */ + geometryName: 'geometry', + + /** + * Property: nestingLayerLookup + * {Object} Hashtable lookup for nesting layer nodes. Used while writing + * the OWS context document. It is necessary to keep track of the + * nestingPaths for which nesting layer nodes have already been + * created, so (nesting) layer nodes are added to those nodes. + * + * For example: + * + * If there are three layers with nestingPaths: + * layer1.metadata.nestingPath = "a/b/" + * layer2.metadata.nestingPath = "a/b/" + * layer2.metadata.nestingPath = "a/c" + * + * then a nesting layer node "a" should be created once and added + * to the resource list, a nesting layer node "b" should be created + * once and added under "a", and a nesting layer node "c" should be + * created and added under "a". The lookup paths for these nodes + * will be "a", "a/b", and "a/c" respectively. + */ + nestingLayerLookup: null, + + /** + * Constructor: OpenLayers.Format.OWSContext.v0_3_1 + * Instances of this class are not created directly. Use the + * <OpenLayers.Format.OWSContext> 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]); + OpenLayers.Format.GML.v2.prototype.setGeometryTypes.call(this); + }, + + /** + * Method: setNestingPath + * Set the nestingPath property of the layer depending on the position + * of the layer in hierarchy of layers. + * + * Parameters: + * l - {Object} An object that may have a layersContext array property. + * + */ + setNestingPath : function(l){ + if(l.layersContext){ + for (var i = 0, len = l.layersContext.length; i < len; i++) { + var layerContext = l.layersContext[i]; + var nPath = []; + var nTitle = l.title || ""; + if(l.metadata && l.metadata.nestingPath){ + nPath = l.metadata.nestingPath.slice(); + } + if (nTitle != "") { + nPath.push(nTitle); + } + layerContext.metadata.nestingPath = nPath; + if(layerContext.layersContext){ + this.setNestingPath(layerContext); + } + } + } + }, + + /** + * Function: decomposeNestingPath + * Takes a nestingPath like "a/b/c" and decomposes it into subpaths: + * "a", "a/b", "a/b/c" + * + * Parameters: + * nPath - {Array} the nesting path + * + * Returns: + * Array({String}) Array with subpaths, or empty array if there is nothing + * to decompose + */ + decomposeNestingPath: function(nPath){ + var a = []; + if (OpenLayers.Util.isArray(nPath)) { + var path = nPath.slice(); + while (path.length > 0) { + a.push(path.slice()); + path.pop(); + } + a.reverse(); + } + return a; + }, + + /** + * APIMethod: read + * Read OWS context data from a string or DOMElement, and return a list + * of layers. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Object} The context object with a flat layer list as a property named + * layersContext. + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + if(data && data.nodeType == 9) { + data = data.documentElement; + } + var context = {}; + this.readNode(data, context); + // since an OWSContext can be nested we need to go through this + // structure recursively + this.setNestingPath({layersContext : context.layersContext}); + // after nesting path has been set, create a flat list of layers + var layers = []; + this.processLayer(layers, context); + delete context.layersContext; + context.layersContext = layers; + return context; + }, + + /** + * Method: processLayer + * Recursive function to get back a flat list of layers from the hierarchic + * layer structure. + * + * Parameters: + * layerArray - {Array({Object})} Array of layerContext objects + * layer - {Object} layerContext object + */ + processLayer: function(layerArray, layer) { + if (layer.layersContext) { + for (var i=0, len = layer.layersContext.length; i<len; i++) { + var l = layer.layersContext[i]; + layerArray.push(l); + if (l.layersContext) { + this.processLayer(layerArray, l); + } + } + } + }, + + /** + * APIMethod: write + * + * Parameters: + * context - {Object} An object representing the map context. + * options - {Object} Optional object. + * + * Returns: + * {String} An OWS Context document string. + */ + write: function(context, options) { + var name = "OWSContext"; + this.nestingLayerLookup = {}; //start with empty lookup + options = options || {}; + OpenLayers.Util.applyDefaults(options, context); + var root = this.writeNode(name, options); + this.nestingLayerLookup = null; //clear lookup + this.setAttributeNS( + root, this.namespaces["xsi"], + "xsi:schemaLocation", this.schemaLocation + ); + return OpenLayers.Format.XML.prototype.write.apply(this, [root]); + }, + + /** + * 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: { + "kml": { + "Document": function(node, obj) { + obj.features = new OpenLayers.Format.KML( + {kmlns: this.namespaces.kml, + extractStyles: true}).read(node); + } + }, + "owc": { + "OWSContext": function(node, obj) { + this.readChildNodes(node, obj); + }, + "General": function(node, obj) { + this.readChildNodes(node, obj); + }, + "ResourceList": function(node, obj) { + this.readChildNodes(node, obj); + }, + "Layer": function(node, obj) { + var layerContext = { + metadata: {}, + visibility: (node.getAttribute("hidden") != "1"), + queryable: (node.getAttribute("queryable") == "1"), + opacity: ((node.getAttribute("opacity") != null) ? + parseFloat(node.getAttribute("opacity")) : null), + name: node.getAttribute("name"), + /* A category layer is a dummy layer meant for creating + hierarchies. It is not a physical layer in the + OpenLayers sense. The assumption we make here is that + category layers do not have a name attribute */ + categoryLayer: (node.getAttribute("name") == null), + formats: [], + styles: [] + }; + if (!obj.layersContext) { + obj.layersContext = []; + } + obj.layersContext.push(layerContext); + this.readChildNodes(node, layerContext); + }, + "InlineGeometry": function(node, obj) { + obj.features = []; + var elements = this.getElementsByTagNameNS(node, + this.namespaces.gml, "featureMember"); + var el; + if (elements.length >= 1) { + el = elements[0]; + } + if (el && el.firstChild) { + var featurenode = (el.firstChild.nextSibling) ? + el.firstChild.nextSibling : el.firstChild; + this.setNamespace("feature", featurenode.namespaceURI); + this.featureType = featurenode.localName || + featurenode.nodeName.split(":").pop(); + this.readChildNodes(node, obj); + } + }, + "Server": function(node, obj) { + // when having multiple Server types, we prefer WMS + if ((!obj.service && !obj.version) || + (obj.service != + OpenLayers.Format.Context.serviceTypes.WMS)) { + obj.service = node.getAttribute("service"); + obj.version = node.getAttribute("version"); + this.readChildNodes(node, obj); + } + }, + "Name": function(node, obj) { + obj.name = this.getChildValue(node); + this.readChildNodes(node, obj); + }, + "Title": function(node, obj) { + obj.title = this.getChildValue(node); + this.readChildNodes(node, obj); + }, + "StyleList": function(node, obj) { + this.readChildNodes(node, obj.styles); + }, + "Style": function(node, obj) { + var style = {}; + obj.push(style); + this.readChildNodes(node, style); + }, + "LegendURL": function(node, obj) { + var legend = {}; + obj.legend = legend; + this.readChildNodes(node, legend); + }, + "OnlineResource": function(node, obj) { + obj.url = this.getAttributeNS(node, this.namespaces.xlink, + "href"); + this.readChildNodes(node, obj); + } + }, + "ows": OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers.ows, + "gml": OpenLayers.Format.GML.v2.prototype.readers.gml, + "sld": OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld, + "feature": OpenLayers.Format.GML.v2.prototype.readers.feature + }, + + /** + * 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: { + "owc": { + "OWSContext": function(options) { + var node = this.createElementNSPlus("OWSContext", { + attributes: { + version: this.VERSION, + id: options.id || OpenLayers.Util.createUniqueID("OpenLayers_OWSContext_") + } + }); + this.writeNode("General", options, node); + this.writeNode("ResourceList", options, node); + return node; + }, + "General": function(options) { + var node = this.createElementNSPlus("General"); + this.writeNode("ows:BoundingBox", options, node); + this.writeNode("ows:Title", options.title || 'OpenLayers OWSContext', node); + return node; + }, + "ResourceList": function(options) { + var node = this.createElementNSPlus("ResourceList"); + for (var i=0, len=options.layers.length; i<len; i++) { + var layer = options.layers[i]; + var decomposedPath = this.decomposeNestingPath(layer.metadata.nestingPath); + this.writeNode("_Layer", {layer: layer, subPaths: decomposedPath}, node); + } + return node; + }, + "Server": function(options) { + var node = this.createElementNSPlus("Server", {attributes: { + version: options.version, + service: options.service } + }); + this.writeNode("OnlineResource", options, node); + return node; + }, + "OnlineResource": function(options) { + var node = this.createElementNSPlus("OnlineResource", {attributes: { + "xlink:href": options.url } + }); + return node; + }, + "InlineGeometry": function(layer) { + var node = this.createElementNSPlus("InlineGeometry"), + dataExtent = layer.getDataExtent(); + if (dataExtent !== null) { + this.writeNode("gml:boundedBy", dataExtent, node); + } + for (var i=0, len=layer.features.length; i<len; i++) { + this.writeNode("gml:featureMember", layer.features[i], node); + } + return node; + }, + "StyleList": function(styles) { + var node = this.createElementNSPlus("StyleList"); + for (var i=0, len=styles.length; i<len; i++) { + this.writeNode("Style", styles[i], node); + } + return node; + }, + "Style": function(style) { + var node = this.createElementNSPlus("Style"); + this.writeNode("Name", style, node); + this.writeNode("Title", style, node); + if (style.legend) { + this.writeNode("LegendURL", style, node); + } + return node; + }, + "Name": function(obj) { + var node = this.createElementNSPlus("Name", { + value: obj.name }); + return node; + }, + "Title": function(obj) { + var node = this.createElementNSPlus("Title", { + value: obj.title }); + return node; + }, + "LegendURL": function(style) { + var node = this.createElementNSPlus("LegendURL"); + this.writeNode("OnlineResource", style.legend, node); + return node; + }, + "_WMS": function(layer) { + var node = this.createElementNSPlus("Layer", {attributes: { + name: layer.params.LAYERS, + queryable: layer.queryable ? "1" : "0", + hidden: layer.visibility ? "0" : "1", + opacity: layer.hasOwnProperty("opacity") ? layer.opacity : null} + }); + this.writeNode("ows:Title", layer.name, node); + this.writeNode("ows:OutputFormat", layer.params.FORMAT, node); + this.writeNode("Server", {service: + OpenLayers.Format.Context.serviceTypes.WMS, + version: layer.params.VERSION, url: layer.url}, node); + if (layer.metadata.styles && layer.metadata.styles.length > 0) { + this.writeNode("StyleList", layer.metadata.styles, node); + } + return node; + }, + "_Layer": function(options) { + var layer, subPaths, node, title; + layer = options.layer; + subPaths = options.subPaths; + node = null; + title = null; + // subPaths is an array of an array + // recursively calling _Layer writer eats up subPaths, until a + // real writer is called and nodes are returned. + if(subPaths.length > 0){ + var path = subPaths[0].join("/"); + var index = path.lastIndexOf("/"); + node = this.nestingLayerLookup[path]; + title = (index > 0)?path.substring(index + 1, path.length):path; + if(!node){ + // category layer + node = this.createElementNSPlus("Layer"); + this.writeNode("ows:Title", title, node); + this.nestingLayerLookup[path] = node; + } + options.subPaths.shift();//remove a path after each call + this.writeNode("_Layer", options, node); + return node; + } else { + // write out the actual layer + if (layer instanceof OpenLayers.Layer.WMS) { + node = this.writeNode("_WMS", layer); + } else if (layer instanceof OpenLayers.Layer.Vector) { + if (layer.protocol instanceof OpenLayers.Protocol.WFS.v1) { + node = this.writeNode("_WFS", layer); + } else if (layer.protocol instanceof OpenLayers.Protocol.HTTP) { + if (layer.protocol.format instanceof OpenLayers.Format.GML) { + layer.protocol.format.version = "2.1.2"; + node = this.writeNode("_GML", layer); + } else if (layer.protocol.format instanceof OpenLayers.Format.KML) { + layer.protocol.format.version = "2.2"; + node = this.writeNode("_KML", layer); + } + } else { + // write out as inline GML since we have no idea + // about the original Format + this.setNamespace("feature", this.featureNS); + node = this.writeNode("_InlineGeometry", layer); + } + } + if (layer.options.maxScale) { + this.writeNode("sld:MinScaleDenominator", + layer.options.maxScale, node); + } + if (layer.options.minScale) { + this.writeNode("sld:MaxScaleDenominator", + layer.options.minScale, node); + } + this.nestingLayerLookup[layer.name] = node; + return node; + } + }, + "_WFS": function(layer) { + var node = this.createElementNSPlus("Layer", {attributes: { + name: layer.protocol.featurePrefix + ":" + layer.protocol.featureType, + hidden: layer.visibility ? "0" : "1" } + }); + this.writeNode("ows:Title", layer.name, node); + this.writeNode("Server", {service: + OpenLayers.Format.Context.serviceTypes.WFS, + version: layer.protocol.version, + url: layer.protocol.url}, node); + return node; + }, + "_InlineGeometry": function(layer) { + var node = this.createElementNSPlus("Layer", {attributes: { + name: this.featureType, + hidden: layer.visibility ? "0" : "1" } + }); + this.writeNode("ows:Title", layer.name, node); + this.writeNode("InlineGeometry", layer, node); + return node; + }, + "_GML": function(layer) { + var node = this.createElementNSPlus("Layer"); + this.writeNode("ows:Title", layer.name, node); + this.writeNode("Server", {service: + OpenLayers.Format.Context.serviceTypes.GML, + url: layer.protocol.url, version: + layer.protocol.format.version}, node); + return node; + }, + "_KML": function(layer) { + var node = this.createElementNSPlus("Layer"); + this.writeNode("ows:Title", layer.name, node); + this.writeNode("Server", {service: + OpenLayers.Format.Context.serviceTypes.KML, + version: layer.protocol.format.version, url: + layer.protocol.url}, node); + return node; + } + }, + "gml": OpenLayers.Util.applyDefaults({ + "boundedBy": function(bounds) { + var node = this.createElementNSPlus("gml:boundedBy"); + this.writeNode("gml:Box", bounds, node); + return node; + } + }, OpenLayers.Format.GML.v2.prototype.writers.gml), + "ows": OpenLayers.Format.OWSCommon.v1_0_0.prototype.writers.ows, + "sld": OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld, + "feature": OpenLayers.Format.GML.v2.prototype.writers.feature + }, + + CLASS_NAME: "OpenLayers.Format.OWSContext.v0_3_1" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/QueryStringFilter.js b/misc/openlayers/lib/OpenLayers/Format/QueryStringFilter.js new file mode 100644 index 0000000..e33f722 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/QueryStringFilter.js @@ -0,0 +1,183 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Console.js + * @requires OpenLayers/Format.js + * @requires OpenLayers/Filter/Spatial.js + * @requires OpenLayers/Filter/Comparison.js + * @requires OpenLayers/Filter/Logical.js + */ + +/** + * Class: OpenLayers.Format.QueryStringFilter + * Parser for reading a query string and creating a simple filter. + * + * Inherits from: + * - <OpenLayers.Format> + */ +OpenLayers.Format.QueryStringFilter = (function() { + + /** + * Map the OpenLayers.Filter.Comparison types to the operation strings of + * the protocol. + */ + var cmpToStr = {}; + cmpToStr[OpenLayers.Filter.Comparison.EQUAL_TO] = "eq"; + cmpToStr[OpenLayers.Filter.Comparison.NOT_EQUAL_TO] = "ne"; + cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN] = "lt"; + cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO] = "lte"; + cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN] = "gt"; + cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO] = "gte"; + cmpToStr[OpenLayers.Filter.Comparison.LIKE] = "ilike"; + + /** + * Function: regex2value + * Convert the value from a regular expression string to a LIKE/ILIKE + * string known to the web service. + * + * Parameters: + * value - {String} The regex string. + * + * Returns: + * {String} The converted string. + */ + function regex2value(value) { + + // highly sensitive!! Do not change this without running the + // Protocol/HTTP.html unit tests + + // convert % to \% + value = value.replace(/%/g, "\\%"); + + // convert \\. to \\_ (\\.* occurences converted later) + value = value.replace(/\\\\\.(\*)?/g, function($0, $1) { + return $1 ? $0 : "\\\\_"; + }); + + // convert \\.* to \\% + value = value.replace(/\\\\\.\*/g, "\\\\%"); + + // convert . to _ (\. and .* occurences converted later) + value = value.replace(/(\\)?\.(\*)?/g, function($0, $1, $2) { + return $1 || $2 ? $0 : "_"; + }); + + // convert .* to % (\.* occurnces converted later) + value = value.replace(/(\\)?\.\*/g, function($0, $1) { + return $1 ? $0 : "%"; + }); + + // convert \. to . + value = value.replace(/\\\./g, "."); + + // replace \* with * (watching out for \\*) + value = value.replace(/(\\)?\\\*/g, function($0, $1) { + return $1 ? $0 : "*"; + }); + + return value; + } + + return OpenLayers.Class(OpenLayers.Format, { + + /** + * Property: wildcarded. + * {Boolean} If true percent signs are added around values + * read from LIKE filters, for example if the protocol + * read method is passed a LIKE filter whose property + * is "foo" and whose value is "bar" the string + * "foo__ilike=%bar%" will be sent in the query string; + * defaults to false. + */ + wildcarded: false, + + /** + * APIProperty: srsInBBOX + * {Boolean} Include the SRS identifier in BBOX query string parameter. + * Default is false. If true and the layer has a projection object set, + * any BBOX filter will be serialized with a fifth item identifying the + * projection. E.g. bbox=-1000,-1000,1000,1000,EPSG:900913 + */ + srsInBBOX: false, + + /** + * APIMethod: write + * Serialize an <OpenLayers.Filter> objects using the "simple" filter syntax for + * query string parameters. This function must be called as a method of + * a protocol instance. + * + * Parameters: + * filter - {<OpenLayers.Filter>} filter to convert. + * params - {Object} The parameters object. + * + * Returns: + * {Object} The resulting parameters object. + */ + write: function(filter, params) { + params = params || {}; + var className = filter.CLASS_NAME; + var filterType = className.substring(className.lastIndexOf(".") + 1); + switch (filterType) { + case "Spatial": + switch (filter.type) { + case OpenLayers.Filter.Spatial.BBOX: + params.bbox = filter.value.toArray(); + if (this.srsInBBOX && filter.projection) { + params.bbox.push(filter.projection.getCode()); + } + break; + case OpenLayers.Filter.Spatial.DWITHIN: + params.tolerance = filter.distance; + // no break here + case OpenLayers.Filter.Spatial.WITHIN: + params.lon = filter.value.x; + params.lat = filter.value.y; + break; + default: + OpenLayers.Console.warn( + "Unknown spatial filter type " + filter.type); + } + break; + case "Comparison": + var op = cmpToStr[filter.type]; + if (op !== undefined) { + var value = filter.value; + if (filter.type == OpenLayers.Filter.Comparison.LIKE) { + value = regex2value(value); + if (this.wildcarded) { + value = "%" + value + "%"; + } + } + params[filter.property + "__" + op] = value; + params.queryable = params.queryable || []; + params.queryable.push(filter.property); + } else { + OpenLayers.Console.warn( + "Unknown comparison filter type " + filter.type); + } + break; + case "Logical": + if (filter.type === OpenLayers.Filter.Logical.AND) { + for (var i=0,len=filter.filters.length; i<len; i++) { + params = this.write(filter.filters[i], params); + } + } else { + OpenLayers.Console.warn( + "Unsupported logical filter type " + filter.type); + } + break; + default: + OpenLayers.Console.warn("Unknown filter type " + filterType); + } + return params; + }, + + CLASS_NAME: "OpenLayers.Format.QueryStringFilter" + + }); + + +})(); diff --git a/misc/openlayers/lib/OpenLayers/Format/SLD.js b/misc/openlayers/lib/OpenLayers/Format/SLD.js new file mode 100644 index 0000000..56e59d0 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/SLD.js @@ -0,0 +1,81 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML/VersionedOGC.js + * @requires OpenLayers/Style.js + * @requires OpenLayers/Rule.js + * @requires OpenLayers/Filter/FeatureId.js + * @requires OpenLayers/Filter/Logical.js + * @requires OpenLayers/Filter/Comparison.js + * @requires OpenLayers/Filter/Spatial.js + */ + +/** + * Class: OpenLayers.Format.SLD + * Read/Write SLD. Create a new instance with the <OpenLayers.Format.SLD> + * constructor. + * + * Inherits from: + * - <OpenLayers.Format.XML.VersionedOGC> + */ +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". + */ + defaultVersion: "1.0.0", + + /** + * APIProperty: stringifyOutput + * {Boolean} If true, write will return a string otherwise a DOMElement. + * Default is true. + */ + stringifyOutput: true, + + /** + * APIProperty: namedLayersAsArray + * {Boolean} Generate a namedLayers array. If false, the namedLayers + * property value will be an object keyed by layer name. Default is + * false. + */ + namedLayersAsArray: false, + + /** + * APIMethod: write + * Write a SLD document given a list of styles. + * + * Parameters: + * sld - {Object} An object representing the SLD. + * options - {Object} Optional configuration object. + * + * Returns: + * {String} An SLD document string. + */ + + /** + * APIMethod: read + * Read and SLD doc and return an object representing the SLD. + * + * Parameters: + * data - {String | DOMElement} Data to read. + * options - {Object} Options for the reader. + * + * Returns: + * {Object} An object representing the SLD. + */ + + CLASS_NAME: "OpenLayers.Format.SLD" +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/SLD/v1.js b/misc/openlayers/lib/OpenLayers/Format/SLD/v1.js new file mode 100644 index 0000000..c43bac4 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/SLD/v1.js @@ -0,0 +1,1309 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Rule.js + * @requires OpenLayers/Format/SLD.js + * @requires OpenLayers/Format/Filter/v1_0_0.js + * @requires OpenLayers/Symbolizer/Point.js + * @requires OpenLayers/Symbolizer/Line.js + * @requires OpenLayers/Symbolizer/Polygon.js + * @requires OpenLayers/Symbolizer/Text.js + * @requires OpenLayers/Symbolizer/Raster.js + */ + +/** + * Class: OpenLayers.Format.SLD.v1 + * Superclass for SLD version 1 parsers. + * + * Inherits from: + * - <OpenLayers.Format.Filter.v1_0_0> + */ +OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + sld: "http://www.opengis.net/sld", + ogc: "http://www.opengis.net/ogc", + gml: "http://www.opengis.net/gml", + 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: multipleSymbolizers + * {Boolean} Support multiple symbolizers per rule. Default is false. if + * true, an OpenLayers.Style2 instance will be created to represent + * user styles instead of an OpenLayers.Style instace. The + * OpenLayers.Style2 class allows collections of rules with multiple + * symbolizers, but is not currently useful for client side rendering. + * If multiple symbolizers is true, multiple FeatureTypeStyle elements + * are preserved in reading/writing by setting symbolizer zIndex values. + * In addition, the <defaultSymbolizer> property is ignored if + * multiple symbolizers are supported (defaults should be applied + * when rendering). + */ + multipleSymbolizers: false, + + /** + * Property: featureTypeCounter + * {Number} Private counter for multiple feature type styles. + */ + featureTypeCounter: null, + + /** + * APIProperty: defaultSymbolizer. + * {Object} A symbolizer with the SLD defaults. + */ + defaultSymbolizer: { + fillColor: "#808080", + fillOpacity: 1, + strokeColor: "#000000", + strokeOpacity: 1, + strokeWidth: 1, + strokeDashstyle: "solid", + pointRadius: 3, + graphicName: "square" + }, + + /** + * Constructor: OpenLayers.Format.SLD.v1 + * Instances of this class are not created directly. Use the + * <OpenLayers.Format.SLD> constructor instead. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * Method: read + * + * Parameters: + * data - {DOMElement} An SLD document element. + * options - {Object} Options for the reader. + * + * Valid options: + * namedLayersAsArray - {Boolean} Generate a namedLayers array. If false, + * the namedLayers property value will be an object keyed by layer name. + * Default is false. + * + * Returns: + * {Object} An object representing the SLD. + */ + read: function(data, options) { + options = OpenLayers.Util.applyDefaults(options, this.options); + var sld = { + namedLayers: options.namedLayersAsArray === true ? [] : {} + }; + 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: OpenLayers.Util.applyDefaults({ + "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, len=layer.userStyles.length; i<len; ++i) { + layer.userStyles[i].layerName = layer.name; + } + if(OpenLayers.Util.isArray(sld.namedLayers)) { + sld.namedLayers.push(layer); + } else { + sld.namedLayers[layer.name] = layer; + } + }, + "NamedStyle": function(node, layer) { + layer.namedStyles.push( + this.getChildName(node.firstChild) + ); + }, + "UserStyle": function(node, layer) { + var obj = {defaultsPerSymbolizer: true, rules: []}; + this.featureTypeCounter = -1; + this.readChildNodes(node, obj); + var style; + if (this.multipleSymbolizers) { + delete obj.defaultsPerSymbolizer; + style = new OpenLayers.Style2(obj); + } else { + style = new OpenLayers.Style(this.defaultSymbolizer, obj); + } + layer.userStyles.push(style); + }, + "IsDefault": function(node, style) { + if(this.getChildValue(node) == "1") { + style.isDefault = true; + } + }, + "FeatureTypeStyle": function(node, style) { + ++this.featureTypeCounter; + var obj = { + rules: this.multipleSymbolizers ? style.rules : [] + }; + this.readChildNodes(node, obj); + if (!this.multipleSymbolizers) { + style.rules = obj.rules; + } + }, + "Rule": function(node, obj) { + var config; + if (this.multipleSymbolizers) { + config = {symbolizers: []}; + } + var rule = new OpenLayers.Rule(config); + this.readChildNodes(node, rule); + obj.rules.push(rule); + }, + "ElseFilter": function(node, rule) { + rule.elseFilter = true; + }, + "MinScaleDenominator": function(node, rule) { + rule.minScaleDenominator = parseFloat(this.getChildValue(node)); + }, + "MaxScaleDenominator": function(node, rule) { + rule.maxScaleDenominator = parseFloat(this.getChildValue(node)); + }, + "TextSymbolizer": function(node, rule) { + var config = {}; + this.readChildNodes(node, config); + if (this.multipleSymbolizers) { + config.zIndex = this.featureTypeCounter; + rule.symbolizers.push( + new OpenLayers.Symbolizer.Text(config) + ); + } else { + rule.symbolizer["Text"] = OpenLayers.Util.applyDefaults( + config, rule.symbolizer["Text"] + ); + } + }, + "LabelPlacement": function(node, symbolizer) { + this.readChildNodes(node, symbolizer); + }, + "PointPlacement": function(node, symbolizer) { + var config = {}; + this.readChildNodes(node, config); + config.labelRotation = config.rotation; + delete config.rotation; + var labelAlign, + x = symbolizer.labelAnchorPointX, + y = symbolizer.labelAnchorPointY; + if (x <= 1/3) { + labelAlign = 'l'; + } else if (x > 1/3 && x < 2/3) { + labelAlign = 'c'; + } else if (x >= 2/3) { + labelAlign = 'r'; + } + if (y <= 1/3) { + labelAlign += 'b'; + } else if (y > 1/3 && y < 2/3) { + labelAlign += 'm'; + } else if (y >= 2/3) { + labelAlign += 't'; + } + config.labelAlign = labelAlign; + OpenLayers.Util.applyDefaults(symbolizer, config); + }, + "AnchorPoint": function(node, symbolizer) { + this.readChildNodes(node, symbolizer); + }, + "AnchorPointX": function(node, symbolizer) { + var labelAnchorPointX = this.readers.ogc._expression.call(this, node); + // always string, could be empty string + if(labelAnchorPointX) { + symbolizer.labelAnchorPointX = labelAnchorPointX; + } + }, + "AnchorPointY": function(node, symbolizer) { + var labelAnchorPointY = this.readers.ogc._expression.call(this, node); + // always string, could be empty string + if(labelAnchorPointY) { + symbolizer.labelAnchorPointY = labelAnchorPointY; + } + }, + "Displacement": function(node, symbolizer) { + this.readChildNodes(node, symbolizer); + }, + "DisplacementX": function(node, symbolizer) { + var labelXOffset = this.readers.ogc._expression.call(this, node); + // always string, could be empty string + if(labelXOffset) { + symbolizer.labelXOffset = labelXOffset; + } + }, + "DisplacementY": function(node, symbolizer) { + var labelYOffset = this.readers.ogc._expression.call(this, node); + // always string, could be empty string + if(labelYOffset) { + symbolizer.labelYOffset = labelYOffset; + } + }, + "LinePlacement": function(node, symbolizer) { + this.readChildNodes(node, symbolizer); + }, + "PerpendicularOffset": function(node, symbolizer) { + var labelPerpendicularOffset = this.readers.ogc._expression.call(this, node); + // always string, could be empty string + if(labelPerpendicularOffset) { + symbolizer.labelPerpendicularOffset = labelPerpendicularOffset; + } + }, + "Label": function(node, symbolizer) { + var value = this.readers.ogc._expression.call(this, node); + if (value) { + symbolizer.label = value; + } + }, + "Font": function(node, symbolizer) { + this.readChildNodes(node, symbolizer); + }, + "Halo": function(node, symbolizer) { + // halo has a fill, so send fresh object + var obj = {}; + this.readChildNodes(node, obj); + symbolizer.haloRadius = obj.haloRadius; + symbolizer.haloColor = obj.fillColor; + symbolizer.haloOpacity = obj.fillOpacity; + }, + "Radius": function(node, symbolizer) { + var radius = this.readers.ogc._expression.call(this, node); + if(radius != null) { + // radius is only used for halo + symbolizer.haloRadius = radius; + } + }, + "RasterSymbolizer": function(node, rule) { + var config = {}; + this.readChildNodes(node, config); + if (this.multipleSymbolizers) { + config.zIndex = this.featureTypeCounter; + rule.symbolizers.push( + new OpenLayers.Symbolizer.Raster(config) + ); + } else { + rule.symbolizer["Raster"] = OpenLayers.Util.applyDefaults( + config, rule.symbolizer["Raster"] + ); + } + }, + "Geometry": function(node, obj) { + obj.geometry = {}; + this.readChildNodes(node, obj.geometry); + }, + "ColorMap": function(node, symbolizer) { + symbolizer.colorMap = []; + this.readChildNodes(node, symbolizer.colorMap); + }, + "ColorMapEntry": function(node, colorMap) { + var q = node.getAttribute("quantity"); + var o = node.getAttribute("opacity"); + colorMap.push({ + color: node.getAttribute("color"), + quantity: q !== null ? parseFloat(q) : undefined, + label: node.getAttribute("label") || undefined, + opacity: o !== null ? parseFloat(o) : undefined + }); + }, + "LineSymbolizer": function(node, rule) { + var config = {}; + this.readChildNodes(node, config); + if (this.multipleSymbolizers) { + config.zIndex = this.featureTypeCounter; + rule.symbolizers.push( + new OpenLayers.Symbolizer.Line(config) + ); + } else { + rule.symbolizer["Line"] = OpenLayers.Util.applyDefaults( + config, rule.symbolizer["Line"] + ); + } + }, + "PolygonSymbolizer": function(node, rule) { + var config = { + fill: false, + stroke: false + }; + if (!this.multipleSymbolizers) { + config = rule.symbolizer["Polygon"] || config; + } + this.readChildNodes(node, config); + if (this.multipleSymbolizers) { + config.zIndex = this.featureTypeCounter; + rule.symbolizers.push( + new OpenLayers.Symbolizer.Polygon(config) + ); + } else { + rule.symbolizer["Polygon"] = config; + } + }, + "PointSymbolizer": function(node, rule) { + var config = { + fill: false, + stroke: false, + graphic: false + }; + if (!this.multipleSymbolizers) { + config = rule.symbolizer["Point"] || config; + } + this.readChildNodes(node, config); + if (this.multipleSymbolizers) { + config.zIndex = this.featureTypeCounter; + rule.symbolizers.push( + new OpenLayers.Symbolizer.Point(config) + ); + } else { + rule.symbolizer["Point"] = config; + } + }, + "Stroke": function(node, symbolizer) { + symbolizer.stroke = true; + this.readChildNodes(node, symbolizer); + }, + "Fill": function(node, symbolizer) { + symbolizer.fill = true; + this.readChildNodes(node, symbolizer); + }, + "CssParameter": function(node, symbolizer) { + var cssProperty = node.getAttribute("name"); + var symProperty = this.cssMap[cssProperty]; + // 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 + var value = this.readers.ogc._expression.call(this, node); + // always string, could be an empty string + if(value) { + symbolizer[symProperty] = value; + } + } + }, + "Graphic": function(node, symbolizer) { + symbolizer.graphic = true; + 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", "strokeColor", "strokeWidth", "strokeOpacity", + "strokeLinecap", "fill", "fillColor", "fillOpacity", + "graphicName", "rotation", "graphicFormat" + ]; + var prop, value; + for(var i=0, len=properties.length; i<len; ++i) { + prop = properties[i]; + value = graphic[prop]; + if(value != undefined) { + symbolizer[prop] = value; + } + } + // set other generic properties with specific graphic property names + if(graphic.opacity != undefined) { + symbolizer.graphicOpacity = graphic.opacity; + } + if(graphic.size != undefined) { + 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; + } + if(graphic.rotation != undefined) { + symbolizer.rotation = graphic.rotation; + } + }, + "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 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.readers.ogc._expression.call(this, node); + // always string, could be empty string + if(size) { + obj.size = size; + } + }, + "Rotation": function(node, obj) { + var rotation = this.readers.ogc._expression.call(this, node); + // always string, could be empty string + if(rotation) { + obj.rotation = rotation; + } + }, + "OnlineResource": function(node, obj) { + obj.href = this.getAttributeNS( + node, this.namespaces.xlink, "href" + ); + }, + "Format": function(node, graphic) { + graphic.graphicFormat = this.getChildValue(node); + } + } + }, OpenLayers.Format.Filter.v1_0_0.prototype.readers), + + /** + * 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", + "stroke-dasharray": "strokeDashstyle", + "fill": "fillColor", + "fill-opacity": "fillOpacity", + "font-family": "fontFamily", + "font-size": "fontSize", + "font-weight": "fontWeight", + "font-style": "fontStyle" + }, + + /** + * Method: getCssProperty + * Given a symbolizer property, get the corresponding CSS property + * from the <cssMap>. + * + * 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 + * <defaultGraphicFormat> if one of the known <graphicFormats> 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.defaultGraphicFormat; + }, + + /** + * Property: defaultGraphicFormat + * {String} If none other can be determined from <getGraphicFormat>, 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: 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<len; i++) { + item = tokens[i]; + last = item.indexOf("}"); + if(last > 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", + {attributes: { + "version": this.VERSION, + "xsi:schemaLocation": this.schemaLocation + }} + ); + + // For ArcGIS Server it is necessary to define this + // at the root level (see ticket:2166). + root.setAttribute("xmlns:ogc", this.namespaces.ogc); + root.setAttribute("xmlns:gml", this.namespaces.gml); + + // add in optional name + if(sld.name) { + this.writeNode("Name", sld.name, root); + } + // add in optional title + if(sld.title) { + this.writeNode("Title", sld.title, root); + } + // add in optional description + if(sld.description) { + this.writeNode("Abstract", sld.description, root); + } + // add in named layers + // allow namedLayers to be an array + if(OpenLayers.Util.isArray(sld.namedLayers)) { + for(var i=0, len=sld.namedLayers.length; i<len; ++i) { + this.writeNode("NamedLayer", sld.namedLayers[i], root); + } + } else { + for(var name in sld.namedLayers) { + this.writeNode("NamedLayer", sld.namedLayers[name], root); + } + } + return root; + }, + "Name": function(name) { + return this.createElementNSPlus("sld:Name", {value: name}); + }, + "Title": function(title) { + return this.createElementNSPlus("sld:Title", {value: title}); + }, + "Abstract": function(description) { + return this.createElementNSPlus( + "sld:Abstract", {value: description} + ); + }, + "NamedLayer": function(layer) { + var node = this.createElementNSPlus("sld:NamedLayer"); + + // add in required name + this.writeNode("Name", layer.name, node); + + // optional sld:LayerFeatureConstraints here + + // add in named styles + if(layer.namedStyles) { + for(var i=0, len=layer.namedStyles.length; i<len; ++i) { + this.writeNode( + "NamedStyle", layer.namedStyles[i], node + ); + } + } + + // add in user styles + if(layer.userStyles) { + for(var i=0, len=layer.userStyles.length; i<len; ++i) { + this.writeNode( + "UserStyle", layer.userStyles[i], node + ); + } + } + + return node; + }, + "NamedStyle": function(name) { + var node = this.createElementNSPlus("sld:NamedStyle"); + this.writeNode("Name", name, node); + return node; + }, + "UserStyle": function(style) { + var node = this.createElementNSPlus("sld:UserStyle"); + + // add in optional name + if(style.name) { + this.writeNode("Name", style.name, node); + } + // add in optional title + if(style.title) { + this.writeNode("Title", style.title, node); + } + // add in optional description + if(style.description) { + this.writeNode("Abstract", style.description, node); + } + + // add isdefault + if(style.isDefault) { + this.writeNode("IsDefault", style.isDefault, node); + } + + // add FeatureTypeStyles + if (this.multipleSymbolizers && style.rules) { + // group style objects by symbolizer zIndex + var rulesByZ = { + 0: [] + }; + var zValues = [0]; + var rule, ruleMap, symbolizer, zIndex, clone; + for (var i=0, ii=style.rules.length; i<ii; ++i) { + rule = style.rules[i]; + if (rule.symbolizers) { + ruleMap = {}; + for (var j=0, jj=rule.symbolizers.length; j<jj; ++j) { + symbolizer = rule.symbolizers[j]; + zIndex = symbolizer.zIndex; + if (!(zIndex in ruleMap)) { + clone = rule.clone(); + clone.symbolizers = []; + ruleMap[zIndex] = clone; + } + ruleMap[zIndex].symbolizers.push(symbolizer.clone()); + } + for (zIndex in ruleMap) { + if (!(zIndex in rulesByZ)) { + zValues.push(zIndex); + rulesByZ[zIndex] = []; + } + rulesByZ[zIndex].push(ruleMap[zIndex]); + } + } else { + // no symbolizers in rule + rulesByZ[0].push(rule.clone()); + } + } + // write one FeatureTypeStyle per zIndex + zValues.sort(); + var rules; + for (var i=0, ii=zValues.length; i<ii; ++i) { + rules = rulesByZ[zValues[i]]; + if (rules.length > 0) { + clone = style.clone(); + clone.rules = rulesByZ[zValues[i]]; + this.writeNode("FeatureTypeStyle", clone, node); + } + } + } else { + this.writeNode("FeatureTypeStyle", style, node); + } + + return node; + }, + "IsDefault": function(bool) { + return this.createElementNSPlus( + "sld:IsDefault", {value: (bool) ? "1" : "0"} + ); + }, + "FeatureTypeStyle": function(style) { + var node = this.createElementNSPlus("sld:FeatureTypeStyle"); + + // OpenLayers currently stores no Name, Title, Abstract, + // FeatureTypeName, or SemanticTypeIdentifier information + // related to FeatureTypeStyle + + // add in rules + for(var i=0, len=style.rules.length; i<len; ++i) { + this.writeNode("Rule", style.rules[i], node); + } + + return node; + }, + "Rule": function(rule) { + var node = this.createElementNSPlus("sld:Rule"); + + // add in optional name + if(rule.name) { + this.writeNode("Name", rule.name, node); + } + // add in optional title + if(rule.title) { + this.writeNode("Title", rule.title, node); + } + // add in optional description + if(rule.description) { + this.writeNode("Abstract", rule.description, node); + } + + // add in LegendGraphic here + + // add in optional filters + if(rule.elseFilter) { + this.writeNode("ElseFilter", null, node); + } else if(rule.filter) { + this.writeNode("ogc:Filter", rule.filter, node); + } + + // add in scale limits + if(rule.minScaleDenominator != undefined) { + this.writeNode( + "MinScaleDenominator", rule.minScaleDenominator, node + ); + } + if(rule.maxScaleDenominator != undefined) { + this.writeNode( + "MaxScaleDenominator", rule.maxScaleDenominator, node + ); + } + + var type, symbolizer; + if (this.multipleSymbolizers && rule.symbolizers) { + var symbolizer; + for (var i=0, ii=rule.symbolizers.length; i<ii; ++i) { + symbolizer = rule.symbolizers[i]; + type = symbolizer.CLASS_NAME.split(".").pop(); + this.writeNode( + type + "Symbolizer", symbolizer, node + ); + } + } else { + // add in symbolizers (relies on geometry type keys) + var types = OpenLayers.Style.SYMBOLIZER_PREFIXES; + for(var i=0, len=types.length; i<len; ++i) { + type = types[i]; + symbolizer = rule.symbolizer[type]; + if(symbolizer) { + this.writeNode( + type + "Symbolizer", symbolizer, node + ); + } + } + } + return node; + + }, + "ElseFilter": function() { + return this.createElementNSPlus("sld:ElseFilter"); + }, + "MinScaleDenominator": function(scale) { + return this.createElementNSPlus( + "sld:MinScaleDenominator", {value: scale} + ); + }, + "MaxScaleDenominator": function(scale) { + return this.createElementNSPlus( + "sld:MaxScaleDenominator", {value: scale} + ); + }, + "LineSymbolizer": function(symbolizer) { + var node = this.createElementNSPlus("sld:LineSymbolizer"); + this.writeNode("Stroke", symbolizer, node); + return node; + }, + "Stroke": function(symbolizer) { + var node = this.createElementNSPlus("sld:Stroke"); + + // GraphicFill here + // GraphicStroke here + + // add in CssParameters + if(symbolizer.strokeColor != undefined) { + this.writeNode( + "CssParameter", + {symbolizer: symbolizer, key: "strokeColor"}, + node + ); + } + if(symbolizer.strokeOpacity != undefined) { + this.writeNode( + "CssParameter", + {symbolizer: symbolizer, key: "strokeOpacity"}, + node + ); + } + if(symbolizer.strokeWidth != undefined) { + this.writeNode( + "CssParameter", + {symbolizer: symbolizer, key: "strokeWidth"}, + node + ); + } + if(symbolizer.strokeDashstyle != undefined && symbolizer.strokeDashstyle !== "solid") { + // assumes valid stroke-dasharray value + this.writeNode( + "CssParameter", + {symbolizer: symbolizer, key: "strokeDashstyle"}, + node + ); + } + if(symbolizer.strokeLinecap != undefined) { + this.writeNode( + "CssParameter", + {symbolizer: symbolizer, key: "strokeLinecap"}, + node + ); + } + return node; + }, + "CssParameter": function(obj) { + // not handling ogc:expressions for now + return this.createElementNSPlus("sld:CssParameter", { + attributes: {name: this.getCssProperty(obj.key)}, + value: obj.symbolizer[obj.key] + }); + }, + "TextSymbolizer": function(symbolizer) { + var node = this.createElementNSPlus("sld:TextSymbolizer"); + // add in optional Label + if(symbolizer.label != null) { + this.writeNode("Label", symbolizer.label, node); + } + // add in optional Font + if(symbolizer.fontFamily != null || + symbolizer.fontSize != null || + symbolizer.fontWeight != null || + symbolizer.fontStyle != null) { + this.writeNode("Font", symbolizer, node); + } + // add in optional LabelPlacement + if (symbolizer.labelAnchorPointX != null || + symbolizer.labelAnchorPointY != null || + symbolizer.labelAlign != null || + symbolizer.labelXOffset != null || + symbolizer.labelYOffset != null || + symbolizer.labelRotation != null || + symbolizer.labelPerpendicularOffset != null) { + this.writeNode("LabelPlacement", symbolizer, node); + } + // add in optional Halo + if(symbolizer.haloRadius != null || + symbolizer.haloColor != null || + symbolizer.haloOpacity != null) { + this.writeNode("Halo", symbolizer, node); + } + // add in optional Fill + if(symbolizer.fontColor != null || + symbolizer.fontOpacity != null) { + this.writeNode("Fill", { + fillColor: symbolizer.fontColor, + fillOpacity: symbolizer.fontOpacity + }, node); + } + return node; + }, + "LabelPlacement": function(symbolizer) { + var node = this.createElementNSPlus("sld:LabelPlacement"); + // PointPlacement and LinePlacement are choices, so don't output both + if ((symbolizer.labelAnchorPointX != null || + symbolizer.labelAnchorPointY != null || + symbolizer.labelAlign != null || + symbolizer.labelXOffset != null || + symbolizer.labelYOffset != null || + symbolizer.labelRotation != null) && + symbolizer.labelPerpendicularOffset == null) { + this.writeNode("PointPlacement", symbolizer, node); + } + if (symbolizer.labelPerpendicularOffset != null) { + this.writeNode("LinePlacement", symbolizer, node); + } + return node; + }, + "LinePlacement": function(symbolizer) { + var node = this.createElementNSPlus("sld:LinePlacement"); + this.writeNode("PerpendicularOffset", symbolizer.labelPerpendicularOffset, node); + return node; + }, + "PerpendicularOffset": function(value) { + return this.createElementNSPlus("sld:PerpendicularOffset", { + value: value + }); + }, + "PointPlacement": function(symbolizer) { + var node = this.createElementNSPlus("sld:PointPlacement"); + if (symbolizer.labelAnchorPointX != null || + symbolizer.labelAnchorPointY != null || + symbolizer.labelAlign != null) { + this.writeNode("AnchorPoint", symbolizer, node); + } + if (symbolizer.labelXOffset != null || + symbolizer.labelYOffset != null) { + this.writeNode("Displacement", symbolizer, node); + } + if (symbolizer.labelRotation != null) { + this.writeNode("Rotation", symbolizer.labelRotation, node); + } + return node; + }, + "AnchorPoint": function(symbolizer) { + var node = this.createElementNSPlus("sld:AnchorPoint"); + var x = symbolizer.labelAnchorPointX, + y = symbolizer.labelAnchorPointY; + if (x != null) { + this.writeNode("AnchorPointX", x, node); + } + if (y != null) { + this.writeNode("AnchorPointY", y, node); + } + if (x == null && y == null) { + var xAlign = symbolizer.labelAlign.substr(0, 1), + yAlign = symbolizer.labelAlign.substr(1, 1); + if (xAlign === "l") { + x = 0; + } else if (xAlign === "c") { + x = 0.5; + } else if (xAlign === "r") { + x = 1; + } + if (yAlign === "b") { + y = 0; + } else if (yAlign === "m") { + y = 0.5; + } else if (yAlign === "t") { + y = 1; + } + this.writeNode("AnchorPointX", x, node); + this.writeNode("AnchorPointY", y, node); + } + return node; + }, + "AnchorPointX": function(value) { + return this.createElementNSPlus("sld:AnchorPointX", { + value: value + }); + }, + "AnchorPointY": function(value) { + return this.createElementNSPlus("sld:AnchorPointY", { + value: value + }); + }, + "Displacement": function(symbolizer) { + var node = this.createElementNSPlus("sld:Displacement"); + if (symbolizer.labelXOffset != null) { + this.writeNode("DisplacementX", symbolizer.labelXOffset, node); + } + if (symbolizer.labelYOffset != null) { + this.writeNode("DisplacementY", symbolizer.labelYOffset, node); + } + return node; + }, + "DisplacementX": function(value) { + return this.createElementNSPlus("sld:DisplacementX", { + value: value + }); + }, + "DisplacementY": function(value) { + return this.createElementNSPlus("sld:DisplacementY", { + value: value + }); + }, + "Font": function(symbolizer) { + var node = this.createElementNSPlus("sld:Font"); + // add in CssParameters + if(symbolizer.fontFamily) { + this.writeNode( + "CssParameter", + {symbolizer: symbolizer, key: "fontFamily"}, + node + ); + } + if(symbolizer.fontSize) { + this.writeNode( + "CssParameter", + {symbolizer: symbolizer, key: "fontSize"}, + node + ); + } + if(symbolizer.fontWeight) { + this.writeNode( + "CssParameter", + {symbolizer: symbolizer, key: "fontWeight"}, + node + ); + } + if(symbolizer.fontStyle) { + this.writeNode( + "CssParameter", + {symbolizer: symbolizer, key: "fontStyle"}, + node + ); + } + return node; + }, + "Label": function(label) { + return this.writers.sld._OGCExpression.call( + this, "sld:Label", label + ); + }, + "Halo": function(symbolizer) { + var node = this.createElementNSPlus("sld:Halo"); + if(symbolizer.haloRadius) { + this.writeNode("Radius", symbolizer.haloRadius, node); + } + if(symbolizer.haloColor || symbolizer.haloOpacity) { + this.writeNode("Fill", { + fillColor: symbolizer.haloColor, + fillOpacity: symbolizer.haloOpacity + }, node); + } + return node; + }, + "Radius": function(value) { + return this.createElementNSPlus("sld:Radius", { + value: value + }); + }, + "RasterSymbolizer": function(symbolizer) { + var node = this.createElementNSPlus("sld:RasterSymbolizer"); + if (symbolizer.geometry) { + this.writeNode("Geometry", symbolizer.geometry, node); + } + if (symbolizer.opacity) { + this.writeNode("Opacity", symbolizer.opacity, node); + } + if (symbolizer.colorMap) { + this.writeNode("ColorMap", symbolizer.colorMap, node); + } + return node; + }, + "Geometry": function(geometry) { + var node = this.createElementNSPlus("sld:Geometry"); + if (geometry.property) { + this.writeNode("ogc:PropertyName", geometry, node); + } + return node; + }, + "ColorMap": function(colorMap) { + var node = this.createElementNSPlus("sld:ColorMap"); + for (var i=0, len=colorMap.length; i<len; ++i) { + this.writeNode("ColorMapEntry", colorMap[i], node); + } + return node; + }, + "ColorMapEntry": function(colorMapEntry) { + var node = this.createElementNSPlus("sld:ColorMapEntry"); + var a = colorMapEntry; + node.setAttribute("color", a.color); + a.opacity !== undefined && node.setAttribute("opacity", + parseFloat(a.opacity)); + a.quantity !== undefined && node.setAttribute("quantity", + parseFloat(a.quantity)); + a.label !== undefined && node.setAttribute("label", a.label); + return node; + }, + "PolygonSymbolizer": function(symbolizer) { + var node = this.createElementNSPlus("sld:PolygonSymbolizer"); + if(symbolizer.fill !== false) { + this.writeNode("Fill", symbolizer, node); + } + if(symbolizer.stroke !== false) { + this.writeNode("Stroke", symbolizer, node); + } + return node; + }, + "Fill": function(symbolizer) { + var node = this.createElementNSPlus("sld:Fill"); + + // GraphicFill here + + // add in CssParameters + if(symbolizer.fillColor) { + this.writeNode( + "CssParameter", + {symbolizer: symbolizer, key: "fillColor"}, + node + ); + } + if(symbolizer.fillOpacity != null) { + this.writeNode( + "CssParameter", + {symbolizer: symbolizer, key: "fillOpacity"}, + node + ); + } + return node; + }, + "PointSymbolizer": function(symbolizer) { + var node = this.createElementNSPlus("sld:PointSymbolizer"); + this.writeNode("Graphic", symbolizer, node); + return node; + }, + "Graphic": function(symbolizer) { + var node = this.createElementNSPlus("sld:Graphic"); + if(symbolizer.externalGraphic != undefined) { + this.writeNode("ExternalGraphic", symbolizer, node); + } else { + this.writeNode("Mark", symbolizer, node); + } + + if(symbolizer.graphicOpacity != undefined) { + this.writeNode("Opacity", symbolizer.graphicOpacity, node); + } + 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); + } + return node; + }, + "ExternalGraphic": function(symbolizer) { + var node = this.createElementNSPlus("sld:ExternalGraphic"); + this.writeNode( + "OnlineResource", symbolizer.externalGraphic, node + ); + var format = symbolizer.graphicFormat || + this.getGraphicFormat(symbolizer.externalGraphic); + this.writeNode("Format", format, node); + return node; + }, + "Mark": function(symbolizer) { + var node = this.createElementNSPlus("sld:Mark"); + if(symbolizer.graphicName) { + this.writeNode("WellKnownName", symbolizer.graphicName, node); + } + if (symbolizer.fill !== false) { + this.writeNode("Fill", symbolizer, node); + } + if (symbolizer.stroke !== false) { + this.writeNode("Stroke", symbolizer, node); + } + return node; + }, + "WellKnownName": function(name) { + return this.createElementNSPlus("sld:WellKnownName", { + value: name + }); + }, + "Opacity": function(value) { + return this.createElementNSPlus("sld:Opacity", { + value: value + }); + }, + "Size": function(value) { + return this.writers.sld._OGCExpression.call( + this, "sld:Size", value + ); + }, + "Rotation": function(value) { + return this.createElementNSPlus("sld:Rotation", { + value: value + }); + }, + "OnlineResource": function(href) { + return this.createElementNSPlus("sld:OnlineResource", { + attributes: { + "xlink:type": "simple", + "xlink:href": href + } + }); + }, + "Format": function(format) { + return this.createElementNSPlus("sld:Format", { + value: format + }); + } + } + }, OpenLayers.Format.Filter.v1_0_0.prototype.writers), + + CLASS_NAME: "OpenLayers.Format.SLD.v1" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/SLD/v1_0_0.js b/misc/openlayers/lib/OpenLayers/Format/SLD/v1_0_0.js new file mode 100644 index 0000000..e920b50 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/SLD/v1_0_0.js @@ -0,0 +1,46 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/SLD/v1.js + * @requires OpenLayers/Format/Filter/v1_0_0.js + */ + +/** + * Class: OpenLayers.Format.SLD.v1_0_0 + * Write SLD version 1.0.0. + * + * Inherits from: + * - <OpenLayers.Format.SLD.v1> + */ +OpenLayers.Format.SLD.v1_0_0 = OpenLayers.Class( + OpenLayers.Format.SLD.v1, { + + /** + * Constant: VERSION + * {String} 1.0.0 + */ + VERSION: "1.0.0", + + /** + * Property: schemaLocation + * {String} http://www.opengis.net/sld + * http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd + */ + schemaLocation: "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd", + + /** + * Constructor: OpenLayers.Format.SLD.v1_0_0 + * Instances of this class are not created directly. Use the + * <OpenLayers.Format.SLD> constructor instead. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + CLASS_NAME: "OpenLayers.Format.SLD.v1_0_0" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js b/misc/openlayers/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js new file mode 100644 index 0000000..902da67 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/SLD/v1_0_0_GeoServer.js @@ -0,0 +1,149 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/SLD/v1_0_0.js + */ + +/** + * Class: OpenLayers.Format.SLD/v1_0_0_GeoServer + * 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: + * - <OpenLayers.Format.SLD.v1_0_0> + */ +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: OpenLayers.Util.applyDefaults({ + "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[node.getAttribute("name")] = this.getChildValue(node); + }, + "TextSymbolizer": function(node, rule) { + OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld.TextSymbolizer.apply(this, arguments); + var symbolizer = this.multipleSymbolizers ? rule.symbolizers[rule.symbolizers.length-1] : rule.symbolizer["Text"]; + if (symbolizer.graphic === undefined) { + symbolizer.graphic = false; + } + } + }, OpenLayers.Format.SLD.v1_0_0.prototype.readers["sld"]) + }, OpenLayers.Format.SLD.v1_0_0.prototype.readers), + + /** + * 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: OpenLayers.Util.applyDefaults({ + "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 writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; + var node = writers["sld"]["TextSymbolizer"].apply(this, arguments); + if (symbolizer.graphic !== false && (symbolizer.externalGraphic || symbolizer.graphicName)) { + this.writeNode("Graphic", symbolizer, node); + } + if ("priority" in symbolizer) { + this.writeNode("Priority", symbolizer.priority, node); + } + return this.addVendorOptions(node, symbolizer); + }, + "PointSymbolizer": function(symbolizer) { + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; + var node = writers["sld"]["PointSymbolizer"].apply(this, arguments); + return this.addVendorOptions(node, symbolizer); + }, + "LineSymbolizer": function(symbolizer) { + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; + var node = writers["sld"]["LineSymbolizer"].apply(this, arguments); + return this.addVendorOptions(node, symbolizer); + }, + "PolygonSymbolizer": function(symbolizer) { + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; + var node = writers["sld"]["PolygonSymbolizer"].apply(this, arguments); + return this.addVendorOptions(node, symbolizer); + } + }, OpenLayers.Format.SLD.v1_0_0.prototype.writers["sld"]) + }, OpenLayers.Format.SLD.v1_0_0.prototype.writers), + + /** + * Method: addVendorOptions + * Add in the VendorOption tags and return the node again. + * + * Parameters: + * node - {DOMElement} A DOM node. + * symbolizer - {Object} + * + * Returns: + * {DOMElement} A DOM node. + */ + addVendorOptions: function(node, symbolizer) { + var options = symbolizer.vendorOptions; + if (options) { + for (var key in symbolizer.vendorOptions) { + this.writeNode("VendorOption", { + name: key, + value: symbolizer.vendorOptions[key] + }, node); + } + } + return node; + }, + + CLASS_NAME: "OpenLayers.Format.SLD.v1_0_0_GeoServer" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/SOSCapabilities.js b/misc/openlayers/lib/OpenLayers/Format/SOSCapabilities.js new file mode 100644 index 0000000..1abb1c8 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/SOSCapabilities.js @@ -0,0 +1,48 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML/VersionedOGC.js + */ + +/** + * Class: OpenLayers.Format.SOSCapabilities + * Read SOS Capabilities. + * + * Inherits from: + * - <OpenLayers.Format.XML.VersionedOGC> + */ +OpenLayers.Format.SOSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { + + /** + * APIProperty: defaultVersion + * {String} Version number to assume if none found. Default is "1.0.0". + */ + defaultVersion: "1.0.0", + + /** + * Constructor: OpenLayers.Format.SOSCapabilities + * Create a new parser for SOS Capabilities. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Read capabilities data from a string, and return information about + * the service (offering and observedProperty mostly). + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Object} Info about the SOS + */ + + CLASS_NAME: "OpenLayers.Format.SOSCapabilities" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/SOSCapabilities/v1_0_0.js b/misc/openlayers/lib/OpenLayers/Format/SOSCapabilities/v1_0_0.js new file mode 100644 index 0000000..89c0e91 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/SOSCapabilities/v1_0_0.js @@ -0,0 +1,158 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/SOSCapabilities.js + * @requires OpenLayers/Format/OWSCommon/v1_1_0.js + * @requires OpenLayers/Format/GML/v3.js + */ + +/** + * Class: OpenLayers.Format.SOSCapabilities.v1_0_0 + * Read SOS Capabilities version 1.0.0. + * + * Inherits from: + * - <OpenLayers.Format.SOSCapabilities> + */ +OpenLayers.Format.SOSCapabilities.v1_0_0 = OpenLayers.Class( + OpenLayers.Format.SOSCapabilities, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + ows: "http://www.opengis.net/ows/1.1", + sos: "http://www.opengis.net/sos/1.0", + gml: "http://www.opengis.net/gml", + xlink: "http://www.w3.org/1999/xlink" + }, + + /** + * Property: regExes + * Compiled regular expressions for manipulating strings. + */ + regExes: { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g) + }, + + /** + * Constructor: OpenLayers.Format.SOSCapabilities.v1_0_0 + * Create a new parser for SOS capabilities version 1.0.0. + * + * 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]); + this.options = options; + }, + + /** + * APIMethod: read + * Read capabilities data from a string, and return info about the SOS. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Object} Information about the SOS service. + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + if(data && data.nodeType == 9) { + data = data.documentElement; + } + var capabilities = {}; + this.readNode(data, capabilities); + return capabilities; + }, + + /** + * 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: { + "gml": OpenLayers.Util.applyDefaults({ + "name": function(node, obj) { + obj.name = this.getChildValue(node); + }, + "TimePeriod": function(node, obj) { + obj.timePeriod = {}; + this.readChildNodes(node, obj.timePeriod); + }, + "beginPosition": function(node, timePeriod) { + timePeriod.beginPosition = this.getChildValue(node); + }, + "endPosition": function(node, timePeriod) { + timePeriod.endPosition = this.getChildValue(node); + } + }, OpenLayers.Format.GML.v3.prototype.readers["gml"]), + "sos": { + "Capabilities": function(node, obj) { + this.readChildNodes(node, obj); + }, + "Contents": function(node, obj) { + obj.contents = {}; + this.readChildNodes(node, obj.contents); + }, + "ObservationOfferingList": function(node, contents) { + contents.offeringList = {}; + this.readChildNodes(node, contents.offeringList); + }, + "ObservationOffering": function(node, offeringList) { + var id = this.getAttributeNS(node, this.namespaces.gml, "id"); + offeringList[id] = { + procedures: [], + observedProperties: [], + featureOfInterestIds: [], + responseFormats: [], + resultModels: [], + responseModes: [] + }; + this.readChildNodes(node, offeringList[id]); + }, + "time": function(node, offering) { + offering.time = {}; + this.readChildNodes(node, offering.time); + }, + "procedure": function(node, offering) { + offering.procedures.push(this.getAttributeNS(node, + this.namespaces.xlink, "href")); + }, + "observedProperty": function(node, offering) { + offering.observedProperties.push(this.getAttributeNS(node, + this.namespaces.xlink, "href")); + }, + "featureOfInterest": function(node, offering) { + offering.featureOfInterestIds.push(this.getAttributeNS(node, + this.namespaces.xlink, "href")); + }, + "responseFormat": function(node, offering) { + offering.responseFormats.push(this.getChildValue(node)); + }, + "resultModel": function(node, offering) { + offering.resultModels.push(this.getChildValue(node)); + }, + "responseMode": function(node, offering) { + offering.responseModes.push(this.getChildValue(node)); + } + }, + "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] + }, + + CLASS_NAME: "OpenLayers.Format.SOSCapabilities.v1_0_0" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/SOSGetFeatureOfInterest.js b/misc/openlayers/lib/OpenLayers/Format/SOSGetFeatureOfInterest.js new file mode 100644 index 0000000..aac2030 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/SOSGetFeatureOfInterest.js @@ -0,0 +1,190 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Format/GML/v3.js + */ + +/** + * Class: OpenLayers.Format.SOSGetFeatureOfInterest + * Read and write SOS GetFeatureOfInterest. This is used to get to + * the location of the features (stations). The stations can have 1 or more + * sensors. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.SOSGetFeatureOfInterest = OpenLayers.Class( + OpenLayers.Format.XML, { + + /** + * Constant: VERSION + * {String} 1.0.0 + */ + VERSION: "1.0.0", + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + sos: "http://www.opengis.net/sos/1.0", + gml: "http://www.opengis.net/gml", + sa: "http://www.opengis.net/sampling/1.0", + xsi: "http://www.w3.org/2001/XMLSchema-instance" + }, + + /** + * Property: schemaLocation + * {String} Schema location + */ + schemaLocation: "http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosAll.xsd", + + /** + * Property: defaultPrefix + */ + defaultPrefix: "sos", + + /** + * Property: regExes + * Compiled regular expressions for manipulating strings. + */ + regExes: { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g) + }, + + /** + * Constructor: OpenLayers.Format.SOSGetFeatureOfInterest + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Parse a GetFeatureOfInterest response and return an array of features + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array(<OpenLayers.Feature.Vector>)} An array of features. + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + if(data && data.nodeType == 9) { + data = data.documentElement; + } + + var info = {features: []}; + this.readNode(data, info); + + var features = []; + for (var i=0, len=info.features.length; i<len; i++) { + var container = info.features[i]; + // reproject features if needed + if(this.internalProjection && this.externalProjection && + container.components[0]) { + container.components[0].transform( + this.externalProjection, this.internalProjection + ); + } + var feature = new OpenLayers.Feature.Vector( + container.components[0], container.attributes); + features.push(feature); + } + return features; + }, + + /** + * 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: { + "sa": { + "SamplingPoint": function(node, obj) { + // sampling point can also be without a featureMember if + // there is only 1 + if (!obj.attributes) { + var feature = {attributes: {}}; + obj.features.push(feature); + obj = feature; + } + obj.attributes.id = this.getAttributeNS(node, + this.namespaces.gml, "id"); + this.readChildNodes(node, obj); + }, + "position": function (node, obj) { + this.readChildNodes(node, obj); + } + }, + "gml": OpenLayers.Util.applyDefaults({ + "FeatureCollection": function(node, obj) { + this.readChildNodes(node, obj); + }, + "featureMember": function(node, obj) { + var feature = {attributes: {}}; + obj.features.push(feature); + this.readChildNodes(node, feature); + }, + "name": function(node, obj) { + obj.attributes.name = this.getChildValue(node); + }, + "pos": function(node, obj) { + // we need to parse the srsName to get to the + // externalProjection, that's why we cannot use + // GML v3 for this + if (!this.externalProjection) { + this.externalProjection = new OpenLayers.Projection( + node.getAttribute("srsName")); + } + OpenLayers.Format.GML.v3.prototype.readers.gml.pos.apply( + this, [node, obj]); + } + }, OpenLayers.Format.GML.v3.prototype.readers.gml) + }, + + /** + * 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: { + "sos": { + "GetFeatureOfInterest": function(options) { + var node = this.createElementNSPlus("GetFeatureOfInterest", { + attributes: { + version: this.VERSION, + service: 'SOS', + "xsi:schemaLocation": this.schemaLocation + } + }); + for (var i=0, len=options.fois.length; i<len; i++) { + this.writeNode("FeatureOfInterestId", {foi: options.fois[i]}, node); + } + return node; + }, + "FeatureOfInterestId": function(options) { + var node = this.createElementNSPlus("FeatureOfInterestId", {value: options.foi}); + return node; + } + } + }, + + CLASS_NAME: "OpenLayers.Format.SOSGetFeatureOfInterest" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/SOSGetObservation.js b/misc/openlayers/lib/OpenLayers/Format/SOSGetObservation.js new file mode 100644 index 0000000..9a6e2d7 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/SOSGetObservation.js @@ -0,0 +1,302 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Format/SOSGetFeatureOfInterest.js + */ + +/** + * Class: OpenLayers.Format.SOSGetObservation + * Read and write SOS GetObersation (to get the actual values from a sensor) + * version 1.0.0 + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.SOSGetObservation = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + ows: "http://www.opengis.net/ows", + gml: "http://www.opengis.net/gml", + sos: "http://www.opengis.net/sos/1.0", + ogc: "http://www.opengis.net/ogc", + om: "http://www.opengis.net/om/1.0", + sa: "http://www.opengis.net/sampling/1.0", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance" + }, + + /** + * Property: regExes + * Compiled regular expressions for manipulating strings. + */ + regExes: { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g) + }, + + /** + * Constant: VERSION + * {String} 1.0.0 + */ + VERSION: "1.0.0", + + /** + * Property: schemaLocation + * {String} Schema location + */ + schemaLocation: "http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosGetObservation.xsd", + + /** + * Property: defaultPrefix + */ + defaultPrefix: "sos", + + /** + * Constructor: OpenLayers.Format.SOSGetObservation + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * Method: read + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Object} An object containing the measurements + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + if(data && data.nodeType == 9) { + data = data.documentElement; + } + var info = {measurements: [], observations: []}; + this.readNode(data, info); + return info; + }, + + /** + * Method: write + * + * Parameters: + * options - {Object} Optional object. + * + * Returns: + * {String} An SOS GetObservation request XML string. + */ + write: function(options) { + var node = this.writeNode("sos:GetObservation", options); + node.setAttribute("xmlns:om", this.namespaces.om); + node.setAttribute("xmlns:ogc", this.namespaces.ogc); + this.setAttributeNS( + node, this.namespaces.xsi, + "xsi:schemaLocation", this.schemaLocation + ); + return OpenLayers.Format.XML.prototype.write.apply(this, [node]); + }, + + /** + * 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: { + "om": { + "ObservationCollection": function(node, obj) { + obj.id = this.getAttributeNS(node, this.namespaces.gml, "id"); + this.readChildNodes(node, obj); + }, + "member": function(node, observationCollection) { + this.readChildNodes(node, observationCollection); + }, + "Measurement": function(node, observationCollection) { + var measurement = {}; + observationCollection.measurements.push(measurement); + this.readChildNodes(node, measurement); + }, + "Observation": function(node, observationCollection) { + var observation = {}; + observationCollection.observations.push(observation); + this.readChildNodes(node, observation); + }, + "samplingTime": function(node, measurement) { + var samplingTime = {}; + measurement.samplingTime = samplingTime; + this.readChildNodes(node, samplingTime); + }, + "observedProperty": function(node, measurement) { + measurement.observedProperty = + this.getAttributeNS(node, this.namespaces.xlink, "href"); + this.readChildNodes(node, measurement); + }, + "procedure": function(node, measurement) { + measurement.procedure = + this.getAttributeNS(node, this.namespaces.xlink, "href"); + this.readChildNodes(node, measurement); + }, + "featureOfInterest": function(node, observation) { + var foi = {features: []}; + observation.fois = []; + observation.fois.push(foi); + this.readChildNodes(node, foi); + // postprocessing to get actual features + var features = []; + for (var i=0, len=foi.features.length; i<len; i++) { + var feature = foi.features[i]; + features.push(new OpenLayers.Feature.Vector( + feature.components[0], feature.attributes)); + } + foi.features = features; + }, + "result": function(node, measurement) { + var result = {}; + measurement.result = result; + if (this.getChildValue(node) !== '') { + result.value = this.getChildValue(node); + result.uom = node.getAttribute("uom"); + } else { + this.readChildNodes(node, result); + } + } + }, + "sa": OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.sa, + "gml": OpenLayers.Util.applyDefaults({ + "TimeInstant": function(node, samplingTime) { + var timeInstant = {}; + samplingTime.timeInstant = timeInstant; + this.readChildNodes(node, timeInstant); + }, + "timePosition": function(node, timeInstant) { + timeInstant.timePosition = this.getChildValue(node); + } + }, OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.gml) + }, + + /** + * 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: { + "sos": { + "GetObservation": function(options) { + var node = this.createElementNSPlus("GetObservation", { + attributes: { + version: this.VERSION, + service: 'SOS' + } + }); + this.writeNode("offering", options, node); + if (options.eventTime) { + this.writeNode("eventTime", options, node); + } + for (var procedure in options.procedures) { + this.writeNode("procedure", options.procedures[procedure], node); + } + for (var observedProperty in options.observedProperties) { + this.writeNode("observedProperty", options.observedProperties[observedProperty], node); + } + if (options.foi) { + this.writeNode("featureOfInterest", options.foi, node); + } + this.writeNode("responseFormat", options, node); + if (options.resultModel) { + this.writeNode("resultModel", options, node); + } + if (options.responseMode) { + this.writeNode("responseMode", options, node); + } + return node; + }, + "featureOfInterest": function(foi) { + var node = this.createElementNSPlus("featureOfInterest"); + this.writeNode("ObjectID", foi.objectId, node); + return node; + }, + "ObjectID": function(options) { + return this.createElementNSPlus("ObjectID", + {value: options}); + }, + "responseFormat": function(options) { + return this.createElementNSPlus("responseFormat", + {value: options.responseFormat}); + }, + "procedure": function(procedure) { + return this.createElementNSPlus("procedure", + {value: procedure}); + }, + "offering": function(options) { + return this.createElementNSPlus("offering", {value: + options.offering}); + }, + "observedProperty": function(observedProperty) { + return this.createElementNSPlus("observedProperty", + {value: observedProperty}); + }, + "eventTime": function(options) { + var node = this.createElementNSPlus("eventTime"); + if (options.eventTime === 'latest') { + this.writeNode("ogc:TM_Equals", options, node); + } + return node; + }, + "resultModel": function(options) { + return this.createElementNSPlus("resultModel", {value: + options.resultModel}); + }, + "responseMode": function(options) { + return this.createElementNSPlus("responseMode", {value: + options.responseMode}); + } + }, + "ogc": { + "TM_Equals": function(options) { + var node = this.createElementNSPlus("ogc:TM_Equals"); + this.writeNode("ogc:PropertyName", {property: + "urn:ogc:data:time:iso8601"}, node); + if (options.eventTime === 'latest') { + this.writeNode("gml:TimeInstant", {value: 'latest'}, node); + } + return node; + }, + "PropertyName": function(options) { + return this.createElementNSPlus("ogc:PropertyName", + {value: options.property}); + } + }, + "gml": { + "TimeInstant": function(options) { + var node = this.createElementNSPlus("gml:TimeInstant"); + this.writeNode("gml:timePosition", options, node); + return node; + }, + "timePosition": function(options) { + var node = this.createElementNSPlus("gml:timePosition", + {value: options.value}); + return node; + } + } + }, + + CLASS_NAME: "OpenLayers.Format.SOSGetObservation" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/Text.js b/misc/openlayers/lib/OpenLayers/Format/Text.js new file mode 100644 index 0000000..bf9bcd5 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/Text.js @@ -0,0 +1,151 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Feature/Vector.js + * @requires OpenLayers/Geometry/Point.js + */ + +/** + * Class: OpenLayers.Format.Text + * Read Text format. Create a new instance with the <OpenLayers.Format.Text> + * constructor. This reads text which is formatted like CSV text, using + * tabs as the seperator by default. It provides parsing of data originally + * used in the MapViewerService, described on the wiki. This Format is used + * by the <OpenLayers.Layer.Text> class. + * + * Inherits from: + * - <OpenLayers.Format> + */ +OpenLayers.Format.Text = OpenLayers.Class(OpenLayers.Format, { + + /** + * APIProperty: defaultStyle + * defaultStyle allows one to control the default styling of the features. + * It should be a symbolizer hash. By default, this is set to match the + * Layer.Text behavior, which is to use the default OpenLayers Icon. + */ + defaultStyle: null, + + /** + * APIProperty: extractStyles + * set to true to extract styles from the TSV files, using information + * from the image or icon, iconSize and iconOffset fields. This will result + * in features with a symbolizer (style) property set, using the + * default symbolizer specified in <defaultStyle>. Set to false if you + * wish to use a styleMap or OpenLayers.Style options to style your + * layer instead. + */ + extractStyles: true, + + /** + * Constructor: OpenLayers.Format.Text + * Create a new parser for TSV Text. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + options = options || {}; + + if(options.extractStyles !== false) { + options.defaultStyle = { + 'externalGraphic': OpenLayers.Util.getImageLocation("marker.png"), + 'graphicWidth': 21, + 'graphicHeight': 25, + 'graphicXOffset': -10.5, + 'graphicYOffset': -12.5 + }; + } + + OpenLayers.Format.prototype.initialize.apply(this, [options]); + }, + + /** + * APIMethod: read + * Return a list of features from a Tab Seperated Values text string. + * + * Parameters: + * text - {String} + * + * Returns: + * Array({<OpenLayers.Feature.Vector>}) + */ + read: function(text) { + var lines = text.split('\n'); + var columns; + var features = []; + // length - 1 to allow for trailing new line + for (var lcv = 0; lcv < (lines.length - 1); lcv++) { + var currLine = lines[lcv].replace(/^\s*/,'').replace(/\s*$/,''); + + if (currLine.charAt(0) != '#') { /* not a comment */ + + if (!columns) { + //First line is columns + columns = currLine.split('\t'); + } else { + var vals = currLine.split('\t'); + var geometry = new OpenLayers.Geometry.Point(0,0); + var attributes = {}; + var style = this.defaultStyle ? + OpenLayers.Util.applyDefaults({}, this.defaultStyle) : + null; + var icon, iconSize, iconOffset, overflow; + var set = false; + for (var valIndex = 0; valIndex < vals.length; valIndex++) { + if (vals[valIndex]) { + if (columns[valIndex] == 'point') { + var coords = vals[valIndex].split(','); + geometry.y = parseFloat(coords[0]); + geometry.x = parseFloat(coords[1]); + set = true; + } else if (columns[valIndex] == 'lat') { + geometry.y = parseFloat(vals[valIndex]); + set = true; + } else if (columns[valIndex] == 'lon') { + geometry.x = parseFloat(vals[valIndex]); + set = true; + } else if (columns[valIndex] == 'title') + attributes['title'] = vals[valIndex]; + else if (columns[valIndex] == 'image' || + columns[valIndex] == 'icon' && style) { + style['externalGraphic'] = vals[valIndex]; + } else if (columns[valIndex] == 'iconSize' && style) { + var size = vals[valIndex].split(','); + style['graphicWidth'] = parseFloat(size[0]); + style['graphicHeight'] = parseFloat(size[1]); + } else if (columns[valIndex] == 'iconOffset' && style) { + var offset = vals[valIndex].split(','); + style['graphicXOffset'] = parseFloat(offset[0]); + style['graphicYOffset'] = parseFloat(offset[1]); + } else if (columns[valIndex] == 'description') { + attributes['description'] = vals[valIndex]; + } else if (columns[valIndex] == 'overflow') { + attributes['overflow'] = vals[valIndex]; + } else { + // For StyleMap filtering, allow additional + // columns to be stored as attributes. + attributes[columns[valIndex]] = vals[valIndex]; + } + } + } + if (set) { + if (this.internalProjection && this.externalProjection) { + geometry.transform(this.externalProjection, + this.internalProjection); + } + var feature = new OpenLayers.Feature.Vector(geometry, attributes, style); + features.push(feature); + } + } + } + } + return features; + }, + + CLASS_NAME: "OpenLayers.Format.Text" +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WCSCapabilities.js b/misc/openlayers/lib/OpenLayers/Format/WCSCapabilities.js new file mode 100644 index 0000000..934aaa5 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WCSCapabilities.js @@ -0,0 +1,47 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML/VersionedOGC.js + */ + +/** + * Class: OpenLayers.Format.WCSCapabilities + * Read WCS Capabilities. + * + * Inherits from: + * - <OpenLayers.Format.XML.VersionedOGC> + */ +OpenLayers.Format.WCSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { + + /** + * APIProperty: defaultVersion + * {String} Version number to assume if none found. Default is "1.1.0". + */ + defaultVersion: "1.1.0", + + /** + * Constructor: OpenLayers.Format.WCSCapabilities + * Create a new parser for WCS capabilities. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Read capabilities data from a string, and return a list of coverages. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array} List of named coverages. + */ + + CLASS_NAME: "OpenLayers.Format.WCSCapabilities" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WCSCapabilities/v1.js b/misc/openlayers/lib/OpenLayers/Format/WCSCapabilities/v1.js new file mode 100644 index 0000000..bf8da3b --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WCSCapabilities/v1.js @@ -0,0 +1,55 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WCSCapabilities.js + */ + +/** + * Class: OpenLayers.Format.WCSCapabilities.v1 + * Abstract class not to be instantiated directly. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.WCSCapabilities.v1 = OpenLayers.Class( + OpenLayers.Format.XML, { + + regExes: { + trimSpace: (/^\s*|\s*$/g), + splitSpace: (/\s+/) + }, + + /** + * Property: defaultPrefix + */ + defaultPrefix: "wcs", + + /** + * APIMethod: read + * Read capabilities data from a string, and return a list of coverages. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array} List of named coverages. + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + var raw = data; + if(data && data.nodeType == 9) { + data = data.documentElement; + } + var capabilities = {}; + this.readNode(data, capabilities); + return capabilities; + }, + + CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1" + +});
\ No newline at end of file diff --git a/misc/openlayers/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js b/misc/openlayers/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js new file mode 100644 index 0000000..4dfa0b8 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js @@ -0,0 +1,170 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WCSCapabilities/v1.js + * @requires OpenLayers/Format/GML/v3.js + */ + +/** + * Class: OpenLayers.Format.WCSCapabilities/v1_0_0 + * Read WCS Capabilities version 1.0.0. + * + * Inherits from: + * - <OpenLayers.Format.WCSCapabilities.v1> + */ +OpenLayers.Format.WCSCapabilities.v1_0_0 = OpenLayers.Class( + OpenLayers.Format.WCSCapabilities.v1, { + + /** + * Constructor: OpenLayers.Format.WCSCapabilities.v1_0_0 + * Create a new parser for WCS capabilities version 1.0.0. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + wcs: "http://www.opengis.net/wcs", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance", + ows: "http://www.opengis.net/ows" + }, + + /** + * Property: errorProperty + * {String} Which property of the returned object to check for in order to + * determine whether or not parsing has failed. In the case that the + * errorProperty is undefined on the returned object, the document will be + * run through an OGCExceptionReport parser. + */ + errorProperty: "service", + + /** + * 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: { + "wcs": { + "WCS_Capabilities": function(node, obj) { + this.readChildNodes(node, obj); + }, + "Service": function(node, obj) { + obj.service = {}; + this.readChildNodes(node, obj.service); + }, + "name": function(node, service) { + service.name = this.getChildValue(node); + }, + "label": function(node, service) { + service.label = this.getChildValue(node); + }, + "keywords": function(node, service) { + service.keywords = []; + this.readChildNodes(node, service.keywords); + }, + "keyword": function(node, keywords) { + // Append the keyword to the keywords list + keywords.push(this.getChildValue(node)); + }, + "responsibleParty": function(node, service) { + service.responsibleParty = {}; + this.readChildNodes(node, service.responsibleParty); + }, + "individualName": function(node, responsibleParty) { + responsibleParty.individualName = this.getChildValue(node); + }, + "organisationName": function(node, responsibleParty) { + responsibleParty.organisationName = this.getChildValue(node); + }, + "positionName": function(node, responsibleParty) { + responsibleParty.positionName = this.getChildValue(node); + }, + "contactInfo": function(node, responsibleParty) { + responsibleParty.contactInfo = {}; + this.readChildNodes(node, responsibleParty.contactInfo); + }, + "phone": function(node, contactInfo) { + contactInfo.phone = {}; + this.readChildNodes(node, contactInfo.phone); + }, + "voice": function(node, phone) { + phone.voice = this.getChildValue(node); + }, + "facsimile": function(node, phone) { + phone.facsimile = this.getChildValue(node); + }, + "address": function(node, contactInfo) { + contactInfo.address = {}; + this.readChildNodes(node, contactInfo.address); + }, + "deliveryPoint": function(node, address) { + address.deliveryPoint = this.getChildValue(node); + }, + "city": function(node, address) { + address.city = this.getChildValue(node); + }, + "postalCode": function(node, address) { + address.postalCode = this.getChildValue(node); + }, + "country": function(node, address) { + address.country = this.getChildValue(node); + }, + "electronicMailAddress": function(node, address) { + address.electronicMailAddress = this.getChildValue(node); + }, + "fees": function(node, service) { + service.fees = this.getChildValue(node); + }, + "accessConstraints": function(node, service) { + service.accessConstraints = this.getChildValue(node); + }, + "ContentMetadata": function(node, obj) { + obj.contentMetadata = []; + this.readChildNodes(node, obj.contentMetadata); + }, + "CoverageOfferingBrief": function(node, contentMetadata) { + var coverageOfferingBrief = {}; + this.readChildNodes(node, coverageOfferingBrief); + contentMetadata.push(coverageOfferingBrief); + }, + "name": function(node, coverageOfferingBrief) { + coverageOfferingBrief.name = this.getChildValue(node); + }, + "label": function(node, coverageOfferingBrief) { + coverageOfferingBrief.label = this.getChildValue(node); + }, + "lonLatEnvelope": function(node, coverageOfferingBrief) { + var nodeList = this.getElementsByTagNameNS(node, "http://www.opengis.net/gml", "pos"); + + // We expect two nodes here, to create the corners of a bounding box + if(nodeList.length == 2) { + var min = {}; + var max = {}; + + OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[0], min]); + OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[1], max]); + + coverageOfferingBrief.lonLatEnvelope = {}; + coverageOfferingBrief.lonLatEnvelope.srsName = node.getAttribute("srsName"); + coverageOfferingBrief.lonLatEnvelope.min = min.points[0]; + coverageOfferingBrief.lonLatEnvelope.max = max.points[0]; + } + } + } + }, + + CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_0_0" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WCSCapabilities/v1_1_0.js b/misc/openlayers/lib/OpenLayers/Format/WCSCapabilities/v1_1_0.js new file mode 100644 index 0000000..1753c51 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WCSCapabilities/v1_1_0.js @@ -0,0 +1,109 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WCSCapabilities/v1.js + * @requires OpenLayers/Format/OWSCommon/v1_1_0.js + */ + +/** + * Class: OpenLayers.Format.WCSCapabilities/v1_1_0 + * Read WCS Capabilities version 1.1.0. + * + * Inherits from: + * - <OpenLayers.Format.WCSCapabilities.v1> + */ +OpenLayers.Format.WCSCapabilities.v1_1_0 = OpenLayers.Class( + OpenLayers.Format.WCSCapabilities.v1, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + wcs: "http://www.opengis.net/wcs/1.1", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance", + ows: "http://www.opengis.net/ows/1.1" + }, + + /** + * APIProperty: errorProperty + * {String} Which property of the returned object to check for in order to + * determine whether or not parsing has failed. In the case that the + * errorProperty is undefined on the returned object, the document will be + * run through an OGCExceptionReport parser. + */ + errorProperty: "operationsMetadata", + + /** + * Constructor: OpenLayers.Format.WCSCapabilities.v1_1_0 + * Create a new parser for WCS capabilities version 1.1.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: { + "wcs": OpenLayers.Util.applyDefaults({ + // In 1.0.0, this was WCS_Capabilties, in 1.1.0, it's Capabilities + "Capabilities": function(node, obj) { + this.readChildNodes(node, obj); + }, + "Contents": function(node, request) { + request.contentMetadata = []; + this.readChildNodes(node, request.contentMetadata); + }, + "CoverageSummary": function(node, contentMetadata) { + var coverageSummary = {}; + // Read the summary: + this.readChildNodes(node, coverageSummary); + + // Add it to the contentMetadata array: + contentMetadata.push(coverageSummary); + }, + "Identifier": function(node, coverageSummary) { + coverageSummary.identifier = this.getChildValue(node); + }, + "Title": function(node, coverageSummary) { + coverageSummary.title = this.getChildValue(node); + }, + "Abstract": function(node, coverageSummary) { + coverageSummary["abstract"] = this.getChildValue(node); + }, + "SupportedCRS": function(node, coverageSummary) { + var crs = this.getChildValue(node); + if(crs) { + if(!coverageSummary.supportedCRS) { + coverageSummary.supportedCRS = []; + } + coverageSummary.supportedCRS.push(crs); + } + }, + "SupportedFormat": function(node, coverageSummary) { + var format = this.getChildValue(node); + if(format) { + if(!coverageSummary.supportedFormat) { + coverageSummary.supportedFormat = []; + } + coverageSummary.supportedFormat.push(format); + } + } + }, OpenLayers.Format.WCSCapabilities.v1.prototype.readers["wcs"]), + "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] + }, + + CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_1_0" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WCSGetCoverage.js b/misc/openlayers/lib/OpenLayers/Format/WCSGetCoverage.js new file mode 100644 index 0000000..2817f28 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WCSGetCoverage.js @@ -0,0 +1,199 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Format/OWSCommon/v1_1_0.js + */ + +/** + * Class: OpenLayers.Format.WCSGetCoverage version 1.1.0 + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.WCSGetCoverage = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + ows: "http://www.opengis.net/ows/1.1", + wcs: "http://www.opengis.net/wcs/1.1", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance" + }, + + /** + * Property: regExes + * Compiled regular expressions for manipulating strings. + */ + regExes: { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g) + }, + + /** + * Constant: VERSION + * {String} 1.1.2 + */ + VERSION: "1.1.2", + + /** + * Property: schemaLocation + * {String} Schema location + */ + schemaLocation: "http://www.opengis.net/wcs/1.1 http://schemas.opengis.net/wcs/1.1/wcsGetCoverage.xsd", + + /** + * Constructor: OpenLayers.Format.WCSGetCoverage + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * Method: write + * + * Parameters: + * options - {Object} Optional object. + * + * Returns: + * {String} A WCS GetCoverage request XML string. + */ + write: function(options) { + var node = this.writeNode("wcs:GetCoverage", options); + this.setAttributeNS( + node, this.namespaces.xsi, + "xsi:schemaLocation", this.schemaLocation + ); + return OpenLayers.Format.XML.prototype.write.apply(this, [node]); + }, + + /** + * 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: { + "wcs": { + "GetCoverage": function(options) { + var node = this.createElementNSPlus("wcs:GetCoverage", { + attributes: { + version: options.version || this.VERSION, + service: 'WCS' + } + }); + this.writeNode("ows:Identifier", options.identifier, node); + this.writeNode("wcs:DomainSubset", options.domainSubset, node); + this.writeNode("wcs:Output", options.output, node); + return node; + }, + "DomainSubset": function(domainSubset) { + var node = this.createElementNSPlus("wcs:DomainSubset", {}); + this.writeNode("ows:BoundingBox", domainSubset.boundingBox, node); + if (domainSubset.temporalSubset) { + this.writeNode("wcs:TemporalSubset", domainSubset.temporalSubset, node); + } + return node; + }, + "TemporalSubset": function(temporalSubset) { + var node = this.createElementNSPlus("wcs:TemporalSubset", {}); + for (var i=0, len=temporalSubset.timePeriods.length; i<len; ++i) { + this.writeNode("wcs:TimePeriod", temporalSubset.timePeriods[i], node); + } + return node; + }, + "TimePeriod": function(timePeriod) { + var node = this.createElementNSPlus("wcs:TimePeriod", {}); + this.writeNode("wcs:BeginPosition", timePeriod.begin, node); + this.writeNode("wcs:EndPosition", timePeriod.end, node); + if (timePeriod.resolution) { + this.writeNode("wcs:TimeResolution", timePeriod.resolution, node); + } + return node; + }, + "BeginPosition": function(begin) { + var node = this.createElementNSPlus("wcs:BeginPosition", { + value: begin + }); + return node; + }, + "EndPosition": function(end) { + var node = this.createElementNSPlus("wcs:EndPosition", { + value: end + }); + return node; + }, + "TimeResolution": function(resolution) { + var node = this.createElementNSPlus("wcs:TimeResolution", { + value: resolution + }); + return node; + }, + "Output": function(output) { + var node = this.createElementNSPlus("wcs:Output", { + attributes: { + format: output.format, + store: output.store + } + }); + if (output.gridCRS) { + this.writeNode("wcs:GridCRS", output.gridCRS, node); + } + return node; + }, + "GridCRS": function(gridCRS) { + var node = this.createElementNSPlus("wcs:GridCRS", {}); + this.writeNode("wcs:GridBaseCRS", gridCRS.baseCRS, node); + if (gridCRS.type) { + this.writeNode("wcs:GridType", gridCRS.type, node); + } + if (gridCRS.origin) { + this.writeNode("wcs:GridOrigin", gridCRS.origin, node); + } + this.writeNode("wcs:GridOffsets", gridCRS.offsets, node); + if (gridCRS.CS) { + this.writeNode("wcs:GridCS", gridCRS.CS, node); + } + return node; + }, + "GridBaseCRS": function(baseCRS) { + return this.createElementNSPlus("wcs:GridBaseCRS", { + value: baseCRS + }); + }, + "GridOrigin": function(origin) { + return this.createElementNSPlus("wcs:GridOrigin", { + value: origin + }); + }, + "GridType": function(type) { + return this.createElementNSPlus("wcs:GridType", { + value: type + }); + }, + "GridOffsets": function(offsets) { + return this.createElementNSPlus("wcs:GridOffsets", { + value: offsets + }); + }, + "GridCS": function(CS) { + return this.createElementNSPlus("wcs:GridCS", { + value: CS + }); + } + }, + "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.writers.ows + }, + + CLASS_NAME: "OpenLayers.Format.WCSGetCoverage" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WFS.js b/misc/openlayers/lib/OpenLayers/Format/WFS.js new file mode 100644 index 0000000..44b03a3 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WFS.js @@ -0,0 +1,223 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/GML.js + * @requires OpenLayers/Console.js + * @requires OpenLayers/Lang.js + */ + +/** + * Class: OpenLayers.Format.WFS + * Read/Write WFS. + * + * Inherits from: + * - <OpenLayers.Format.GML> + */ +OpenLayers.Format.WFS = OpenLayers.Class(OpenLayers.Format.GML, { + + /** + * Property: layer + * {<OpenLayers.Layer>} + */ + layer: null, + + /** + * APIProperty: wfsns + * {String} + */ + wfsns: "http://www.opengis.net/wfs", + + /** + * Property: ogcns + * {String} + */ + ogcns: "http://www.opengis.net/ogc", + + /** + * Constructor: OpenLayers.Format.WFS + * Create a WFS-T formatter. This requires a layer: that layer should + * have two properties: geometry_column and typename. The parser + * for this format is subclassed entirely from GML: There is a writer + * only, which uses most of the code from the GML layer, and wraps + * it in transactional elements. + * + * Parameters: + * options - {Object} + * layer - {<OpenLayers.Layer>} + */ + initialize: function(options, layer) { + OpenLayers.Format.GML.prototype.initialize.apply(this, [options]); + this.layer = layer; + if (this.layer.featureNS) { + this.featureNS = this.layer.featureNS; + } + if (this.layer.options.geometry_column) { + this.geometryName = this.layer.options.geometry_column; + } + if (this.layer.options.typename) { + this.featureName = this.layer.options.typename; + } + }, + + /** + * Method: write + * Takes a feature list, and generates a WFS-T Transaction + * + * Parameters: + * features - {Array(<OpenLayers.Feature.Vector>)} + */ + write: function(features) { + + var transaction = this.createElementNS(this.wfsns, 'wfs:Transaction'); + transaction.setAttribute("version","1.0.0"); + transaction.setAttribute("service","WFS"); + for (var i=0; i < features.length; i++) { + switch (features[i].state) { + case OpenLayers.State.INSERT: + transaction.appendChild(this.insert(features[i])); + break; + case OpenLayers.State.UPDATE: + transaction.appendChild(this.update(features[i])); + break; + case OpenLayers.State.DELETE: + transaction.appendChild(this.remove(features[i])); + break; + } + } + + return OpenLayers.Format.XML.prototype.write.apply(this,[transaction]); + }, + + /** + * Method: createFeatureXML + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} + */ + createFeatureXML: function(feature) { + var geometryNode = this.buildGeometryNode(feature.geometry); + var geomContainer = this.createElementNS(this.featureNS, "feature:" + this.geometryName); + geomContainer.appendChild(geometryNode); + var featureContainer = this.createElementNS(this.featureNS, "feature:" + this.featureName); + featureContainer.appendChild(geomContainer); + for(var attr in feature.attributes) { + var attrText = this.createTextNode(feature.attributes[attr]); + var nodename = attr; + if (attr.search(":") != -1) { + nodename = attr.split(":")[1]; + } + var attrContainer = this.createElementNS(this.featureNS, "feature:" + nodename); + attrContainer.appendChild(attrText); + featureContainer.appendChild(attrContainer); + } + return featureContainer; + }, + + /** + * Method: insert + * Takes a feature, and generates a WFS-T Transaction "Insert" + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} + */ + insert: function(feature) { + var insertNode = this.createElementNS(this.wfsns, 'wfs:Insert'); + insertNode.appendChild(this.createFeatureXML(feature)); + return insertNode; + }, + + /** + * Method: update + * Takes a feature, and generates a WFS-T Transaction "Update" + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} + */ + update: function(feature) { + if (!feature.fid) { OpenLayers.Console.userError(OpenLayers.i18n("noFID")); } + var updateNode = this.createElementNS(this.wfsns, 'wfs:Update'); + updateNode.setAttribute("typeName", this.featurePrefix + ':' + this.featureName); + updateNode.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); + + var propertyNode = this.createElementNS(this.wfsns, 'wfs:Property'); + var nameNode = this.createElementNS(this.wfsns, 'wfs:Name'); + + var txtNode = this.createTextNode(this.geometryName); + nameNode.appendChild(txtNode); + propertyNode.appendChild(nameNode); + + var valueNode = this.createElementNS(this.wfsns, 'wfs:Value'); + + var geometryNode = this.buildGeometryNode(feature.geometry); + + if(feature.layer){ + geometryNode.setAttribute( + "srsName", feature.layer.projection.getCode() + ); + } + + valueNode.appendChild(geometryNode); + + propertyNode.appendChild(valueNode); + updateNode.appendChild(propertyNode); + + // add in attributes + for(var propName in feature.attributes) { + propertyNode = this.createElementNS(this.wfsns, 'wfs:Property'); + nameNode = this.createElementNS(this.wfsns, 'wfs:Name'); + nameNode.appendChild(this.createTextNode(propName)); + propertyNode.appendChild(nameNode); + valueNode = this.createElementNS(this.wfsns, 'wfs:Value'); + valueNode.appendChild(this.createTextNode(feature.attributes[propName])); + propertyNode.appendChild(valueNode); + updateNode.appendChild(propertyNode); + } + + + var filterNode = this.createElementNS(this.ogcns, 'ogc:Filter'); + var filterIdNode = this.createElementNS(this.ogcns, 'ogc:FeatureId'); + filterIdNode.setAttribute("fid", feature.fid); + filterNode.appendChild(filterIdNode); + updateNode.appendChild(filterNode); + + return updateNode; + }, + + /** + * Method: remove + * Takes a feature, and generates a WFS-T Transaction "Delete" + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} + */ + remove: function(feature) { + if (!feature.fid) { + OpenLayers.Console.userError(OpenLayers.i18n("noFID")); + return false; + } + var deleteNode = this.createElementNS(this.wfsns, 'wfs:Delete'); + deleteNode.setAttribute("typeName", this.featurePrefix + ':' + this.featureName); + deleteNode.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); + + var filterNode = this.createElementNS(this.ogcns, 'ogc:Filter'); + var filterIdNode = this.createElementNS(this.ogcns, 'ogc:FeatureId'); + filterIdNode.setAttribute("fid", feature.fid); + filterNode.appendChild(filterIdNode); + deleteNode.appendChild(filterNode); + + return deleteNode; + }, + + /** + * APIMethod: destroy + * Remove ciruclar ref to layer + */ + destroy: function() { + this.layer = null; + }, + + CLASS_NAME: "OpenLayers.Format.WFS" +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WFSCapabilities.js b/misc/openlayers/lib/OpenLayers/Format/WFSCapabilities.js new file mode 100644 index 0000000..61af085 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WFSCapabilities.js @@ -0,0 +1,47 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML/VersionedOGC.js + */ + +/** + * Class: OpenLayers.Format.WFSCapabilities + * Read WFS Capabilities. + * + * Inherits from: + * - <OpenLayers.Format.XML.VersionedOGC> + */ +OpenLayers.Format.WFSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { + + /** + * APIProperty: defaultVersion + * {String} Version number to assume if none found. Default is "1.1.0". + */ + defaultVersion: "1.1.0", + + /** + * Constructor: OpenLayers.Format.WFSCapabilities + * Create a new parser for WFS capabilities. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Read capabilities data from a string, and return a list of layers. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array} List of named layers. + */ + + CLASS_NAME: "OpenLayers.Format.WFSCapabilities" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WFSCapabilities/v1.js b/misc/openlayers/lib/OpenLayers/Format/WFSCapabilities/v1.js new file mode 100644 index 0000000..c4ec517 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WFSCapabilities/v1.js @@ -0,0 +1,129 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WFSCapabilities.js + */ + +/** + * Class: OpenLayers.Format.WFSCapabilities.v1 + * Abstract class not to be instantiated directly. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.WFSCapabilities.v1 = OpenLayers.Class( + OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + wfs: "http://www.opengis.net/wfs", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance", + ows: "http://www.opengis.net/ows" + }, + + + /** + * APIProperty: errorProperty + * {String} Which property of the returned object to check for in order to + * determine whether or not parsing has failed. In the case that the + * errorProperty is undefined on the returned object, the document will be + * run through an OGCExceptionReport parser. + */ + errorProperty: "featureTypeList", + + /** + * Property: defaultPrefix + */ + defaultPrefix: "wfs", + + /** + * Constructor: OpenLayers.Format.WFSCapabilities.v1_1 + * Create an instance of one of the subclasses. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Read capabilities data from a string, and return a list of layers. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array} List of named layers. + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + var raw = data; + if(data && data.nodeType == 9) { + data = data.documentElement; + } + var capabilities = {}; + this.readNode(data, capabilities); + return capabilities; + }, + + /** + * 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: { + "wfs": { + "WFS_Capabilities": function(node, obj) { + this.readChildNodes(node, obj); + }, + "FeatureTypeList": function(node, request) { + request.featureTypeList = { + featureTypes: [] + }; + this.readChildNodes(node, request.featureTypeList); + }, + "FeatureType": function(node, featureTypeList) { + var featureType = {}; + this.readChildNodes(node, featureType); + featureTypeList.featureTypes.push(featureType); + }, + "Name": function(node, obj) { + var name = this.getChildValue(node); + if(name) { + var parts = name.split(":"); + obj.name = parts.pop(); + if(parts.length > 0) { + obj.featureNS = this.lookupNamespaceURI(node, parts[0]); + } + } + }, + "Title": function(node, obj) { + var title = this.getChildValue(node); + if(title) { + obj.title = title; + } + }, + "Abstract": function(node, obj) { + var abst = this.getChildValue(node); + if(abst) { + obj["abstract"] = abst; + } + } + } + }, + + CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WFSCapabilities/v1_0_0.js b/misc/openlayers/lib/OpenLayers/Format/WFSCapabilities/v1_0_0.js new file mode 100644 index 0000000..6b202c7 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WFSCapabilities/v1_0_0.js @@ -0,0 +1,115 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WFSCapabilities/v1.js + */ + +/** + * Class: OpenLayers.Format.WFSCapabilities/v1_0_0 + * Read WFS Capabilities version 1.0.0. + * + * Inherits from: + * - <OpenLayers.Format.WFSCapabilities.v1> + */ +OpenLayers.Format.WFSCapabilities.v1_0_0 = OpenLayers.Class( + OpenLayers.Format.WFSCapabilities.v1, { + + /** + * Constructor: OpenLayers.Format.WFSCapabilities.v1_0_0 + * Create a new parser for WFS capabilities 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: { + "wfs": OpenLayers.Util.applyDefaults({ + "Service": function(node, capabilities) { + capabilities.service = {}; + this.readChildNodes(node, capabilities.service); + }, + "Fees": function(node, service) { + var fees = this.getChildValue(node); + if (fees && fees.toLowerCase() != "none") { + service.fees = fees; + } + }, + "AccessConstraints": function(node, service) { + var constraints = this.getChildValue(node); + if (constraints && constraints.toLowerCase() != "none") { + service.accessConstraints = constraints; + } + }, + "OnlineResource": function(node, service) { + var onlineResource = this.getChildValue(node); + if (onlineResource && onlineResource.toLowerCase() != "none") { + service.onlineResource = onlineResource; + } + }, + "Keywords": function(node, service) { + var keywords = this.getChildValue(node); + if (keywords && keywords.toLowerCase() != "none") { + service.keywords = keywords.split(', '); + } + }, + "Capability": function(node, capabilities) { + capabilities.capability = {}; + this.readChildNodes(node, capabilities.capability); + }, + "Request": function(node, obj) { + obj.request = {}; + this.readChildNodes(node, obj.request); + }, + "GetFeature": function(node, request) { + request.getfeature = { + href: {}, // DCPType + formats: [] // ResultFormat + }; + this.readChildNodes(node, request.getfeature); + }, + "ResultFormat": function(node, obj) { + var children = node.childNodes; + var childNode; + for(var i=0; i<children.length; i++) { + childNode = children[i]; + if(childNode.nodeType == 1) { + obj.formats.push(childNode.nodeName); + } + } + }, + "DCPType": function(node, obj) { + this.readChildNodes(node, obj); + }, + "HTTP": function(node, obj) { + this.readChildNodes(node, obj.href); + }, + "Get": function(node, obj) { + obj.get = node.getAttribute("onlineResource"); + }, + "Post": function(node, obj) { + obj.post = node.getAttribute("onlineResource"); + }, + "SRS": function(node, obj) { + var srs = this.getChildValue(node); + if (srs) { + obj.srs = srs; + } + } + }, OpenLayers.Format.WFSCapabilities.v1.prototype.readers["wfs"]) + }, + + CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_0_0" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WFSCapabilities/v1_1_0.js b/misc/openlayers/lib/OpenLayers/Format/WFSCapabilities/v1_1_0.js new file mode 100644 index 0000000..84f6b4b --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WFSCapabilities/v1_1_0.js @@ -0,0 +1,63 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WFSCapabilities/v1.js + * @requires OpenLayers/Format/OWSCommon/v1.js + */ + +/** + * Class: OpenLayers.Format.WFSCapabilities/v1_1_0 + * Read WFS Capabilities version 1.1.0. + * + * Inherits from: + * - <OpenLayers.Format.WFSCapabilities> + */ +OpenLayers.Format.WFSCapabilities.v1_1_0 = OpenLayers.Class( + OpenLayers.Format.WFSCapabilities.v1, { + + /** + * Property: regExes + * Compiled regular expressions for manipulating strings. + */ + regExes: { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g) + }, + + /** + * Constructor: OpenLayers.Format.WFSCapabilities.v1_1_0 + * Create a new parser for WFS capabilities version 1.1.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: { + "wfs": OpenLayers.Util.applyDefaults({ + "DefaultSRS": function(node, obj) { + var defaultSRS = this.getChildValue(node); + if (defaultSRS) { + obj.srs = defaultSRS; + } + } + }, OpenLayers.Format.WFSCapabilities.v1.prototype.readers["wfs"]), + "ows": OpenLayers.Format.OWSCommon.v1.prototype.readers.ows + }, + + CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_1_0" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WFSDescribeFeatureType.js b/misc/openlayers/lib/OpenLayers/Format/WFSDescribeFeatureType.js new file mode 100644 index 0000000..416e845 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WFSDescribeFeatureType.js @@ -0,0 +1,234 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Format/OGCExceptionReport.js + */ + +/** + * Class: OpenLayers.Format.WFSDescribeFeatureType + * Read WFS DescribeFeatureType response + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.WFSDescribeFeatureType = OpenLayers.Class( + OpenLayers.Format.XML, { + + /** + * Property: regExes + * Compiled regular expressions for manipulating strings. + */ + regExes: { + trimSpace: (/^\s*|\s*$/g) + }, + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + xsd: "http://www.w3.org/2001/XMLSchema" + }, + + /** + * Constructor: OpenLayers.Format.WFSDescribeFeatureType + * Create a new parser for WFS DescribeFeatureType responses. + * + * 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: { + "xsd": { + "schema": function(node, obj) { + var complexTypes = []; + var customTypes = {}; + var schema = { + complexTypes: complexTypes, + customTypes: customTypes + }; + var i, len; + + this.readChildNodes(node, schema); + + var attributes = node.attributes; + var attr, name; + for(i=0, len=attributes.length; i<len; ++i) { + attr = attributes[i]; + name = attr.name; + if(name.indexOf("xmlns") === 0) { + this.setNamespace(name.split(":")[1] || "", attr.value); + } else { + obj[name] = attr.value; + } + } + obj.featureTypes = complexTypes; + obj.targetPrefix = this.namespaceAlias[obj.targetNamespace]; + + // map complexTypes to names of customTypes + var complexType, customType; + for(i=0, len=complexTypes.length; i<len; ++i) { + complexType = complexTypes[i]; + customType = customTypes[complexType.typeName]; + if(customTypes[complexType.typeName]) { + complexType.typeName = customType.name; + } + } + }, + "complexType": function(node, obj) { + var complexType = { + // this is a temporary typeName, it will be overwritten by + // the schema reader with the metadata found in the + // customTypes hash + "typeName": node.getAttribute("name") + }; + this.readChildNodes(node, complexType); + obj.complexTypes.push(complexType); + }, + "complexContent": function(node, obj) { + this.readChildNodes(node, obj); + }, + "extension": function(node, obj) { + this.readChildNodes(node, obj); + }, + "sequence": function(node, obj) { + var sequence = { + elements: [] + }; + this.readChildNodes(node, sequence); + obj.properties = sequence.elements; + }, + "element": function(node, obj) { + var type; + if(obj.elements) { + var element = {}; + var attributes = node.attributes; + var attr; + for(var i=0, len=attributes.length; i<len; ++i) { + attr = attributes[i]; + element[attr.name] = attr.value; + } + + type = element.type; + if(!type) { + type = {}; + this.readChildNodes(node, type); + element.restriction = type; + element.type = type.base; + } + var fullType = type.base || type; + element.localType = fullType.split(":").pop(); + obj.elements.push(element); + this.readChildNodes(node, element); + } + + if(obj.complexTypes) { + type = node.getAttribute("type"); + var localType = type.split(":").pop(); + obj.customTypes[localType] = { + "name": node.getAttribute("name"), + "type": type + }; + } + }, + "annotation": function(node, obj) { + obj.annotation = {}; + this.readChildNodes(node, obj.annotation); + }, + "appinfo": function(node, obj) { + if (!obj.appinfo) { + obj.appinfo = []; + } + obj.appinfo.push(this.getChildValue(node)); + }, + "documentation": function(node, obj) { + if (!obj.documentation) { + obj.documentation = []; + } + var value = this.getChildValue(node); + obj.documentation.push({ + lang: node.getAttribute("xml:lang"), + textContent: value.replace(this.regExes.trimSpace, "") + }); + }, + "simpleType": function(node, obj) { + this.readChildNodes(node, obj); + }, + "restriction": function(node, obj) { + obj.base = node.getAttribute("base"); + this.readRestriction(node, obj); + } + } + }, + + /** + * Method: readRestriction + * Reads restriction defined in the child nodes of a restriction element + * + * Parameters: + * node - {DOMElement} the node to parse + * obj - {Object} the object that receives the read result + */ + readRestriction: function(node, obj) { + var children = node.childNodes; + var child, nodeName, value; + for(var i=0, len=children.length; i<len; ++i) { + child = children[i]; + if(child.nodeType == 1) { + nodeName = child.nodeName.split(":").pop(); + value = child.getAttribute("value"); + if(!obj[nodeName]) { + obj[nodeName] = value; + } else { + if(typeof obj[nodeName] == "string") { + obj[nodeName] = [obj[nodeName]]; + } + obj[nodeName].push(value); + } + } + } + }, + + /** + * Method: read + * + * Parameters: + * data - {DOMElement|String} A WFS DescribeFeatureType document. + * + * Returns: + * {Object} An object representing the WFS DescribeFeatureType response. + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + if(data && data.nodeType == 9) { + data = data.documentElement; + } + var schema = {}; + if (data.nodeName.split(":").pop() === 'ExceptionReport') { + // an exception must have occurred, so parse it + var parser = new OpenLayers.Format.OGCExceptionReport(); + schema.error = parser.read(data); + } else { + this.readNode(data, schema); + } + return schema; + }, + + CLASS_NAME: "OpenLayers.Format.WFSDescribeFeatureType" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WFST.js b/misc/openlayers/lib/OpenLayers/Format/WFST.js new file mode 100644 index 0000000..eb3d9d9 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WFST.js @@ -0,0 +1,34 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format.js + */ + +/** + * Function: OpenLayers.Format.WFST + * Used to create a versioned WFS protocol. Default version is 1.0.0. + * + * Returns: + * {<OpenLayers.Format>} A WFST format of the given version. + */ +OpenLayers.Format.WFST = function(options) { + options = OpenLayers.Util.applyDefaults( + options, OpenLayers.Format.WFST.DEFAULTS + ); + var cls = OpenLayers.Format.WFST["v"+options.version.replace(/\./g, "_")]; + if(!cls) { + throw "Unsupported WFST version: " + options.version; + } + return new cls(options); +}; + +/** + * Constant: OpenLayers.Format.WFST.DEFAULTS + * {Object} Default properties for the WFST format. + */ +OpenLayers.Format.WFST.DEFAULTS = { + "version": "1.0.0" +}; diff --git a/misc/openlayers/lib/OpenLayers/Format/WFST/v1.js b/misc/openlayers/lib/OpenLayers/Format/WFST/v1.js new file mode 100644 index 0000000..306ba6f --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WFST/v1.js @@ -0,0 +1,446 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Format/WFST.js + * @requires OpenLayers/Filter/Spatial.js + * @requires OpenLayers/Filter/FeatureId.js + */ + +/** + * Class: OpenLayers.Format.WFST.v1 + * Superclass for WFST parsers. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.WFST.v1 = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance", + wfs: "http://www.opengis.net/wfs", + gml: "http://www.opengis.net/gml", + ogc: "http://www.opengis.net/ogc", + ows: "http://www.opengis.net/ows" + }, + + /** + * Property: defaultPrefix + */ + defaultPrefix: "wfs", + + /** + * Property: version + * {String} WFS version number. + */ + version: null, + + /** + * Property: schemaLocation + * {String} Schema location for a particular minor version. + */ + schemaLocations: null, + + /** + * APIProperty: srsName + * {String} URI for spatial reference system. + */ + srsName: null, + + /** + * APIProperty: extractAttributes + * {Boolean} Extract attributes from GML. Default is true. + */ + extractAttributes: true, + + /** + * APIProperty: xy + * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x) + * Changing is not recommended, a new Format should be instantiated. + */ + xy: true, + + /** + * Property: stateName + * {Object} Maps feature states to node names. + */ + stateName: null, + + /** + * Constructor: OpenLayers.Format.WFST.v1 + * Instances of this class are not created directly. Use the + * <OpenLayers.Format.WFST.v1_0_0> or <OpenLayers.Format.WFST.v1_1_0> + * constructor instead. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + // set state name mapping + this.stateName = {}; + this.stateName[OpenLayers.State.INSERT] = "wfs:Insert"; + this.stateName[OpenLayers.State.UPDATE] = "wfs:Update"; + this.stateName[OpenLayers.State.DELETE] = "wfs:Delete"; + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); + }, + + /** + * Method: getSrsName + */ + getSrsName: function(feature, options) { + var srsName = options && options.srsName; + if(!srsName) { + if(feature && feature.layer) { + srsName = feature.layer.projection.getCode(); + } else { + srsName = this.srsName; + } + } + return srsName; + }, + + /** + * APIMethod: read + * Parse the response from a transaction. Because WFS is split into + * Transaction requests (create, update, and delete) and GetFeature + * requests (read), this method handles parsing of both types of + * responses. + * + * Parameters: + * data - {String | Document} The WFST document to read + * options - {Object} Options for the reader + * + * Valid options properties: + * output - {String} either "features" or "object". The default is + * "features", which means that the method will return an array of + * features. If set to "object", an object with a "features" property + * and other properties read by the parser will be returned. + * + * Returns: + * {Array | Object} Output depending on the output option. + */ + read: function(data, options) { + options = options || {}; + OpenLayers.Util.applyDefaults(options, { + output: "features" + }); + + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + if(data && data.nodeType == 9) { + data = data.documentElement; + } + var obj = {}; + if(data) { + this.readNode(data, obj, true); + } + if(obj.features && options.output === "features") { + obj = obj.features; + } + return obj; + }, + + /** + * 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: { + "wfs": { + "FeatureCollection": function(node, obj) { + obj.features = []; + this.readChildNodes(node, obj); + } + } + }, + + /** + * Method: write + * Given an array of features, write a WFS transaction. This assumes + * the features have a state property that determines the operation + * type - insert, update, or delete. + * + * Parameters: + * features - {Array(<OpenLayers.Feature.Vector>)} A list of features. See + * below for a more detailed description of the influence of the + * feature's *modified* property. + * options - {Object} + * + * feature.modified rules: + * If a feature has a modified property set, the following checks will be + * made before a feature's geometry or attribute is included in an Update + * transaction: + * - *modified* is not set at all: The geometry and all attributes will be + * included. + * - *modified.geometry* is set (null or a geometry): The geometry will be + * included. If *modified.attributes* is not set, all attributes will + * be included. + * - *modified.attributes* is set: Only the attributes set (i.e. to null or + * a value) in *modified.attributes* will be included. + * If *modified.geometry* is not set, the geometry will not be included. + * + * Valid options include: + * - *multi* {Boolean} If set to true, geometries will be casted to + * Multi geometries before writing. + * + * Returns: + * {String} A serialized WFS transaction. + */ + write: function(features, options) { + var node = this.writeNode("wfs:Transaction", { + features:features, + options: options + }); + var value = this.schemaLocationAttr(); + if(value) { + this.setAttributeNS( + node, this.namespaces["xsi"], "xsi:schemaLocation", value + ); + } + return OpenLayers.Format.XML.prototype.write.apply(this, [node]); + }, + + /** + * 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: { + "wfs": { + "GetFeature": function(options) { + var node = this.createElementNSPlus("wfs:GetFeature", { + attributes: { + service: "WFS", + version: this.version, + handle: options && options.handle, + outputFormat: options && options.outputFormat, + maxFeatures: options && options.maxFeatures, + "xsi:schemaLocation": this.schemaLocationAttr(options) + } + }); + if (typeof this.featureType == "string") { + this.writeNode("Query", options, node); + } else { + for (var i=0,len = this.featureType.length; i<len; i++) { + options.featureType = this.featureType[i]; + this.writeNode("Query", options, node); + } + } + return node; + }, + "Transaction": function(obj) { + obj = obj || {}; + var options = obj.options || {}; + var node = this.createElementNSPlus("wfs:Transaction", { + attributes: { + service: "WFS", + version: this.version, + handle: options.handle + } + }); + var i, len; + var features = obj.features; + if(features) { + // temporarily re-assigning geometry types + if (options.multi === true) { + OpenLayers.Util.extend(this.geometryTypes, { + "OpenLayers.Geometry.Point": "MultiPoint", + "OpenLayers.Geometry.LineString": (this.multiCurve === true) ? "MultiCurve": "MultiLineString", + "OpenLayers.Geometry.Polygon": (this.multiSurface === true) ? "MultiSurface" : "MultiPolygon" + }); + } + var name, feature; + for(i=0, len=features.length; i<len; ++i) { + feature = features[i]; + name = this.stateName[feature.state]; + if(name) { + this.writeNode(name, { + feature: feature, + options: options + }, node); + } + } + // switch back to original geometry types assignment + if (options.multi === true) { + this.setGeometryTypes(); + } + } + if (options.nativeElements) { + for (i=0, len=options.nativeElements.length; i<len; ++i) { + this.writeNode("wfs:Native", + options.nativeElements[i], node); + } + } + return node; + }, + "Native": function(nativeElement) { + var node = this.createElementNSPlus("wfs:Native", { + attributes: { + vendorId: nativeElement.vendorId, + safeToIgnore: nativeElement.safeToIgnore + }, + value: nativeElement.value + }); + return node; + }, + "Insert": function(obj) { + var feature = obj.feature; + var options = obj.options; + var node = this.createElementNSPlus("wfs:Insert", { + attributes: { + handle: options && options.handle + } + }); + this.srsName = this.getSrsName(feature); + this.writeNode("feature:_typeName", feature, node); + return node; + }, + "Update": function(obj) { + var feature = obj.feature; + var options = obj.options; + var node = this.createElementNSPlus("wfs:Update", { + attributes: { + handle: options && options.handle, + typeName: (this.featureNS ? this.featurePrefix + ":" : "") + + this.featureType + } + }); + if(this.featureNS) { + node.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); + } + + // add in geometry + var modified = feature.modified; + if (this.geometryName !== null && (!modified || modified.geometry !== undefined)) { + this.srsName = this.getSrsName(feature); + this.writeNode( + "Property", {name: this.geometryName, value: feature.geometry}, node + ); + } + + // add in attributes + for(var key in feature.attributes) { + if(feature.attributes[key] !== undefined && + (!modified || !modified.attributes || + (modified.attributes && modified.attributes[key] !== undefined))) { + this.writeNode( + "Property", {name: key, value: feature.attributes[key]}, node + ); + } + } + + // add feature id filter + this.writeNode("ogc:Filter", new OpenLayers.Filter.FeatureId({ + fids: [feature.fid] + }), node); + + return node; + }, + "Property": function(obj) { + var node = this.createElementNSPlus("wfs:Property"); + this.writeNode("Name", obj.name, node); + if(obj.value !== null) { + this.writeNode("Value", obj.value, node); + } + return node; + }, + "Name": function(name) { + return this.createElementNSPlus("wfs:Name", {value: name}); + }, + "Value": function(obj) { + var node; + if(obj instanceof OpenLayers.Geometry) { + node = this.createElementNSPlus("wfs:Value"); + var geom = this.writeNode("feature:_geometry", obj).firstChild; + node.appendChild(geom); + } else { + node = this.createElementNSPlus("wfs:Value", {value: obj}); + } + return node; + }, + "Delete": function(obj) { + var feature = obj.feature; + var options = obj.options; + var node = this.createElementNSPlus("wfs:Delete", { + attributes: { + handle: options && options.handle, + typeName: (this.featureNS ? this.featurePrefix + ":" : "") + + this.featureType + } + }); + if(this.featureNS) { + node.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); + } + this.writeNode("ogc:Filter", new OpenLayers.Filter.FeatureId({ + fids: [feature.fid] + }), node); + return node; + } + } + }, + + /** + * Method: schemaLocationAttr + * Generate the xsi:schemaLocation attribute value. + * + * Returns: + * {String} The xsi:schemaLocation attribute or undefined if none. + */ + schemaLocationAttr: function(options) { + options = OpenLayers.Util.extend({ + featurePrefix: this.featurePrefix, + schema: this.schema + }, options); + var schemaLocations = OpenLayers.Util.extend({}, this.schemaLocations); + if(options.schema) { + schemaLocations[options.featurePrefix] = options.schema; + } + var parts = []; + var uri; + for(var key in schemaLocations) { + uri = this.namespaces[key]; + if(uri) { + parts.push(uri + " " + schemaLocations[key]); + } + } + var value = parts.join(" ") || undefined; + return value; + }, + + /** + * Method: setFilterProperty + * Set the property of each spatial filter. + * + * Parameters: + * filter - {<OpenLayers.Filter>} + */ + setFilterProperty: function(filter) { + if(filter.filters) { + for(var i=0, len=filter.filters.length; i<len; ++i) { + OpenLayers.Format.WFST.v1.prototype.setFilterProperty.call(this, filter.filters[i]); + } + } else { + if(filter instanceof OpenLayers.Filter.Spatial && !filter.property) { + // got a spatial filter without property, so set it + filter.property = this.geometryName; + } + } + }, + + CLASS_NAME: "OpenLayers.Format.WFST.v1" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WFST/v1_0_0.js b/misc/openlayers/lib/OpenLayers/Format/WFST/v1_0_0.js new file mode 100644 index 0000000..ed81a2d --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WFST/v1_0_0.js @@ -0,0 +1,174 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WFST/v1.js + * @requires OpenLayers/Format/Filter/v1_0_0.js + */ + +/** + * Class: OpenLayers.Format.WFST.v1_0_0 + * A format for creating WFS v1.0.0 transactions. Create a new instance with the + * <OpenLayers.Format.WFST.v1_0_0> constructor. + * + * Inherits from: + * - <OpenLayers.Format.Filter.v1_0_0> + * - <OpenLayers.Format.WFST.v1> + */ +OpenLayers.Format.WFST.v1_0_0 = OpenLayers.Class( + OpenLayers.Format.Filter.v1_0_0, OpenLayers.Format.WFST.v1, { + + /** + * Property: version + * {String} WFS version number. + */ + version: "1.0.0", + + /** + * APIProperty: srsNameInQuery + * {Boolean} If true the reference system is passed in Query requests + * via the "srsName" attribute to the "wfs:Query" element, this + * property defaults to false as it isn't WFS 1.0.0 compliant. + */ + srsNameInQuery: false, + + /** + * Property: schemaLocations + * {Object} Properties are namespace aliases, values are schema locations. + */ + schemaLocations: { + "wfs": "http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd" + }, + + /** + * Constructor: OpenLayers.Format.WFST.v1_0_0 + * A class for parsing and generating WFS v1.0.0 transactions. + * + * Parameters: + * options - {Object} Optional object whose properties will be set on the + * instance. + * + * Valid options properties: + * featureType - {String} Local (without prefix) feature typeName (required). + * featureNS - {String} Feature namespace (optional). + * featurePrefix - {String} Feature namespace alias (optional - only used + * if featureNS is provided). Default is 'feature'. + * geometryName - {String} Name of geometry attribute. Default is 'the_geom'. + */ + initialize: function(options) { + OpenLayers.Format.Filter.v1_0_0.prototype.initialize.apply(this, [options]); + OpenLayers.Format.WFST.v1.prototype.initialize.apply(this, [options]); + }, + + /** + * Method: readNode + * Shorthand for applying one of the named readers given the node + * namespace and local name. Readers take two args (node, obj) and + * generally extend or modify the second. + * + * Parameters: + * node - {DOMElement} The node to be read (required). + * obj - {Object} The object to be modified (optional). + * first - {Boolean} Should be set to true for the first node read. This + * is usually the readNode call in the read method. Without this being + * set, auto-configured properties will stick on subsequent reads. + * + * Returns: + * {Object} The input object, modified (or a new one if none was provided). + */ + readNode: function(node, obj, first) { + // Not the superclass, only the mixin classes inherit from + // Format.GML.v2. We need this because we don't want to get readNode + // from the superclass's superclass, which is OpenLayers.Format.XML. + return OpenLayers.Format.GML.v2.prototype.readNode.apply(this, arguments); + }, + + /** + * 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: { + "wfs": OpenLayers.Util.applyDefaults({ + "WFS_TransactionResponse": function(node, obj) { + obj.insertIds = []; + obj.success = false; + this.readChildNodes(node, obj); + }, + "InsertResult": function(node, container) { + var obj = {fids: []}; + this.readChildNodes(node, obj); + container.insertIds = container.insertIds.concat(obj.fids); + }, + "TransactionResult": function(node, obj) { + this.readChildNodes(node, obj); + }, + "Status": function(node, obj) { + this.readChildNodes(node, obj); + }, + "SUCCESS": function(node, obj) { + obj.success = true; + } + }, OpenLayers.Format.WFST.v1.prototype.readers["wfs"]), + "gml": OpenLayers.Format.GML.v2.prototype.readers["gml"], + "feature": OpenLayers.Format.GML.v2.prototype.readers["feature"], + "ogc": OpenLayers.Format.Filter.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: { + "wfs": OpenLayers.Util.applyDefaults({ + "Query": function(options) { + options = OpenLayers.Util.extend({ + featureNS: this.featureNS, + featurePrefix: this.featurePrefix, + featureType: this.featureType, + srsName: this.srsName, + srsNameInQuery: this.srsNameInQuery + }, options); + var prefix = options.featurePrefix; + var node = this.createElementNSPlus("wfs:Query", { + attributes: { + typeName: (prefix ? prefix + ":" : "") + + options.featureType + } + }); + if(options.srsNameInQuery && options.srsName) { + node.setAttribute("srsName", options.srsName); + } + if(options.featureNS) { + node.setAttribute("xmlns:" + prefix, options.featureNS); + } + if(options.propertyNames) { + for(var i=0,len = options.propertyNames.length; i<len; i++) { + this.writeNode( + "ogc:PropertyName", + {property: options.propertyNames[i]}, + node + ); + } + } + if(options.filter) { + this.setFilterProperty(options.filter); + this.writeNode("ogc:Filter", options.filter, node); + } + return node; + } + }, OpenLayers.Format.WFST.v1.prototype.writers["wfs"]), + "gml": OpenLayers.Format.GML.v2.prototype.writers["gml"], + "feature": OpenLayers.Format.GML.v2.prototype.writers["feature"], + "ogc": OpenLayers.Format.Filter.v1_0_0.prototype.writers["ogc"] + }, + + CLASS_NAME: "OpenLayers.Format.WFST.v1_0_0" +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WFST/v1_1_0.js b/misc/openlayers/lib/OpenLayers/Format/WFST/v1_1_0.js new file mode 100644 index 0000000..ff2a88d --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WFST/v1_1_0.js @@ -0,0 +1,189 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WFST/v1.js + * @requires OpenLayers/Format/Filter/v1_1_0.js + * @requires OpenLayers/Format/OWSCommon/v1_0_0.js + */ + +/** + * Class: OpenLayers.Format.WFST.v1_1_0 + * A format for creating WFS v1.1.0 transactions. Create a new instance with the + * <OpenLayers.Format.WFST.v1_1_0> constructor. + * + * Inherits from: + * - <OpenLayers.Format.Filter.v1_1_0> + * - <OpenLayers.Format.WFST.v1> + */ +OpenLayers.Format.WFST.v1_1_0 = OpenLayers.Class( + OpenLayers.Format.Filter.v1_1_0, OpenLayers.Format.WFST.v1, { + + /** + * Property: version + * {String} WFS version number. + */ + version: "1.1.0", + + /** + * Property: schemaLocations + * {Object} Properties are namespace aliases, values are schema locations. + */ + schemaLocations: { + "wfs": "http://schemas.opengis.net/wfs/1.1.0/wfs.xsd" + }, + + /** + * Constructor: OpenLayers.Format.WFST.v1_1_0 + * A class for parsing and generating WFS v1.1.0 transactions. + * + * To read additional information like hit count (numberOfFeatures) from + * the FeatureCollection, call the <OpenLayers.Format.WFST.v1.read> method + * with {output: "object"} as 2nd argument. Note that it is possible to + * just request the hit count from a WFS 1.1.0 server with the + * resultType="hits" request parameter. + * + * Parameters: + * options - {Object} Optional object whose properties will be set on the + * instance. + * + * Valid options properties: + * featureType - {String} Local (without prefix) feature typeName (required). + * featureNS - {String} Feature namespace (optional). + * featurePrefix - {String} Feature namespace alias (optional - only used + * if featureNS is provided). Default is 'feature'. + * geometryName - {String} Name of geometry attribute. Default is 'the_geom'. + */ + initialize: function(options) { + OpenLayers.Format.Filter.v1_1_0.prototype.initialize.apply(this, [options]); + OpenLayers.Format.WFST.v1.prototype.initialize.apply(this, [options]); + }, + + /** + * Method: readNode + * Shorthand for applying one of the named readers given the node + * namespace and local name. Readers take two args (node, obj) and + * generally extend or modify the second. + * + * Parameters: + * node - {DOMElement} The node to be read (required). + * obj - {Object} The object to be modified (optional). + * first - {Boolean} Should be set to true for the first node read. This + * is usually the readNode call in the read method. Without this being + * set, auto-configured properties will stick on subsequent reads. + * + * Returns: + * {Object} The input object, modified (or a new one if none was provided). + */ + readNode: function(node, obj, first) { + // Not the superclass, only the mixin classes inherit from + // Format.GML.v3. We need this because we don't want to get readNode + // from the superclass's superclass, which is OpenLayers.Format.XML. + return OpenLayers.Format.GML.v3.prototype.readNode.apply(this, arguments); + }, + + /** + * 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: { + "wfs": OpenLayers.Util.applyDefaults({ + "FeatureCollection": function(node, obj) { + obj.numberOfFeatures = parseInt(node.getAttribute( + "numberOfFeatures")); + OpenLayers.Format.WFST.v1.prototype.readers["wfs"]["FeatureCollection"].apply( + this, arguments); + }, + "TransactionResponse": function(node, obj) { + obj.insertIds = []; + obj.success = false; + this.readChildNodes(node, obj); + }, + "TransactionSummary": function(node, obj) { + // this is a limited test of success + obj.success = true; + }, + "InsertResults": function(node, obj) { + this.readChildNodes(node, obj); + }, + "Feature": function(node, container) { + var obj = {fids: []}; + this.readChildNodes(node, obj); + container.insertIds.push(obj.fids[0]); + } + }, OpenLayers.Format.WFST.v1.prototype.readers["wfs"]), + "gml": OpenLayers.Format.GML.v3.prototype.readers["gml"], + "feature": OpenLayers.Format.GML.v3.prototype.readers["feature"], + "ogc": OpenLayers.Format.Filter.v1_1_0.prototype.readers["ogc"], + "ows": OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"] + }, + + /** + * 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: { + "wfs": OpenLayers.Util.applyDefaults({ + "GetFeature": function(options) { + var node = OpenLayers.Format.WFST.v1.prototype.writers["wfs"]["GetFeature"].apply(this, arguments); + options && this.setAttributes(node, { + resultType: options.resultType, + startIndex: options.startIndex, + count: options.count + }); + return node; + }, + "Query": function(options) { + options = OpenLayers.Util.extend({ + featureNS: this.featureNS, + featurePrefix: this.featurePrefix, + featureType: this.featureType, + srsName: this.srsName + }, options); + var prefix = options.featurePrefix; + var node = this.createElementNSPlus("wfs:Query", { + attributes: { + typeName: (prefix ? prefix + ":" : "") + + options.featureType, + srsName: options.srsName + } + }); + if(options.featureNS) { + node.setAttribute("xmlns:" + prefix, options.featureNS); + } + if(options.propertyNames) { + for(var i=0,len = options.propertyNames.length; i<len; i++) { + this.writeNode( + "wfs:PropertyName", + {property: options.propertyNames[i]}, + node + ); + } + } + if(options.filter) { + OpenLayers.Format.WFST.v1_1_0.prototype.setFilterProperty.call(this, options.filter); + this.writeNode("ogc:Filter", options.filter, node); + } + return node; + }, + "PropertyName": function(obj) { + return this.createElementNSPlus("wfs:PropertyName", { + value: obj.property + }); + } + }, OpenLayers.Format.WFST.v1.prototype.writers["wfs"]), + "gml": OpenLayers.Format.GML.v3.prototype.writers["gml"], + "feature": OpenLayers.Format.GML.v3.prototype.writers["feature"], + "ogc": OpenLayers.Format.Filter.v1_1_0.prototype.writers["ogc"] + }, + + CLASS_NAME: "OpenLayers.Format.WFST.v1_1_0" +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WKT.js b/misc/openlayers/lib/OpenLayers/Format/WKT.js new file mode 100644 index 0000000..a7a7b2e --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WKT.js @@ -0,0 +1,392 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format.js + * @requires OpenLayers/Feature/Vector.js + * @requires OpenLayers/Geometry/Point.js + * @requires OpenLayers/Geometry/MultiPoint.js + * @requires OpenLayers/Geometry/LineString.js + * @requires OpenLayers/Geometry/MultiLineString.js + * @requires OpenLayers/Geometry/Polygon.js + * @requires OpenLayers/Geometry/MultiPolygon.js + */ + +/** + * Class: OpenLayers.Format.WKT + * Class for reading and writing Well-Known Text. Create a new instance + * with the <OpenLayers.Format.WKT> constructor. + * + * Inherits from: + * - <OpenLayers.Format> + */ +OpenLayers.Format.WKT = OpenLayers.Class(OpenLayers.Format, { + + /** + * Constructor: OpenLayers.Format.WKT + * Create a new parser for WKT + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance + * + * Returns: + * {<OpenLayers.Format.WKT>} A new WKT parser. + */ + initialize: function(options) { + this.regExes = { + 'typeStr': /^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/, + 'spaces': /\s+/, + 'parenComma': /\)\s*,\s*\(/, + 'doubleParenComma': /\)\s*\)\s*,\s*\(\s*\(/, // can't use {2} here + 'trimParens': /^\s*\(?(.*?)\)?\s*$/ + }; + OpenLayers.Format.prototype.initialize.apply(this, [options]); + }, + + /** + * APIMethod: read + * Deserialize a WKT string and return a vector feature or an + * array of vector features. Supports WKT for POINT, MULTIPOINT, + * LINESTRING, MULTILINESTRING, POLYGON, MULTIPOLYGON, and + * GEOMETRYCOLLECTION. + * + * Parameters: + * wkt - {String} A WKT string + * + * Returns: + * {<OpenLayers.Feature.Vector>|Array} A feature or array of features for + * GEOMETRYCOLLECTION WKT. + */ + read: function(wkt) { + var features, type, str; + wkt = wkt.replace(/[\n\r]/g, " "); + var matches = this.regExes.typeStr.exec(wkt); + if(matches) { + type = matches[1].toLowerCase(); + str = matches[2]; + if(this.parse[type]) { + features = this.parse[type].apply(this, [str]); + } + if (this.internalProjection && this.externalProjection) { + if (features && + features.CLASS_NAME == "OpenLayers.Feature.Vector") { + features.geometry.transform(this.externalProjection, + this.internalProjection); + } else if (features && + type != "geometrycollection" && + typeof features == "object") { + for (var i=0, len=features.length; i<len; i++) { + var component = features[i]; + component.geometry.transform(this.externalProjection, + this.internalProjection); + } + } + } + } + return features; + }, + + /** + * APIMethod: write + * Serialize a feature or array of features into a WKT string. + * + * Parameters: + * features - {<OpenLayers.Feature.Vector>|Array} A feature or array of + * features + * + * Returns: + * {String} The WKT string representation of the input geometries + */ + write: function(features) { + var collection, geometry, isCollection; + if (features.constructor == Array) { + collection = features; + isCollection = true; + } else { + collection = [features]; + isCollection = false; + } + var pieces = []; + if (isCollection) { + pieces.push('GEOMETRYCOLLECTION('); + } + for (var i=0, len=collection.length; i<len; ++i) { + if (isCollection && i>0) { + pieces.push(','); + } + geometry = collection[i].geometry; + pieces.push(this.extractGeometry(geometry)); + } + if (isCollection) { + pieces.push(')'); + } + return pieces.join(''); + }, + + /** + * Method: extractGeometry + * Entry point to construct the WKT for a single Geometry object. + * + * Parameters: + * geometry - {<OpenLayers.Geometry.Geometry>} + * + * Returns: + * {String} A WKT string of representing the geometry + */ + extractGeometry: function(geometry) { + var type = geometry.CLASS_NAME.split('.')[2].toLowerCase(); + if (!this.extract[type]) { + return null; + } + if (this.internalProjection && this.externalProjection) { + geometry = geometry.clone(); + geometry.transform(this.internalProjection, this.externalProjection); + } + var wktType = type == 'collection' ? 'GEOMETRYCOLLECTION' : type.toUpperCase(); + var data = wktType + '(' + this.extract[type].apply(this, [geometry]) + ')'; + return data; + }, + + /** + * Object with properties corresponding to the geometry types. + * Property values are functions that do the actual data extraction. + */ + extract: { + /** + * Return a space delimited string of point coordinates. + * @param {OpenLayers.Geometry.Point} point + * @returns {String} A string of coordinates representing the point + */ + 'point': function(point) { + return point.x + ' ' + point.y; + }, + + /** + * Return a comma delimited string of point coordinates from a multipoint. + * @param {OpenLayers.Geometry.MultiPoint} multipoint + * @returns {String} A string of point coordinate strings representing + * the multipoint + */ + 'multipoint': function(multipoint) { + var array = []; + for(var i=0, len=multipoint.components.length; i<len; ++i) { + array.push('(' + + this.extract.point.apply(this, [multipoint.components[i]]) + + ')'); + } + return array.join(','); + }, + + /** + * Return a comma delimited string of point coordinates from a line. + * @param {OpenLayers.Geometry.LineString} linestring + * @returns {String} A string of point coordinate strings representing + * the linestring + */ + 'linestring': function(linestring) { + var array = []; + for(var i=0, len=linestring.components.length; i<len; ++i) { + array.push(this.extract.point.apply(this, [linestring.components[i]])); + } + return array.join(','); + }, + + /** + * Return a comma delimited string of linestring strings from a multilinestring. + * @param {OpenLayers.Geometry.MultiLineString} multilinestring + * @returns {String} A string of of linestring strings representing + * the multilinestring + */ + 'multilinestring': function(multilinestring) { + var array = []; + for(var i=0, len=multilinestring.components.length; i<len; ++i) { + array.push('(' + + this.extract.linestring.apply(this, [multilinestring.components[i]]) + + ')'); + } + return array.join(','); + }, + + /** + * Return a comma delimited string of linear ring arrays from a polygon. + * @param {OpenLayers.Geometry.Polygon} polygon + * @returns {String} An array of linear ring arrays representing the polygon + */ + 'polygon': function(polygon) { + var array = []; + for(var i=0, len=polygon.components.length; i<len; ++i) { + array.push('(' + + this.extract.linestring.apply(this, [polygon.components[i]]) + + ')'); + } + return array.join(','); + }, + + /** + * Return an array of polygon arrays from a multipolygon. + * @param {OpenLayers.Geometry.MultiPolygon} multipolygon + * @returns {String} An array of polygon arrays representing + * the multipolygon + */ + 'multipolygon': function(multipolygon) { + var array = []; + for(var i=0, len=multipolygon.components.length; i<len; ++i) { + array.push('(' + + this.extract.polygon.apply(this, [multipolygon.components[i]]) + + ')'); + } + return array.join(','); + }, + + /** + * Return the WKT portion between 'GEOMETRYCOLLECTION(' and ')' for an <OpenLayers.Geometry.Collection> + * @param {OpenLayers.Geometry.Collection} collection + * @returns {String} internal WKT representation of the collection + */ + 'collection': function(collection) { + var array = []; + for(var i=0, len=collection.components.length; i<len; ++i) { + array.push(this.extractGeometry.apply(this, [collection.components[i]])); + } + return array.join(','); + } + + }, + + /** + * Object with properties corresponding to the geometry types. + * Property values are functions that do the actual parsing. + */ + parse: { + /** + * Return point feature given a point WKT fragment. + * @param {String} str A WKT fragment representing the point + * @returns {OpenLayers.Feature.Vector} A point feature + * @private + */ + 'point': function(str) { + var coords = OpenLayers.String.trim(str).split(this.regExes.spaces); + return new OpenLayers.Feature.Vector( + new OpenLayers.Geometry.Point(coords[0], coords[1]) + ); + }, + + /** + * Return a multipoint feature given a multipoint WKT fragment. + * @param {String} str A WKT fragment representing the multipoint + * @returns {OpenLayers.Feature.Vector} A multipoint feature + * @private + */ + 'multipoint': function(str) { + var point; + var points = OpenLayers.String.trim(str).split(','); + var components = []; + for(var i=0, len=points.length; i<len; ++i) { + point = points[i].replace(this.regExes.trimParens, '$1'); + components.push(this.parse.point.apply(this, [point]).geometry); + } + return new OpenLayers.Feature.Vector( + new OpenLayers.Geometry.MultiPoint(components) + ); + }, + + /** + * Return a linestring feature given a linestring WKT fragment. + * @param {String} str A WKT fragment representing the linestring + * @returns {OpenLayers.Feature.Vector} A linestring feature + * @private + */ + 'linestring': function(str) { + var points = OpenLayers.String.trim(str).split(','); + var components = []; + for(var i=0, len=points.length; i<len; ++i) { + components.push(this.parse.point.apply(this, [points[i]]).geometry); + } + return new OpenLayers.Feature.Vector( + new OpenLayers.Geometry.LineString(components) + ); + }, + + /** + * Return a multilinestring feature given a multilinestring WKT fragment. + * @param {String} str A WKT fragment representing the multilinestring + * @returns {OpenLayers.Feature.Vector} A multilinestring feature + * @private + */ + 'multilinestring': function(str) { + var line; + var lines = OpenLayers.String.trim(str).split(this.regExes.parenComma); + var components = []; + for(var i=0, len=lines.length; i<len; ++i) { + line = lines[i].replace(this.regExes.trimParens, '$1'); + components.push(this.parse.linestring.apply(this, [line]).geometry); + } + return new OpenLayers.Feature.Vector( + new OpenLayers.Geometry.MultiLineString(components) + ); + }, + + /** + * Return a polygon feature given a polygon WKT fragment. + * @param {String} str A WKT fragment representing the polygon + * @returns {OpenLayers.Feature.Vector} A polygon feature + * @private + */ + 'polygon': function(str) { + var ring, linestring, linearring; + var rings = OpenLayers.String.trim(str).split(this.regExes.parenComma); + var components = []; + for(var i=0, len=rings.length; i<len; ++i) { + ring = rings[i].replace(this.regExes.trimParens, '$1'); + linestring = this.parse.linestring.apply(this, [ring]).geometry; + linearring = new OpenLayers.Geometry.LinearRing(linestring.components); + components.push(linearring); + } + return new OpenLayers.Feature.Vector( + new OpenLayers.Geometry.Polygon(components) + ); + }, + + /** + * Return a multipolygon feature given a multipolygon WKT fragment. + * @param {String} str A WKT fragment representing the multipolygon + * @returns {OpenLayers.Feature.Vector} A multipolygon feature + * @private + */ + 'multipolygon': function(str) { + var polygon; + var polygons = OpenLayers.String.trim(str).split(this.regExes.doubleParenComma); + var components = []; + for(var i=0, len=polygons.length; i<len; ++i) { + polygon = polygons[i].replace(this.regExes.trimParens, '$1'); + components.push(this.parse.polygon.apply(this, [polygon]).geometry); + } + return new OpenLayers.Feature.Vector( + new OpenLayers.Geometry.MultiPolygon(components) + ); + }, + + /** + * Return an array of features given a geometrycollection WKT fragment. + * @param {String} str A WKT fragment representing the geometrycollection + * @returns {Array} An array of OpenLayers.Feature.Vector + * @private + */ + 'geometrycollection': function(str) { + // separate components of the collection with | + str = str.replace(/,\s*([A-Za-z])/g, '|$1'); + var wktArray = OpenLayers.String.trim(str).split('|'); + var components = []; + for(var i=0, len=wktArray.length; i<len; ++i) { + components.push(OpenLayers.Format.WKT.prototype.read.apply(this,[wktArray[i]])); + } + return components; + } + + }, + + CLASS_NAME: "OpenLayers.Format.WKT" +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WMC.js b/misc/openlayers/lib/OpenLayers/Format/WMC.js new file mode 100644 index 0000000..ded1b3a --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WMC.js @@ -0,0 +1,182 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Format/Context.js + */ + +/** + * Class: OpenLayers.Format.WMC + * Read and write Web Map Context documents. + * + * Inherits from: + * - <OpenLayers.Format.Context> + */ +OpenLayers.Format.WMC = OpenLayers.Class(OpenLayers.Format.Context, { + + /** + * APIProperty: defaultVersion + * {String} Version number to assume if none found. Default is "1.1.0". + */ + defaultVersion: "1.1.0", + + /** + * Constructor: OpenLayers.Format.WMC + * Create a new parser for Web Map Context documents. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * Method: layerToContext + * Create a layer context object given a wms layer object. + * + * Parameters: + * layer - {<OpenLayers.Layer.WMS>} The layer. + * + * Returns: + * {Object} A layer context object. + */ + layerToContext: function(layer) { + var parser = this.getParser(); + var layerContext = { + queryable: layer.queryable, + visibility: layer.visibility, + name: layer.params["LAYERS"], + title: layer.name, + "abstract": layer.metadata["abstract"], + dataURL: layer.metadata.dataURL, + metadataURL: layer.metadataURL, + server: { + version: layer.params["VERSION"], + url: layer.url + }, + maxExtent: layer.maxExtent, + transparent: layer.params["TRANSPARENT"], + numZoomLevels: layer.numZoomLevels, + units: layer.units, + isBaseLayer: layer.isBaseLayer, + opacity: layer.opacity == 1 ? undefined : layer.opacity, + displayInLayerSwitcher: layer.displayInLayerSwitcher, + singleTile: layer.singleTile, + tileSize: (layer.singleTile || !layer.tileSize) ? + undefined : {width: layer.tileSize.w, height: layer.tileSize.h}, + minScale : (layer.options.resolutions || + layer.options.scales || + layer.options.maxResolution || + layer.options.minScale) ? + layer.minScale : undefined, + maxScale : (layer.options.resolutions || + layer.options.scales || + layer.options.minResolution || + layer.options.maxScale) ? + layer.maxScale : undefined, + formats: [], + styles: [], + srs: layer.srs, + dimensions: layer.dimensions + }; + + + if (layer.metadata.servertitle) { + layerContext.server.title = layer.metadata.servertitle; + } + + if (layer.metadata.formats && layer.metadata.formats.length > 0) { + for (var i=0, len=layer.metadata.formats.length; i<len; i++) { + var format = layer.metadata.formats[i]; + layerContext.formats.push({ + value: format.value, + current: (format.value == layer.params["FORMAT"]) + }); + } + } else { + layerContext.formats.push({ + value: layer.params["FORMAT"], + current: true + }); + } + + if (layer.metadata.styles && layer.metadata.styles.length > 0) { + for (var i=0, len=layer.metadata.styles.length; i<len; i++) { + var style = layer.metadata.styles[i]; + if ((style.href == layer.params["SLD"]) || + (style.body == layer.params["SLD_BODY"]) || + (style.name == layer.params["STYLES"])) { + style.current = true; + } else { + style.current = false; + } + layerContext.styles.push(style); + } + } else { + layerContext.styles.push({ + href: layer.params["SLD"], + body: layer.params["SLD_BODY"], + name: layer.params["STYLES"] || parser.defaultStyleName, + title: parser.defaultStyleTitle, + current: true + }); + } + + return layerContext; + }, + + /** + * Method: toContext + * Create a context object free from layer given a map or a + * context object. + * + * Parameters: + * obj - {<OpenLayers.Map> | Object} The map or context. + * + * Returns: + * {Object} A context object. + */ + toContext: function(obj) { + var context = {}; + var layers = obj.layers; + if (obj.CLASS_NAME == "OpenLayers.Map") { + var metadata = obj.metadata || {}; + context.size = obj.getSize(); + context.bounds = obj.getExtent(); + context.projection = obj.projection; + context.title = obj.title; + context.keywords = metadata.keywords; + context["abstract"] = metadata["abstract"]; + context.logo = metadata.logo; + context.descriptionURL = metadata.descriptionURL; + context.contactInformation = metadata.contactInformation; + context.maxExtent = obj.maxExtent; + } else { + // copy all obj properties except the "layers" property + OpenLayers.Util.applyDefaults(context, obj); + if (context.layers != undefined) { + delete(context.layers); + } + } + + if (context.layersContext == undefined) { + context.layersContext = []; + } + + // let's convert layers into layersContext object (if any) + if (layers != undefined && OpenLayers.Util.isArray(layers)) { + for (var i=0, len=layers.length; i<len; i++) { + var layer = layers[i]; + if (layer instanceof OpenLayers.Layer.WMS) { + context.layersContext.push(this.layerToContext(layer)); + } + } + } + return context; + }, + + CLASS_NAME: "OpenLayers.Format.WMC" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WMC/v1.js b/misc/openlayers/lib/OpenLayers/Format/WMC/v1.js new file mode 100644 index 0000000..6c9a5c3 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WMC/v1.js @@ -0,0 +1,1267 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WMC.js + * @requires OpenLayers/Format/XML.js + */ + +/** + * Class: OpenLayers.Format.WMC.v1 + * Superclass for WMC version 1 parsers. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.WMC.v1 = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + ol: "http://openlayers.org/context", + wmc: "http://www.opengis.net/context", + sld: "http://www.opengis.net/sld", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance" + }, + + /** + * Property: schemaLocation + * {String} Schema location for a particular minor version. + */ + schemaLocation: "", + + /** + * Method: getNamespacePrefix + * Get the namespace prefix for a given uri from the <namespaces> 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 { + for(prefix in this.namespaces) { + if(this.namespaces[prefix] == uri) { + break; + } + } + } + return prefix; + }, + + /** + * Property: defaultPrefix + */ + defaultPrefix: "wmc", + + /** + * Property: rootPrefix + * {String} Prefix on the root node that maps to the context namespace URI. + */ + rootPrefix: null, + + /** + * Property: defaultStyleName + * {String} Style name used if layer has no style param. Default is "". + */ + defaultStyleName: "", + + /** + * Property: defaultStyleTitle + * {String} Default style title. Default is "Default". + */ + defaultStyleTitle: "Default", + + /** + * Constructor: OpenLayers.Format.WMC.v1 + * Instances of this class are not created directly. Use the + * <OpenLayers.Format.WMC> 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 + * Read capabilities data from a string, and return a list of layers. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array} List of named layers. + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + var root = data.documentElement; + this.rootPrefix = root.prefix; + var context = { + version: root.getAttribute("version") + }; + this.runChildNodes(context, root); + return context; + }, + + /** + * Method: runChildNodes + */ + runChildNodes: function(obj, node) { + var children = node.childNodes; + var childNode, processor, prefix, local; + for(var i=0, len=children.length; i<len; ++i) { + childNode = children[i]; + if(childNode.nodeType == 1) { + prefix = this.getNamespacePrefix(childNode.namespaceURI); + local = childNode.nodeName.split(":").pop(); + processor = this["read_" + prefix + "_" + local]; + if(processor) { + processor.apply(this, [obj, childNode]); + } + } + } + }, + + /** + * Method: read_wmc_General + */ + read_wmc_General: function(context, node) { + this.runChildNodes(context, node); + }, + + /** + * Method: read_wmc_BoundingBox + */ + read_wmc_BoundingBox: function(context, node) { + context.projection = node.getAttribute("SRS"); + context.bounds = new OpenLayers.Bounds( + node.getAttribute("minx"), node.getAttribute("miny"), + node.getAttribute("maxx"), node.getAttribute("maxy") + ); + }, + + /** + * Method: read_wmc_LayerList + */ + read_wmc_LayerList: function(context, node) { + // layersContext is an array containing info for each layer + context.layersContext = []; + this.runChildNodes(context, node); + }, + + /** + * Method: read_wmc_Layer + */ + read_wmc_Layer: function(context, node) { + var layerContext = { + visibility: (node.getAttribute("hidden") != "1"), + queryable: (node.getAttribute("queryable") == "1"), + formats: [], + styles: [], + metadata: {} + }; + + this.runChildNodes(layerContext, node); + // set properties common to multiple objects on layer options/params + context.layersContext.push(layerContext); + }, + + /** + * Method: read_wmc_Extension + */ + read_wmc_Extension: function(obj, node) { + this.runChildNodes(obj, node); + }, + + /** + * Method: read_ol_units + */ + read_ol_units: function(layerContext, node) { + layerContext.units = this.getChildValue(node); + }, + + /** + * Method: read_ol_maxExtent + */ + read_ol_maxExtent: function(obj, node) { + var bounds = new OpenLayers.Bounds( + node.getAttribute("minx"), node.getAttribute("miny"), + node.getAttribute("maxx"), node.getAttribute("maxy") + ); + obj.maxExtent = bounds; + }, + + /** + * Method: read_ol_transparent + */ + read_ol_transparent: function(layerContext, node) { + layerContext.transparent = this.getChildValue(node); + }, + + /** + * Method: read_ol_numZoomLevels + */ + read_ol_numZoomLevels: function(layerContext, node) { + layerContext.numZoomLevels = parseInt(this.getChildValue(node)); + }, + + /** + * Method: read_ol_opacity + */ + read_ol_opacity: function(layerContext, node) { + layerContext.opacity = parseFloat(this.getChildValue(node)); + }, + + /** + * Method: read_ol_singleTile + */ + read_ol_singleTile: function(layerContext, node) { + layerContext.singleTile = (this.getChildValue(node) == "true"); + }, + + /** + * Method: read_ol_tileSize + */ + read_ol_tileSize: function(layerContext, node) { + var obj = {"width": node.getAttribute("width"), "height": node.getAttribute("height")}; + layerContext.tileSize = obj; + }, + + /** + * Method: read_ol_isBaseLayer + */ + read_ol_isBaseLayer: function(layerContext, node) { + layerContext.isBaseLayer = (this.getChildValue(node) == "true"); + }, + + /** + * Method: read_ol_displayInLayerSwitcher + */ + read_ol_displayInLayerSwitcher: function(layerContext, node) { + layerContext.displayInLayerSwitcher = (this.getChildValue(node) == "true"); + }, + + /** + * Method: read_wmc_Server + */ + read_wmc_Server: function(layerContext, node) { + layerContext.version = node.getAttribute("version"); + layerContext.url = this.getOnlineResource_href(node); + layerContext.metadata.servertitle = node.getAttribute("title"); + }, + + /** + * Method: read_wmc_FormatList + */ + read_wmc_FormatList: function(layerContext, node) { + this.runChildNodes(layerContext, node); + }, + + /** + * Method: read_wmc_Format + */ + read_wmc_Format: function(layerContext, node) { + var format = { + value: this.getChildValue(node) + }; + if(node.getAttribute("current") == "1") { + format.current = true; + } + layerContext.formats.push(format); + }, + + /** + * Method: read_wmc_StyleList + */ + read_wmc_StyleList: function(layerContext, node) { + this.runChildNodes(layerContext, node); + }, + + /** + * Method: read_wmc_Style + */ + read_wmc_Style: function(layerContext, node) { + var style = {}; + this.runChildNodes(style, node); + if(node.getAttribute("current") == "1") { + style.current = true; + } + layerContext.styles.push(style); + }, + + /** + * Method: read_wmc_SLD + */ + read_wmc_SLD: function(style, node) { + this.runChildNodes(style, node); + // style either comes back with an href or a body property + }, + + /** + * Method: read_sld_StyledLayerDescriptor + */ + read_sld_StyledLayerDescriptor: function(sld, node) { + var xml = OpenLayers.Format.XML.prototype.write.apply(this, [node]); + sld.body = xml; + }, + + /** + * Method: read_sld_FeatureTypeStyle + */ + read_sld_FeatureTypeStyle: function(sld, node) { + var xml = OpenLayers.Format.XML.prototype.write.apply(this, [node]); + sld.body = xml; + }, + + /** + * Method: read_wmc_OnlineResource + */ + read_wmc_OnlineResource: function(obj, node) { + obj.href = this.getAttributeNS( + node, this.namespaces.xlink, "href" + ); + }, + + /** + * Method: read_wmc_Name + */ + read_wmc_Name: function(obj, node) { + var name = this.getChildValue(node); + if(name) { + obj.name = name; + } + }, + + /** + * Method: read_wmc_Title + */ + read_wmc_Title: function(obj, node) { + var title = this.getChildValue(node); + if(title) { + obj.title = title; + } + }, + + /** + * Method: read_wmc_MetadataURL + */ + read_wmc_MetadataURL: function(layerContext, node) { + layerContext.metadataURL = this.getOnlineResource_href(node); + }, + + /** + * Method: read_wmc_KeywordList + */ + read_wmc_KeywordList: function(context, node) { + context.keywords = []; + this.runChildNodes(context.keywords, node); + }, + + /** + * Method: read_wmc_Keyword + */ + read_wmc_Keyword: function(keywords, node) { + keywords.push(this.getChildValue(node)); + }, + + /** + * Method: read_wmc_Abstract + */ + read_wmc_Abstract: function(obj, node) { + var abst = this.getChildValue(node); + if(abst) { + obj["abstract"] = abst; + } + }, + + /** + * Method: read_wmc_LogoURL + */ + read_wmc_LogoURL: function(context, node) { + context.logo = { + width: node.getAttribute("width"), + height: node.getAttribute("height"), + format: node.getAttribute("format"), + href: this.getOnlineResource_href(node) + }; + }, + + /** + * Method: read_wmc_DescriptionURL + */ + read_wmc_DescriptionURL: function(context, node) { + context.descriptionURL = this.getOnlineResource_href(node); + }, + + /** + * Method: read_wmc_ContactInformation + */ + read_wmc_ContactInformation: function(obj, node) { + var contact = {}; + this.runChildNodes(contact, node); + obj.contactInformation = contact; + }, + + /** + * Method: read_wmc_ContactPersonPrimary + */ + read_wmc_ContactPersonPrimary: function(contact, node) { + var personPrimary = {}; + this.runChildNodes(personPrimary, node); + contact.personPrimary = personPrimary; + }, + + /** + * Method: read_wmc_ContactPerson + */ + read_wmc_ContactPerson: function(primaryPerson, node) { + var person = this.getChildValue(node); + if (person) { + primaryPerson.person = person; + } + }, + + /** + * Method: read_wmc_ContactOrganization + */ + read_wmc_ContactOrganization: function(primaryPerson, node) { + var organization = this.getChildValue(node); + if (organization) { + primaryPerson.organization = organization; + } + }, + + /** + * Method: read_wmc_ContactPosition + */ + read_wmc_ContactPosition: function(contact, node) { + var position = this.getChildValue(node); + if (position) { + contact.position = position; + } + }, + + /** + * Method: read_wmc_ContactAddress + */ + read_wmc_ContactAddress: function(contact, node) { + var contactAddress = {}; + this.runChildNodes(contactAddress, node); + contact.contactAddress = contactAddress; + }, + + /** + * Method: read_wmc_AddressType + */ + read_wmc_AddressType: function(contactAddress, node) { + var type = this.getChildValue(node); + if (type) { + contactAddress.type = type; + } + }, + + /** + * Method: read_wmc_Address + */ + read_wmc_Address: function(contactAddress, node) { + var address = this.getChildValue(node); + if (address) { + contactAddress.address = address; + } + }, + + /** + * Method: read_wmc_City + */ + read_wmc_City: function(contactAddress, node) { + var city = this.getChildValue(node); + if (city) { + contactAddress.city = city; + } + }, + + /** + * Method: read_wmc_StateOrProvince + */ + read_wmc_StateOrProvince: function(contactAddress, node) { + var stateOrProvince = this.getChildValue(node); + if (stateOrProvince) { + contactAddress.stateOrProvince = stateOrProvince; + } + }, + + /** + * Method: read_wmc_PostCode + */ + read_wmc_PostCode: function(contactAddress, node) { + var postcode = this.getChildValue(node); + if (postcode) { + contactAddress.postcode = postcode; + } + }, + + /** + * Method: read_wmc_Country + */ + read_wmc_Country: function(contactAddress, node) { + var country = this.getChildValue(node); + if (country) { + contactAddress.country = country; + } + }, + + /** + * Method: read_wmc_ContactVoiceTelephone + */ + read_wmc_ContactVoiceTelephone: function(contact, node) { + var phone = this.getChildValue(node); + if (phone) { + contact.phone = phone; + } + }, + + /** + * Method: read_wmc_ContactFacsimileTelephone + */ + read_wmc_ContactFacsimileTelephone: function(contact, node) { + var fax = this.getChildValue(node); + if (fax) { + contact.fax = fax; + } + }, + + /** + * Method: read_wmc_ContactElectronicMailAddress + */ + read_wmc_ContactElectronicMailAddress: function(contact, node) { + var email = this.getChildValue(node); + if (email) { + contact.email = email; + } + }, + + /** + * Method: read_wmc_DataURL + */ + read_wmc_DataURL: function(layerContext, node) { + layerContext.dataURL = this.getOnlineResource_href(node); + }, + + /** + * Method: read_wmc_LegendURL + */ + read_wmc_LegendURL: function(style, node) { + var legend = { + width: node.getAttribute('width'), + height: node.getAttribute('height'), + format: node.getAttribute('format'), + href: this.getOnlineResource_href(node) + }; + style.legend = legend; + }, + + /** + * Method: read_wmc_DimensionList + */ + read_wmc_DimensionList: function(layerContext, node) { + layerContext.dimensions = {}; + this.runChildNodes(layerContext.dimensions, node); + }, + /** + * Method: read_wmc_Dimension + */ + read_wmc_Dimension: function(dimensions, node) { + var name = node.getAttribute("name").toLowerCase(); + + var dim = { + name: name, + units: node.getAttribute("units") || "", + unitSymbol: node.getAttribute("unitSymbol") || "", + userValue: node.getAttribute("userValue") || "", + nearestValue: node.getAttribute("nearestValue") === "1", + multipleValues: node.getAttribute("multipleValues") === "1", + current: node.getAttribute("current") === "1", + "default": node.getAttribute("default") || "" + }; + var values = this.getChildValue(node); + dim.values = values.split(","); + + dimensions[dim.name] = dim; + }, + + /** + * Method: write + * + * Parameters: + * context - {Object} An object representing the map context. + * options - {Object} Optional object. + * + * Returns: + * {String} A WMC document string. + */ + write: function(context, options) { + var root = this.createElementDefaultNS("ViewContext"); + this.setAttributes(root, { + version: this.VERSION, + id: (options && typeof options.id == "string") ? + options.id : + OpenLayers.Util.createUniqueID("OpenLayers_Context_") + }); + + // add schemaLocation attribute + this.setAttributeNS( + root, this.namespaces.xsi, + "xsi:schemaLocation", this.schemaLocation + ); + + // required General element + root.appendChild(this.write_wmc_General(context)); + + // required LayerList element + root.appendChild(this.write_wmc_LayerList(context)); + + return OpenLayers.Format.XML.prototype.write.apply(this, [root]); + }, + + /** + * Method: createElementDefaultNS + * Shorthand for createElementNS with namespace from <defaultPrefix>. + * Can optionally be used to set attributes and a text child value. + * + * Parameters: + * name - {String} The qualified node name. + * childValue - {String} Optional value for text child node. + * attributes - {Object} Optional object representing attributes. + * + * Returns: + * {Element} An element node. + */ + createElementDefaultNS: function(name, childValue, attributes) { + var node = this.createElementNS( + this.namespaces[this.defaultPrefix], + name + ); + if(childValue) { + node.appendChild(this.createTextNode(childValue)); + } + if(attributes) { + this.setAttributes(node, attributes); + } + return node; + }, + + /** + * Method: setAttributes + * Set multiple attributes given key value pairs from an object. + * + * Parameters: + * node - {Element} An element node. + * obj - {Object} An object whose properties represent attribute names and + * values represent attribute values. + */ + setAttributes: function(node, obj) { + var value; + for(var name in obj) { + value = obj[name].toString(); + if(value.match(/[A-Z]/)) { + // safari lowercases attributes with setAttribute + this.setAttributeNS(node, null, name, value); + } else { + node.setAttribute(name, value); + } + } + }, + + /** + * Method: write_wmc_General + * Create a General node given an context object. + * + * Parameters: + * context - {Object} Context object. + * + * Returns: + * {Element} A WMC General element node. + */ + write_wmc_General: function(context) { + var node = this.createElementDefaultNS("General"); + + // optional Window element + if(context.size) { + node.appendChild(this.createElementDefaultNS( + "Window", null, + { + width: context.size.w, + height: context.size.h + } + )); + } + + // required BoundingBox element + var bounds = context.bounds; + node.appendChild(this.createElementDefaultNS( + "BoundingBox", null, + { + minx: bounds.left.toPrecision(18), + miny: bounds.bottom.toPrecision(18), + maxx: bounds.right.toPrecision(18), + maxy: bounds.top.toPrecision(18), + SRS: context.projection + } + )); + + // required Title element + node.appendChild(this.createElementDefaultNS( + "Title", context.title + )); + + // optional KeywordList element + if (context.keywords) { + node.appendChild(this.write_wmc_KeywordList(context.keywords)); + } + + // optional Abstract element + if (context["abstract"]) { + node.appendChild(this.createElementDefaultNS( + "Abstract", context["abstract"] + )); + } + + // Optional LogoURL element + if (context.logo) { + node.appendChild(this.write_wmc_URLType("LogoURL", context.logo.href, context.logo)); + } + + // Optional DescriptionURL element + if (context.descriptionURL) { + node.appendChild(this.write_wmc_URLType("DescriptionURL", context.descriptionURL)); + } + + // Optional ContactInformation element + if (context.contactInformation) { + node.appendChild(this.write_wmc_ContactInformation(context.contactInformation)); + } + + // OpenLayers specific map properties + node.appendChild(this.write_ol_MapExtension(context)); + + return node; + }, + + /** + * Method: write_wmc_KeywordList + */ + write_wmc_KeywordList: function(keywords) { + var node = this.createElementDefaultNS("KeywordList"); + + for (var i=0, len=keywords.length; i<len; i++) { + node.appendChild(this.createElementDefaultNS( + "Keyword", keywords[i] + )); + } + return node; + }, + /** + * Method: write_wmc_ContactInformation + */ + write_wmc_ContactInformation: function(contact) { + var node = this.createElementDefaultNS("ContactInformation"); + + if (contact.personPrimary) { + node.appendChild(this.write_wmc_ContactPersonPrimary(contact.personPrimary)); + } + if (contact.position) { + node.appendChild(this.createElementDefaultNS( + "ContactPosition", contact.position + )); + } + if (contact.contactAddress) { + node.appendChild(this.write_wmc_ContactAddress(contact.contactAddress)); + } + if (contact.phone) { + node.appendChild(this.createElementDefaultNS( + "ContactVoiceTelephone", contact.phone + )); + } + if (contact.fax) { + node.appendChild(this.createElementDefaultNS( + "ContactFacsimileTelephone", contact.fax + )); + } + if (contact.email) { + node.appendChild(this.createElementDefaultNS( + "ContactElectronicMailAddress", contact.email + )); + } + return node; + }, + + /** + * Method: write_wmc_ContactPersonPrimary + */ + write_wmc_ContactPersonPrimary: function(personPrimary) { + var node = this.createElementDefaultNS("ContactPersonPrimary"); + if (personPrimary.person) { + node.appendChild(this.createElementDefaultNS( + "ContactPerson", personPrimary.person + )); + } + if (personPrimary.organization) { + node.appendChild(this.createElementDefaultNS( + "ContactOrganization", personPrimary.organization + )); + } + return node; + }, + + /** + * Method: write_wmc_ContactAddress + */ + write_wmc_ContactAddress: function(contactAddress) { + var node = this.createElementDefaultNS("ContactAddress"); + if (contactAddress.type) { + node.appendChild(this.createElementDefaultNS( + "AddressType", contactAddress.type + )); + } + if (contactAddress.address) { + node.appendChild(this.createElementDefaultNS( + "Address", contactAddress.address + )); + } + if (contactAddress.city) { + node.appendChild(this.createElementDefaultNS( + "City", contactAddress.city + )); + } + if (contactAddress.stateOrProvince) { + node.appendChild(this.createElementDefaultNS( + "StateOrProvince", contactAddress.stateOrProvince + )); + } + if (contactAddress.postcode) { + node.appendChild(this.createElementDefaultNS( + "PostCode", contactAddress.postcode + )); + } + if (contactAddress.country) { + node.appendChild(this.createElementDefaultNS( + "Country", contactAddress.country + )); + } + return node; + }, + + /** + * Method: write_ol_MapExtension + */ + write_ol_MapExtension: function(context) { + var node = this.createElementDefaultNS("Extension"); + + var bounds = context.maxExtent; + if(bounds) { + var maxExtent = this.createElementNS( + this.namespaces.ol, "ol:maxExtent" + ); + this.setAttributes(maxExtent, { + minx: bounds.left.toPrecision(18), + miny: bounds.bottom.toPrecision(18), + maxx: bounds.right.toPrecision(18), + maxy: bounds.top.toPrecision(18) + }); + node.appendChild(maxExtent); + } + + return node; + }, + + /** + * Method: write_wmc_LayerList + * Create a LayerList node given an context object. + * + * Parameters: + * context - {Object} Context object. + * + * Returns: + * {Element} A WMC LayerList element node. + */ + write_wmc_LayerList: function(context) { + var list = this.createElementDefaultNS("LayerList"); + + for(var i=0, len=context.layersContext.length; i<len; ++i) { + list.appendChild(this.write_wmc_Layer(context.layersContext[i])); + } + + return list; + }, + + /** + * Method: write_wmc_Layer + * Create a Layer node given a layer context object. + * + * Parameters: + * context - {Object} A layer context object.} + * + * Returns: + * {Element} A WMC Layer element node. + */ + write_wmc_Layer: function(context) { + var node = this.createElementDefaultNS( + "Layer", null, { + queryable: context.queryable ? "1" : "0", + hidden: context.visibility ? "0" : "1" + } + ); + + // required Server element + node.appendChild(this.write_wmc_Server(context)); + + // required Name element + node.appendChild(this.createElementDefaultNS( + "Name", context.name + )); + + // required Title element + node.appendChild(this.createElementDefaultNS( + "Title", context.title + )); + + // optional Abstract element + if (context["abstract"]) { + node.appendChild(this.createElementDefaultNS( + "Abstract", context["abstract"] + )); + } + + // optional DataURL element + if (context.dataURL) { + node.appendChild(this.write_wmc_URLType("DataURL", context.dataURL)); + } + + // optional MetadataURL element + if (context.metadataURL) { + node.appendChild(this.write_wmc_URLType("MetadataURL", context.metadataURL)); + } + + return node; + }, + + /** + * Method: write_wmc_LayerExtension + * Add OpenLayers specific layer parameters to an Extension element. + * + * Parameters: + * context - {Object} A layer context object. + * + * Returns: + * {Element} A WMC Extension element (for a layer). + */ + write_wmc_LayerExtension: function(context) { + var node = this.createElementDefaultNS("Extension"); + + var bounds = context.maxExtent; + var maxExtent = this.createElementNS( + this.namespaces.ol, "ol:maxExtent" + ); + this.setAttributes(maxExtent, { + minx: bounds.left.toPrecision(18), + miny: bounds.bottom.toPrecision(18), + maxx: bounds.right.toPrecision(18), + maxy: bounds.top.toPrecision(18) + }); + node.appendChild(maxExtent); + + if (context.tileSize && !context.singleTile) { + var size = this.createElementNS( + this.namespaces.ol, "ol:tileSize" + ); + this.setAttributes(size, context.tileSize); + node.appendChild(size); + } + + var properties = [ + "transparent", "numZoomLevels", "units", "isBaseLayer", + "opacity", "displayInLayerSwitcher", "singleTile" + ]; + var child; + for(var i=0, len=properties.length; i<len; ++i) { + child = this.createOLPropertyNode(context, properties[i]); + if(child) { + node.appendChild(child); + } + } + + return node; + }, + + /** + * Method: createOLPropertyNode + * Create a node representing an OpenLayers property. If the property is + * null or undefined, null will be returned. + * + * Parameters: + * obj - {Object} An object. + * prop - {String} A property. + * + * Returns: + * {Element} A property node. + */ + createOLPropertyNode: function(obj, prop) { + var node = null; + if(obj[prop] != null) { + node = this.createElementNS(this.namespaces.ol, "ol:" + prop); + node.appendChild(this.createTextNode(obj[prop].toString())); + } + return node; + }, + + /** + * Method: write_wmc_Server + * Create a Server node given a layer context object. + * + * Parameters: + * context - {Object} Layer context object. + * + * Returns: + * {Element} A WMC Server element node. + */ + write_wmc_Server: function(context) { + var server = context.server; + var node = this.createElementDefaultNS("Server"); + var attributes = { + service: "OGC:WMS", + version: server.version + }; + if (server.title) { + attributes.title = server.title; + } + this.setAttributes(node, attributes); + + // required OnlineResource element + node.appendChild(this.write_wmc_OnlineResource(server.url)); + + return node; + }, + + /** + * Method: write_wmc_URLType + * Create a LogoURL/DescriptionURL/MetadataURL/DataURL/LegendURL node given a object and elementName. + * + * Parameters: + * elName - {String} Name of element (LogoURL/DescriptionURL/MetadataURL/LegendURL) + * url - {String} URL string value + * attr - {Object} Optional attributes (width, height, format) + * + * Returns: + * {Element} A WMC element node. + */ + write_wmc_URLType: function(elName, url, attr) { + var node = this.createElementDefaultNS(elName); + node.appendChild(this.write_wmc_OnlineResource(url)); + if (attr) { + var optionalAttributes = ["width", "height", "format"]; + for (var i=0; i<optionalAttributes.length; i++) { + if (optionalAttributes[i] in attr) { + node.setAttribute(optionalAttributes[i], attr[optionalAttributes[i]]); + } + } + } + return node; + }, + + /** + * Method: write_wmc_DimensionList + */ + write_wmc_DimensionList: function(context) { + var node = this.createElementDefaultNS("DimensionList"); + var required_attributes = { + name: true, + units: true, + unitSymbol: true, + userValue: true + }; + for (var dim in context.dimensions) { + var attributes = {}; + var dimension = context.dimensions[dim]; + for (var name in dimension) { + if (typeof dimension[name] == "boolean") { + attributes[name] = Number(dimension[name]); + } else { + attributes[name] = dimension[name]; + } + } + var values = ""; + if (attributes.values) { + values = attributes.values.join(","); + delete attributes.values; + } + + node.appendChild(this.createElementDefaultNS( + "Dimension", values, attributes + )); + } + return node; + }, + + /** + * Method: write_wmc_FormatList + * Create a FormatList node given a layer context. + * + * Parameters: + * context - {Object} Layer context object. + * + * Returns: + * {Element} A WMC FormatList element node. + */ + write_wmc_FormatList: function(context) { + var node = this.createElementDefaultNS("FormatList"); + for (var i=0, len=context.formats.length; i<len; i++) { + var format = context.formats[i]; + node.appendChild(this.createElementDefaultNS( + "Format", + format.value, + (format.current && format.current == true) ? + {current: "1"} : null + )); + } + + return node; + }, + + /** + * Method: write_wmc_StyleList + * Create a StyleList node given a layer context. + * + * Parameters: + * layer - {Object} Layer context object. + * + * Returns: + * {Element} A WMC StyleList element node. + */ + write_wmc_StyleList: function(layer) { + var node = this.createElementDefaultNS("StyleList"); + + var styles = layer.styles; + if (styles && OpenLayers.Util.isArray(styles)) { + var sld; + for (var i=0, len=styles.length; i<len; i++) { + var s = styles[i]; + // three style types to consider + // [1] linked SLD + // [2] inline SLD + // [3] named style + // running child nodes always gets name, optionally gets href or body + var style = this.createElementDefaultNS( + "Style", + null, + (s.current && s.current == true) ? + {current: "1"} : null + ); + if(s.href) { // [1] + sld = this.createElementDefaultNS("SLD"); + // Name is optional. + if (s.name) { + sld.appendChild(this.createElementDefaultNS("Name", s.name)); + } + // Title is optional. + if (s.title) { + sld.appendChild(this.createElementDefaultNS("Title", s.title)); + } + // LegendURL is optional + if (s.legend) { + sld.appendChild(this.write_wmc_URLType("LegendURL", s.legend.href, s.legend)); + } + + var link = this.write_wmc_OnlineResource(s.href); + sld.appendChild(link); + style.appendChild(sld); + } else if(s.body) { // [2] + sld = this.createElementDefaultNS("SLD"); + // Name is optional. + if (s.name) { + sld.appendChild(this.createElementDefaultNS("Name", s.name)); + } + // Title is optional. + if (s.title) { + sld.appendChild(this.createElementDefaultNS("Title", s.title)); + } + // LegendURL is optional + if (s.legend) { + sld.appendChild(this.write_wmc_URLType("LegendURL", s.legend.href, s.legend)); + } + + // read in body as xml doc - assume proper namespace declarations + var doc = OpenLayers.Format.XML.prototype.read.apply(this, [s.body]); + // append to StyledLayerDescriptor node + var imported = doc.documentElement; + if(sld.ownerDocument && sld.ownerDocument.importNode) { + imported = sld.ownerDocument.importNode(imported, true); + } + sld.appendChild(imported); + style.appendChild(sld); + } else { // [3] + // both Name and Title are required. + style.appendChild(this.createElementDefaultNS("Name", s.name)); + style.appendChild(this.createElementDefaultNS("Title", s.title)); + // Abstract is optional + if (s['abstract']) { // abstract is a js keyword + style.appendChild(this.createElementDefaultNS( + "Abstract", s['abstract'] + )); + } + // LegendURL is optional + if (s.legend) { + style.appendChild(this.write_wmc_URLType("LegendURL", s.legend.href, s.legend)); + } + } + node.appendChild(style); + } + } + + return node; + }, + + /** + * Method: write_wmc_OnlineResource + * Create an OnlineResource node given a URL. + * + * Parameters: + * href - {String} URL for the resource. + * + * Returns: + * {Element} A WMC OnlineResource element node. + */ + write_wmc_OnlineResource: function(href) { + var node = this.createElementDefaultNS("OnlineResource"); + this.setAttributeNS(node, this.namespaces.xlink, "xlink:type", "simple"); + this.setAttributeNS(node, this.namespaces.xlink, "xlink:href", href); + return node; + }, + + /** + * Method: getOnlineResource_href + */ + getOnlineResource_href: function(node) { + var object = {}; + var links = node.getElementsByTagName("OnlineResource"); + if(links.length > 0) { + this.read_wmc_OnlineResource(object, links[0]); + } + return object.href; + }, + + + CLASS_NAME: "OpenLayers.Format.WMC.v1" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WMC/v1_0_0.js b/misc/openlayers/lib/OpenLayers/Format/WMC/v1_0_0.js new file mode 100644 index 0000000..ace0d95 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WMC/v1_0_0.js @@ -0,0 +1,104 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WMC/v1.js + */ + +/** + * Class: OpenLayers.Format.WMC.v1_0_0 + * Read and write WMC version 1.0.0. + * + * Inherits from: + * - <OpenLayers.Format.WMC.v1> + */ +OpenLayers.Format.WMC.v1_0_0 = OpenLayers.Class( + OpenLayers.Format.WMC.v1, { + + /** + * Constant: VERSION + * {String} 1.0.0 + */ + VERSION: "1.0.0", + + /** + * Property: schemaLocation + * {String} http://www.opengis.net/context + * http://schemas.opengis.net/context/1.0.0/context.xsd + */ + schemaLocation: "http://www.opengis.net/context http://schemas.opengis.net/context/1.0.0/context.xsd", + + /** + * Constructor: OpenLayers.Format.WMC.v1_0_0 + * Instances of this class are not created directly. Use the + * <OpenLayers.Format.WMC> constructor instead. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + OpenLayers.Format.WMC.v1.prototype.initialize.apply( + this, [options] + ); + }, + + /** + * Method: read_wmc_SRS + */ + read_wmc_SRS: function(layerContext, node) { + var srs = this.getChildValue(node); + if (typeof layerContext.projections != "object") { + layerContext.projections = {}; + } + var values = srs.split(/ +/); + for (var i=0, len=values.length; i<len; i++) { + layerContext.projections[values[i]] = true; + } + }, + + /** + * Method: write_wmc_Layer + * Create a Layer node given a layer context object. This method adds + * elements specific to version 1.0.0. + * + * Parameters: + * context - {Object} A layer context object.} + * + * Returns: + * {Element} A WMC Layer element node. + */ + write_wmc_Layer: function(context) { + var node = OpenLayers.Format.WMC.v1.prototype.write_wmc_Layer.apply( + this, [context] + ); + + // optional SRS element(s) + if (context.srs) { + var projections = []; + for(var name in context.srs) { + projections.push(name); + } + node.appendChild(this.createElementDefaultNS("SRS", projections.join(" "))); + } + + // optional FormatList element + node.appendChild(this.write_wmc_FormatList(context)); + + // optional StyleList element + node.appendChild(this.write_wmc_StyleList(context)); + + // optional DimensionList element + if (context.dimensions) { + node.appendChild(this.write_wmc_DimensionList(context)); + } + + // OpenLayers specific properties go in an Extension element + node.appendChild(this.write_wmc_LayerExtension(context)); + }, + + CLASS_NAME: "OpenLayers.Format.WMC.v1_0_0" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WMC/v1_1_0.js b/misc/openlayers/lib/OpenLayers/Format/WMC/v1_1_0.js new file mode 100644 index 0000000..e5efc3e --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WMC/v1_1_0.js @@ -0,0 +1,149 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WMC/v1.js + */ + +/** + * Class: OpenLayers.Format.WMC.v1_1_0 + * Read and write WMC version 1.1.0. + * + * Differences between 1.1.0 and 1.0.0: + * - 1.1.0 Layers have optional sld:MinScaleDenominator and + * sld:MaxScaleDenominator + * + * Inherits from: + * - <OpenLayers.Format.WMC.v1> + */ +OpenLayers.Format.WMC.v1_1_0 = OpenLayers.Class( + OpenLayers.Format.WMC.v1, { + + /** + * Constant: VERSION + * {String} 1.1.0 + */ + VERSION: "1.1.0", + + /** + * Property: schemaLocation + * {String} http://www.opengis.net/context + * http://schemas.opengis.net/context/1.1.0/context.xsd + */ + schemaLocation: "http://www.opengis.net/context http://schemas.opengis.net/context/1.1.0/context.xsd", + + /** + * Constructor: OpenLayers.Format.WMC.v1_1_0 + * Instances of this class are not created directly. Use the + * <OpenLayers.Format.WMC> constructor instead. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + OpenLayers.Format.WMC.v1.prototype.initialize.apply( + this, [options] + ); + }, + + /** + * Method: read_sld_MinScaleDenominator + * Read a sld:MinScaleDenominator node. + * + * Parameters: + * layerContext - {Object} An object representing a layer. + * node - {Element} An element node. + */ + read_sld_MinScaleDenominator: function(layerContext, node) { + var minScaleDenominator = parseFloat(this.getChildValue(node)); + if (minScaleDenominator > 0) { + layerContext.maxScale = minScaleDenominator; + } + }, + + /** + * Method: read_sld_MaxScaleDenominator + * Read a sld:MaxScaleDenominator node. + * + * Parameters: + * layerContext - {Object} An object representing a layer. + * node - {Element} An element node. + */ + read_sld_MaxScaleDenominator: function(layerContext, node) { + layerContext.minScale = parseFloat(this.getChildValue(node)); + }, + + /** + * Method: read_wmc_SRS + */ + read_wmc_SRS: function(layerContext, node) { + if (! ("srs" in layerContext)) { + layerContext.srs = {}; + } + layerContext.srs[this.getChildValue(node)] = true; + }, + + /** + * Method: write_wmc_Layer + * Create a Layer node given a layer context object. This method adds + * elements specific to version 1.1.0. + * + * Parameters: + * context - {Object} A layer context object.} + * + * Returns: + * {Element} A WMC Layer element node. + */ + write_wmc_Layer: function(context) { + var node = OpenLayers.Format.WMC.v1.prototype.write_wmc_Layer.apply( + this, [context] + ); + + // min/max scale denominator elements go before the 4th element in v1 + if(context.maxScale) { + var minSD = this.createElementNS( + this.namespaces.sld, "sld:MinScaleDenominator" + ); + minSD.appendChild(this.createTextNode(context.maxScale.toPrecision(16))); + node.appendChild(minSD); + } + + if(context.minScale) { + var maxSD = this.createElementNS( + this.namespaces.sld, "sld:MaxScaleDenominator" + ); + maxSD.appendChild(this.createTextNode(context.minScale.toPrecision(16))); + node.appendChild(maxSD); + } + + // optional SRS element(s) + if (context.srs) { + for(var name in context.srs) { + node.appendChild(this.createElementDefaultNS("SRS", name)); + } + } + + // optional FormatList element + node.appendChild(this.write_wmc_FormatList(context)); + + // optional StyleList element + node.appendChild(this.write_wmc_StyleList(context)); + + // optional DimensionList element + if (context.dimensions) { + node.appendChild(this.write_wmc_DimensionList(context)); + } + + // OpenLayers specific properties go in an Extension element + node.appendChild(this.write_wmc_LayerExtension(context)); + + return node; + + }, + + CLASS_NAME: "OpenLayers.Format.WMC.v1_1_0" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities.js b/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities.js new file mode 100644 index 0000000..2bf3cef --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities.js @@ -0,0 +1,56 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML/VersionedOGC.js + */ + +/** + * Class: OpenLayers.Format.WMSCapabilities + * Read WMS Capabilities. + * + * Inherits from: + * - <OpenLayers.Format.XML.VersionedOGC> + */ +OpenLayers.Format.WMSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { + + /** + * APIProperty: defaultVersion + * {String} Version number to assume if none found. Default is "1.1.1". + */ + defaultVersion: "1.1.1", + + /** + * APIProperty: profile + * {String} If provided, use a custom profile. + * + * Currently supported profiles: + * - WMSC - parses vendor specific capabilities for WMS-C. + */ + profile: null, + + /** + * Constructor: OpenLayers.Format.WMSCapabilities + * Create a new parser for WMS capabilities. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Read capabilities data from a string, and return a list of layers. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array} List of named layers. + */ + + CLASS_NAME: "OpenLayers.Format.WMSCapabilities" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1.js b/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1.js new file mode 100644 index 0000000..ef5c133 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1.js @@ -0,0 +1,368 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WMSCapabilities.js + * @requires OpenLayers/Format/OGCExceptionReport.js + * @requires OpenLayers/Format/XML.js + */ + +/** + * Class: OpenLayers.Format.WMSCapabilities.v1 + * Abstract class not to be instantiated directly. Creates + * the common parts for both WMS 1.1.X and WMS 1.3.X. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.WMSCapabilities.v1 = OpenLayers.Class( + OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + wms: "http://www.opengis.net/wms", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance" + }, + + /** + * Property: defaultPrefix + */ + defaultPrefix: "wms", + + /** + * Constructor: OpenLayers.Format.WMSCapabilities.v1 + * Create an instance of one of the subclasses. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Read capabilities data from a string, and return a list of layers. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array} List of named layers. + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + var raw = data; + if(data && data.nodeType == 9) { + data = data.documentElement; + } + var capabilities = {}; + this.readNode(data, capabilities); + if (capabilities.service === undefined) { + // an exception must have occurred, so parse it + var parser = new OpenLayers.Format.OGCExceptionReport(); + capabilities.error = parser.read(raw); + } + return capabilities; + }, + + /** + * 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: { + "wms": { + "Service": function(node, obj) { + obj.service = {}; + this.readChildNodes(node, obj.service); + }, + "Name": function(node, obj) { + obj.name = this.getChildValue(node); + }, + "Title": function(node, obj) { + obj.title = this.getChildValue(node); + }, + "Abstract": function(node, obj) { + obj["abstract"] = this.getChildValue(node); + }, + "BoundingBox": function(node, obj) { + var bbox = {}; + bbox.bbox = [ + parseFloat(node.getAttribute("minx")), + parseFloat(node.getAttribute("miny")), + parseFloat(node.getAttribute("maxx")), + parseFloat(node.getAttribute("maxy")) + ]; + var res = { + x: parseFloat(node.getAttribute("resx")), + y: parseFloat(node.getAttribute("resy")) + }; + + if (! (isNaN(res.x) && isNaN(res.y))) { + bbox.res = res; + } + // return the bbox so that descendant classes can set the + // CRS and SRS and add it to the obj + return bbox; + }, + "OnlineResource": function(node, obj) { + obj.href = this.getAttributeNS(node, this.namespaces.xlink, + "href"); + }, + "ContactInformation": function(node, obj) { + obj.contactInformation = {}; + this.readChildNodes(node, obj.contactInformation); + }, + "ContactPersonPrimary": function(node, obj) { + obj.personPrimary = {}; + this.readChildNodes(node, obj.personPrimary); + }, + "ContactPerson": function(node, obj) { + obj.person = this.getChildValue(node); + }, + "ContactOrganization": function(node, obj) { + obj.organization = this.getChildValue(node); + }, + "ContactPosition": function(node, obj) { + obj.position = this.getChildValue(node); + }, + "ContactAddress": function(node, obj) { + obj.contactAddress = {}; + this.readChildNodes(node, obj.contactAddress); + }, + "AddressType": function(node, obj) { + obj.type = this.getChildValue(node); + }, + "Address": function(node, obj) { + obj.address = this.getChildValue(node); + }, + "City": function(node, obj) { + obj.city = this.getChildValue(node); + }, + "StateOrProvince": function(node, obj) { + obj.stateOrProvince = this.getChildValue(node); + }, + "PostCode": function(node, obj) { + obj.postcode = this.getChildValue(node); + }, + "Country": function(node, obj) { + obj.country = this.getChildValue(node); + }, + "ContactVoiceTelephone": function(node, obj) { + obj.phone = this.getChildValue(node); + }, + "ContactFacsimileTelephone": function(node, obj) { + obj.fax = this.getChildValue(node); + }, + "ContactElectronicMailAddress": function(node, obj) { + obj.email = this.getChildValue(node); + }, + "Fees": function(node, obj) { + var fees = this.getChildValue(node); + if (fees && fees.toLowerCase() != "none") { + obj.fees = fees; + } + }, + "AccessConstraints": function(node, obj) { + var constraints = this.getChildValue(node); + if (constraints && constraints.toLowerCase() != "none") { + obj.accessConstraints = constraints; + } + }, + "Capability": function(node, obj) { + obj.capability = { + nestedLayers: [], + layers: [] + }; + this.readChildNodes(node, obj.capability); + }, + "Request": function(node, obj) { + obj.request = {}; + this.readChildNodes(node, obj.request); + }, + "GetCapabilities": function(node, obj) { + obj.getcapabilities = {formats: []}; + this.readChildNodes(node, obj.getcapabilities); + }, + "Format": function(node, obj) { + if (OpenLayers.Util.isArray(obj.formats)) { + obj.formats.push(this.getChildValue(node)); + } else { + obj.format = this.getChildValue(node); + } + }, + "DCPType": function(node, obj) { + this.readChildNodes(node, obj); + }, + "HTTP": function(node, obj) { + this.readChildNodes(node, obj); + }, + "Get": function(node, obj) { + obj.get = {}; + this.readChildNodes(node, obj.get); + // backwards compatibility + if (!obj.href) { + obj.href = obj.get.href; + } + }, + "Post": function(node, obj) { + obj.post = {}; + this.readChildNodes(node, obj.post); + // backwards compatibility + if (!obj.href) { + obj.href = obj.get.href; + } + }, + "GetMap": function(node, obj) { + obj.getmap = {formats: []}; + this.readChildNodes(node, obj.getmap); + }, + "GetFeatureInfo": function(node, obj) { + obj.getfeatureinfo = {formats: []}; + this.readChildNodes(node, obj.getfeatureinfo); + }, + "Exception": function(node, obj) { + obj.exception = {formats: []}; + this.readChildNodes(node, obj.exception); + }, + "Layer": function(node, obj) { + var parentLayer, capability; + if (obj.capability) { + capability = obj.capability; + parentLayer = obj; + } else { + capability = obj; + } + var attrNode = node.getAttributeNode("queryable"); + var queryable = (attrNode && attrNode.specified) ? + node.getAttribute("queryable") : null; + attrNode = node.getAttributeNode("cascaded"); + var cascaded = (attrNode && attrNode.specified) ? + node.getAttribute("cascaded") : null; + attrNode = node.getAttributeNode("opaque"); + var opaque = (attrNode && attrNode.specified) ? + node.getAttribute('opaque') : null; + var noSubsets = node.getAttribute('noSubsets'); + var fixedWidth = node.getAttribute('fixedWidth'); + var fixedHeight = node.getAttribute('fixedHeight'); + var parent = parentLayer || {}, + extend = OpenLayers.Util.extend; + var layer = { + nestedLayers: [], + styles: parentLayer ? [].concat(parentLayer.styles) : [], + srs: parentLayer ? extend({}, parent.srs) : {}, + metadataURLs: [], + bbox: parentLayer ? extend({}, parent.bbox) : {}, + llbbox: parent.llbbox, + dimensions: parentLayer ? extend({}, parent.dimensions) : {}, + authorityURLs: parentLayer ? extend({}, parent.authorityURLs) : {}, + identifiers: {}, + keywords: [], + queryable: (queryable && queryable !== "") ? + (queryable === "1" || queryable === "true" ) : + (parent.queryable || false), + cascaded: (cascaded !== null) ? parseInt(cascaded) : + (parent.cascaded || 0), + opaque: opaque ? + (opaque === "1" || opaque === "true" ) : + (parent.opaque || false), + noSubsets: (noSubsets !== null) ? + (noSubsets === "1" || noSubsets === "true" ) : + (parent.noSubsets || false), + fixedWidth: (fixedWidth != null) ? + parseInt(fixedWidth) : (parent.fixedWidth || 0), + fixedHeight: (fixedHeight != null) ? + parseInt(fixedHeight) : (parent.fixedHeight || 0), + minScale: parent.minScale, + maxScale: parent.maxScale, + attribution: parent.attribution + }; + obj.nestedLayers.push(layer); + layer.capability = capability; + this.readChildNodes(node, layer); + delete layer.capability; + if(layer.name) { + var parts = layer.name.split(":"), + request = capability.request, + gfi = request.getfeatureinfo; + if(parts.length > 0) { + layer.prefix = parts[0]; + } + capability.layers.push(layer); + if (layer.formats === undefined) { + layer.formats = request.getmap.formats; + } + if (layer.infoFormats === undefined && gfi) { + layer.infoFormats = gfi.formats; + } + } + }, + "Attribution": function(node, obj) { + obj.attribution = {}; + this.readChildNodes(node, obj.attribution); + }, + "LogoURL": function(node, obj) { + obj.logo = { + width: node.getAttribute("width"), + height: node.getAttribute("height") + }; + this.readChildNodes(node, obj.logo); + }, + "Style": function(node, obj) { + var style = {}; + obj.styles.push(style); + this.readChildNodes(node, style); + }, + "LegendURL": function(node, obj) { + var legend = { + width: node.getAttribute("width"), + height: node.getAttribute("height") + }; + obj.legend = legend; + this.readChildNodes(node, legend); + }, + "MetadataURL": function(node, obj) { + var metadataURL = {type: node.getAttribute("type")}; + obj.metadataURLs.push(metadataURL); + this.readChildNodes(node, metadataURL); + }, + "DataURL": function(node, obj) { + obj.dataURL = {}; + this.readChildNodes(node, obj.dataURL); + }, + "FeatureListURL": function(node, obj) { + obj.featureListURL = {}; + this.readChildNodes(node, obj.featureListURL); + }, + "AuthorityURL": function(node, obj) { + var name = node.getAttribute("name"); + var authority = {}; + this.readChildNodes(node, authority); + obj.authorityURLs[name] = authority.href; + }, + "Identifier": function(node, obj) { + var authority = node.getAttribute("authority"); + obj.identifiers[authority] = this.getChildValue(node); + }, + "KeywordList": function(node, obj) { + this.readChildNodes(node, obj); + }, + "SRS": function(node, obj) { + obj.srs[this.getChildValue(node)] = true; + } + } + }, + + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_1.js b/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_1.js new file mode 100644 index 0000000..0e15d38 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_1.js @@ -0,0 +1,122 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WMSCapabilities/v1.js + */ + +/** + * Class: OpenLayers.Format.WMSCapabilities.v1_1 + * Abstract class not to be instantiated directly. + * + * Inherits from: + * - <OpenLayers.Format.WMSCapabilities.v1> + */ +OpenLayers.Format.WMSCapabilities.v1_1 = OpenLayers.Class( + OpenLayers.Format.WMSCapabilities.v1, { + + /** + * 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: { + "wms": OpenLayers.Util.applyDefaults({ + "WMT_MS_Capabilities": function(node, obj) { + this.readChildNodes(node, obj); + }, + "Keyword": function(node, obj) { + if (obj.keywords) { + obj.keywords.push(this.getChildValue(node)); + } + }, + "DescribeLayer": function(node, obj) { + obj.describelayer = {formats: []}; + this.readChildNodes(node, obj.describelayer); + }, + "GetLegendGraphic": function(node, obj) { + obj.getlegendgraphic = {formats: []}; + this.readChildNodes(node, obj.getlegendgraphic); + }, + "GetStyles": function(node, obj) { + obj.getstyles = {formats: []}; + this.readChildNodes(node, obj.getstyles); + }, + "PutStyles": function(node, obj) { + obj.putstyles = {formats: []}; + this.readChildNodes(node, obj.putstyles); + }, + "UserDefinedSymbolization": function(node, obj) { + var userSymbols = { + supportSLD: parseInt(node.getAttribute("SupportSLD")) == 1, + userLayer: parseInt(node.getAttribute("UserLayer")) == 1, + userStyle: parseInt(node.getAttribute("UserStyle")) == 1, + remoteWFS: parseInt(node.getAttribute("RemoteWFS")) == 1 + }; + obj.userSymbols = userSymbols; + }, + "LatLonBoundingBox": function(node, obj) { + obj.llbbox = [ + parseFloat(node.getAttribute("minx")), + parseFloat(node.getAttribute("miny")), + parseFloat(node.getAttribute("maxx")), + parseFloat(node.getAttribute("maxy")) + ]; + }, + "BoundingBox": function(node, obj) { + var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]); + bbox.srs = node.getAttribute("SRS"); + obj.bbox[bbox.srs] = bbox; + }, + "ScaleHint": function(node, obj) { + var min = node.getAttribute("min"); + var max = node.getAttribute("max"); + var rad2 = Math.pow(2, 0.5); + var ipm = OpenLayers.INCHES_PER_UNIT["m"]; + if (min != 0) { + obj.maxScale = parseFloat( + ((min / rad2) * ipm * + OpenLayers.DOTS_PER_INCH).toPrecision(13) + ); + } + if (max != Number.POSITIVE_INFINITY) { + obj.minScale = parseFloat( + ((max / rad2) * ipm * + OpenLayers.DOTS_PER_INCH).toPrecision(13) + ); + } + }, + "Dimension": function(node, obj) { + var name = node.getAttribute("name").toLowerCase(); + var dim = { + name: name, + units: node.getAttribute("units"), + unitsymbol: node.getAttribute("unitSymbol") + }; + obj.dimensions[dim.name] = dim; + }, + "Extent": function(node, obj) { + var name = node.getAttribute("name").toLowerCase(); + if (name in obj["dimensions"]) { + var extent = obj.dimensions[name]; + extent.nearestVal = + node.getAttribute("nearestValue") === "1"; + extent.multipleVal = + node.getAttribute("multipleValues") === "1"; + extent.current = node.getAttribute("current") === "1"; + extent["default"] = node.getAttribute("default") || ""; + var values = this.getChildValue(node); + extent.values = values.split(","); + } + } + }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]) + }, + + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_1_0.js b/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_1_0.js new file mode 100644 index 0000000..a1c6279 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_1_0.js @@ -0,0 +1,57 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WMSCapabilities/v1_1.js + */ + +/** + * Class: OpenLayers.Format.WMSCapabilities/v1_1_0 + * Read WMS Capabilities version 1.1.0. + * + * Inherits from: + * - <OpenLayers.Format.WMSCapabilities.v1_1> + */ +OpenLayers.Format.WMSCapabilities.v1_1_0 = OpenLayers.Class( + OpenLayers.Format.WMSCapabilities.v1_1, { + + /** + * Property: version + * {String} The specific parser version. + */ + version: "1.1.0", + + /** + * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_0 + * Create a new parser for WMS capabilities version 1.1.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: { + "wms": OpenLayers.Util.applyDefaults({ + "SRS": function(node, obj) { + var srs = this.getChildValue(node); + var values = srs.split(/ +/); + for (var i=0, len=values.length; i<len; i++) { + obj.srs[values[i]] = true; + } + } + }, OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"]) + }, + + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_0" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_1_1.js b/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_1_1.js new file mode 100644 index 0000000..459572b --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_1_1.js @@ -0,0 +1,60 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WMSCapabilities/v1_1.js + */ + +/** + * Class: OpenLayers.Format.WMSCapabilities/v1_1_1 + * Read WMS Capabilities version 1.1.1. + * + * Note on <ScaleHint> parsing: If the 'min' attribute is set to "0", no + * maxScale will be set on the layer object. If the 'max' attribute is set to + * "Infinity", no minScale will be set. This makes it easy to create proper + * {<OpenLayers.Layer.WMS>} configurations directly from the layer object + * literals returned by this format, because no minScale/maxScale modifications + * need to be made. + * + * Inherits from: + * - <OpenLayers.Format.WMSCapabilities.v1_1> + */ +OpenLayers.Format.WMSCapabilities.v1_1_1 = OpenLayers.Class( + OpenLayers.Format.WMSCapabilities.v1_1, { + + /** + * Property: version + * {String} The specific parser version. + */ + version: "1.1.1", + + /** + * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_1 + * Create a new parser for WMS capabilities version 1.1.1. + * + * 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: { + "wms": OpenLayers.Util.applyDefaults({ + "SRS": function(node, obj) { + obj.srs[this.getChildValue(node)] = true; + } + }, OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"]) + }, + + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_1_1_WMSC.js b/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_1_1_WMSC.js new file mode 100644 index 0000000..e58e4f7 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_1_1_WMSC.js @@ -0,0 +1,85 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WMSCapabilities/v1_1_1.js + */ + +/** + * Class: OpenLayers.Format.WMSCapabilities/v1_1_1_WMSC + * Read WMS-C Capabilities version 1.1.1. + * + * Inherits from: + * - <OpenLayers.Format.WMSCapabilities.v1_1_1> + */ +OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC = OpenLayers.Class( + OpenLayers.Format.WMSCapabilities.v1_1_1, { + + /** + * Property: version + * {String} The specific parser version. + */ + version: "1.1.1", + + /** + * Property: profile + * {String} The specific profile + */ + profile: "WMSC", + + /** + * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_1 + * Create a new parser for WMS-C capabilities version 1.1.1. + * + * 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: { + "wms": OpenLayers.Util.applyDefaults({ + "VendorSpecificCapabilities": function(node, obj) { + obj.vendorSpecific = {tileSets: []}; + this.readChildNodes(node, obj.vendorSpecific); + }, + "TileSet": function(node, vendorSpecific) { + var tileset = {srs: {}, bbox: {}, resolutions: []}; + this.readChildNodes(node, tileset); + vendorSpecific.tileSets.push(tileset); + }, + "Resolutions": function(node, tileset) { + var res = this.getChildValue(node).split(" "); + for (var i=0, len=res.length; i<len; i++) { + if (res[i] != "") { + tileset.resolutions.push(parseFloat(res[i])); + } + } + }, + "Width": function(node, tileset) { + tileset.width = parseInt(this.getChildValue(node)); + }, + "Height": function(node, tileset) { + tileset.height = parseInt(this.getChildValue(node)); + }, + "Layers": function(node, tileset) { + tileset.layers = this.getChildValue(node); + }, + "Styles": function(node, tileset) { + tileset.styles = this.getChildValue(node); + } + }, OpenLayers.Format.WMSCapabilities.v1_1_1.prototype.readers["wms"]) + }, + + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_3.js b/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_3.js new file mode 100644 index 0000000..57aee1a --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_3.js @@ -0,0 +1,128 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the 2-clause BSD license.
+ * See license.txt in the OpenLayers distribution or repository for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/WMSCapabilities/v1.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WMSCapabilities/v1_3
+ * Abstract base class for WMS Capabilities version 1.3.X.
+ * SLD 1.1.0 adds in the extra operations DescribeLayer and GetLegendGraphic,
+ * see: http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd
+ *
+ * Inherits from:
+ * - <OpenLayers.Format.WMSCapabilities.v1>
+ */
+OpenLayers.Format.WMSCapabilities.v1_3 = OpenLayers.Class(
+ OpenLayers.Format.WMSCapabilities.v1, {
+
+ /**
+ * 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: {
+ "wms": OpenLayers.Util.applyDefaults({
+ "WMS_Capabilities": function(node, obj) {
+ this.readChildNodes(node, obj);
+ },
+ "LayerLimit": function(node, obj) {
+ obj.layerLimit = parseInt(this.getChildValue(node));
+ },
+ "MaxWidth": function(node, obj) {
+ obj.maxWidth = parseInt(this.getChildValue(node));
+ },
+ "MaxHeight": function(node, obj) {
+ obj.maxHeight = parseInt(this.getChildValue(node));
+ },
+ "BoundingBox": function(node, obj) {
+ var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]);
+ bbox.srs = node.getAttribute("CRS");
+ obj.bbox[bbox.srs] = bbox;
+ },
+ "CRS": function(node, obj) {
+ // CRS is the synonym of SRS
+ this.readers.wms.SRS.apply(this, [node, obj]);
+ },
+ "EX_GeographicBoundingBox": function(node, obj) {
+ // replacement of LatLonBoundingBox
+ obj.llbbox = [];
+ this.readChildNodes(node, obj.llbbox);
+
+ },
+ "westBoundLongitude": function(node, obj) {
+ obj[0] = this.getChildValue(node);
+ },
+ "eastBoundLongitude": function(node, obj) {
+ obj[2] = this.getChildValue(node);
+ },
+ "southBoundLatitude": function(node, obj) {
+ obj[1] = this.getChildValue(node);
+ },
+ "northBoundLatitude": function(node, obj) {
+ obj[3] = this.getChildValue(node);
+ },
+ "MinScaleDenominator": function(node, obj) {
+ obj.maxScale = parseFloat(this.getChildValue(node)).toPrecision(16);
+ },
+ "MaxScaleDenominator": function(node, obj) {
+ obj.minScale = parseFloat(this.getChildValue(node)).toPrecision(16);
+ },
+ "Dimension": function(node, obj) {
+ // dimension has extra attributes: default, multipleValues,
+ // nearestValue, current which used to be part of Extent. It now
+ // also contains the values.
+ var name = node.getAttribute("name").toLowerCase();
+ var dim = {
+ name: name,
+ units: node.getAttribute("units"),
+ unitsymbol: node.getAttribute("unitSymbol"),
+ nearestVal: node.getAttribute("nearestValue") === "1",
+ multipleVal: node.getAttribute("multipleValues") === "1",
+ "default": node.getAttribute("default") || "",
+ current: node.getAttribute("current") === "1",
+ values: this.getChildValue(node).split(",")
+
+ };
+ // Theoretically there can be more dimensions with the same
+ // name, but with a different unit. Until we meet such a case,
+ // let's just keep the same structure as the WMS 1.1
+ // GetCapabilities parser uses. We will store the last
+ // one encountered.
+ obj.dimensions[dim.name] = dim;
+ },
+ "Keyword": function(node, obj) {
+ // TODO: should we change the structure of keyword in v1.js?
+ // Make it an object with a value instead of a string?
+ var keyword = {value: this.getChildValue(node),
+ vocabulary: node.getAttribute("vocabulary")};
+ if (obj.keywords) {
+ obj.keywords.push(keyword);
+ }
+ }
+ }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]),
+ "sld": {
+ "UserDefinedSymbolization": function(node, obj) {
+ this.readers.wms.UserDefinedSymbolization.apply(this, [node, obj]);
+ // add the two extra attributes
+ obj.userSymbols.inlineFeature = parseInt(node.getAttribute("InlineFeature")) == 1;
+ obj.userSymbols.remoteWCS = parseInt(node.getAttribute("RemoteWCS")) == 1;
+ },
+ "DescribeLayer": function(node, obj) {
+ this.readers.wms.DescribeLayer.apply(this, [node, obj]);
+ },
+ "GetLegendGraphic": function(node, obj) {
+ this.readers.wms.GetLegendGraphic.apply(this, [node, obj]);
+ }
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3"
+
+});
diff --git a/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_3_0.js b/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_3_0.js new file mode 100644 index 0000000..c2c4ca4 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_3_0.js @@ -0,0 +1,30 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the 2-clause BSD license.
+ * See license.txt in the OpenLayers distribution or repository for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/WMSCapabilities/v1_3.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WMSCapabilities/v1_3_0
+ * Read WMS Capabilities version 1.3.0.
+ * SLD 1.1.0 adds in the extra operations DescribeLayer and GetLegendGraphic,
+ * see: http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd
+ *
+ * Inherits from:
+ * - <OpenLayers.Format.WMSCapabilities.v1_3>
+ */
+OpenLayers.Format.WMSCapabilities.v1_3_0 = OpenLayers.Class(
+ OpenLayers.Format.WMSCapabilities.v1_3, {
+
+ /**
+ * Property: version
+ * {String} The specific parser version.
+ */
+ version: "1.3.0",
+
+ CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3_0"
+
+});
diff --git a/misc/openlayers/lib/OpenLayers/Format/WMSDescribeLayer.js b/misc/openlayers/lib/OpenLayers/Format/WMSDescribeLayer.js new file mode 100644 index 0000000..296262c --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WMSDescribeLayer.js @@ -0,0 +1,53 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML/VersionedOGC.js + */ + +/** + * Class: OpenLayers.Format.WMSDescribeLayer + * Read SLD WMS DescribeLayer response + * DescribeLayer is meant to couple WMS to WFS and WCS + * + * Inherits from: + * - <OpenLayers.Format.XML.VersionedOGC> + */ +OpenLayers.Format.WMSDescribeLayer = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { + + /** + * APIProperty: defaultVersion + * {String} Version number to assume if none found. Default is "1.1.1". + */ + defaultVersion: "1.1.1", + + /** + * Constructor: OpenLayers.Format.WMSDescribeLayer + * Create a new parser for WMS DescribeLayer responses. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Read DescribeLayer data from a string, and return the response. + * The OGC currently defines 2 formats which are allowed for output, + * so we need to parse these 2 types + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array} Array of {<LayerDescription>} objects which have: + * - {String} owsType: WFS/WCS + * - {String} owsURL: the online resource + * - {String} typeName: the name of the typename on the service + */ + + CLASS_NAME: "OpenLayers.Format.WMSDescribeLayer" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WMSDescribeLayer/v1_1.js b/misc/openlayers/lib/OpenLayers/Format/WMSDescribeLayer/v1_1.js new file mode 100644 index 0000000..3929d4b --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WMSDescribeLayer/v1_1.js @@ -0,0 +1,122 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WMSDescribeLayer.js + * @requires OpenLayers/Format/OGCExceptionReport.js + */ + +/** + * Class: OpenLayers.Format.WMSDescribeLayer.v1_1_1 + * Read SLD WMS DescribeLayer response for WMS 1.1.X + * WMS 1.1.X is tightly coupled to SLD 1.0.0 + * + * Example DescribeLayer request: + * http://demo.opengeo.org/geoserver/wms?request=DescribeLayer&version=1.1.1&layers=topp:states + * + * Inherits from: + * - <OpenLayers.Format.WMSDescribeLayer> + */ +OpenLayers.Format.WMSDescribeLayer.v1_1_1 = OpenLayers.Class( + OpenLayers.Format.WMSDescribeLayer, { + + /** + * Constructor: OpenLayers.Format.WMSDescribeLayer + * Create a new parser for WMS DescribeLayer responses. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + OpenLayers.Format.WMSDescribeLayer.prototype.initialize.apply(this, + [options]); + }, + + /** + * APIMethod: read + * Read DescribeLayer data from a string, and return the response. + * The OGC defines 2 formats which are allowed for output, + * so we need to parse these 2 types for version 1.1.X + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Object} Object with a layerDescriptions property, which holds an Array + * of {<LayerDescription>} objects which have: + * - {String} owsType: WFS/WCS + * - {String} owsURL: the online resource + * - {String} typeName: the name of the typename on the owsType service + * - {String} layerName: the name of the WMS layer we did a lookup for + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + var root = data.documentElement; + var children = root.childNodes; + var describelayer = {layerDescriptions: []}; + var childNode, nodeName; + for(var i=0; i<children.length; ++i) { + childNode = children[i]; + nodeName = childNode.nodeName; + if (nodeName == 'LayerDescription') { + var layerName = childNode.getAttribute('name'); + var owsType = ''; + var owsURL = ''; + var typeName = ''; + // check for owsType and owsURL attributes + if (childNode.getAttribute('owsType')) { + owsType = childNode.getAttribute('owsType'); + owsURL = childNode.getAttribute('owsURL'); + } else { + // look for wfs or wcs attribute + if (childNode.getAttribute('wfs') != '') { + owsType = 'WFS'; + owsURL = childNode.getAttribute('wfs'); + } else if (childNode.getAttribute('wcs') != '') { + owsType = 'WCS'; + owsURL = childNode.getAttribute('wcs'); + } + } + // look for Query child + var query = childNode.getElementsByTagName('Query'); + if(query.length > 0) { + typeName = query[0].getAttribute('typeName'); + if (!typeName) { + // because of Ionic bug + typeName = query[0].getAttribute('typename'); + } + } + var layerDescription = { + layerName: layerName, owsType: owsType, + owsURL: owsURL, typeName: typeName + }; + describelayer.layerDescriptions.push(layerDescription); + + //TODO do this in deprecated.js instead: + // array style index for backwards compatibility + describelayer.length = describelayer.layerDescriptions.length; + describelayer[describelayer.length - 1] = layerDescription; + + } else if (nodeName == 'ServiceException') { + // an exception must have occurred, so parse it + var parser = new OpenLayers.Format.OGCExceptionReport(); + return { + error: parser.read(data) + }; + } + } + return describelayer; + }, + + CLASS_NAME: "OpenLayers.Format.WMSDescribeLayer.v1_1_1" + +}); + +// Version alias - workaround for http://trac.osgeo.org/mapserver/ticket/2257 +OpenLayers.Format.WMSDescribeLayer.v1_1_0 = + OpenLayers.Format.WMSDescribeLayer.v1_1_1; diff --git a/misc/openlayers/lib/OpenLayers/Format/WMSGetFeatureInfo.js b/misc/openlayers/lib/OpenLayers/Format/WMSGetFeatureInfo.js new file mode 100644 index 0000000..57eb219 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WMSGetFeatureInfo.js @@ -0,0 +1,296 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + */ + +/** + * Class: OpenLayers.Format.WMSGetFeatureInfo + * Class to read GetFeatureInfo responses from Web Mapping Services + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * APIProperty: layerIdentifier + * {String} All xml nodes containing this search criteria will populate an + * internal array of layer nodes. + */ + layerIdentifier: '_layer', + + /** + * APIProperty: featureIdentifier + * {String} All xml nodes containing this search criteria will populate an + * internal array of feature nodes for each layer node found. + */ + featureIdentifier: '_feature', + + /** + * Property: regExes + * Compiled regular expressions for manipulating strings. + */ + regExes: { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g) + }, + + /** + * Property: gmlFormat + * {<OpenLayers.Format.GML>} internal GML format for parsing geometries + * in msGMLOutput + */ + gmlFormat: null, + + /** + * Constructor: OpenLayers.Format.WMSGetFeatureInfo + * Create a new parser for WMS GetFeatureInfo responses + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Read WMS GetFeatureInfo data from a string, and return an array of features + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array(<OpenLayers.Feature.Vector>)} An array of features. + */ + read: function(data) { + var result; + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + var root = data.documentElement; + if(root) { + var scope = this; + var read = this["read_" + root.nodeName]; + if(read) { + result = read.call(this, root); + } else { + // fall-back to GML since this is a common output format for WMS + // GetFeatureInfo responses + result = new OpenLayers.Format.GML((this.options ? this.options : {})).read(data); + } + } else { + result = data; + } + return result; + }, + + + /** + * Method: read_msGMLOutput + * Parse msGMLOutput nodes. + * + * Parameters: + * data - {DOMElement} + * + * Returns: + * {Array} + */ + read_msGMLOutput: function(data) { + var response = []; + var layerNodes = this.getSiblingNodesByTagCriteria(data, + this.layerIdentifier); + if (layerNodes) { + for (var i=0, len=layerNodes.length; i<len; ++i) { + var node = layerNodes[i]; + var layerName = node.nodeName; + if (node.prefix) { + layerName = layerName.split(':')[1]; + } + var layerName = layerName.replace(this.layerIdentifier, ''); + var featureNodes = this.getSiblingNodesByTagCriteria(node, + this.featureIdentifier); + if (featureNodes) { + for (var j = 0; j < featureNodes.length; j++) { + var featureNode = featureNodes[j]; + var geomInfo = this.parseGeometry(featureNode); + var attributes = this.parseAttributes(featureNode); + var feature = new OpenLayers.Feature.Vector(geomInfo.geometry, + attributes, null); + feature.bounds = geomInfo.bounds; + feature.type = layerName; + response.push(feature); + } + } + } + } + return response; + }, + + /** + * Method: read_FeatureInfoResponse + * Parse FeatureInfoResponse nodes. + * + * Parameters: + * data - {DOMElement} + * + * Returns: + * {Array} + */ + read_FeatureInfoResponse: function(data) { + var response = []; + var featureNodes = this.getElementsByTagNameNS(data, '*', + 'FIELDS'); + + for(var i=0, len=featureNodes.length;i<len;i++) { + var featureNode = featureNodes[i]; + var geom = null; + + // attributes can be actual attributes on the FIELDS tag, + // or FIELD children + var attributes = {}; + var j; + var jlen = featureNode.attributes.length; + if (jlen > 0) { + for(j=0; j<jlen; j++) { + var attribute = featureNode.attributes[j]; + attributes[attribute.nodeName] = attribute.nodeValue; + } + } else { + var nodes = featureNode.childNodes; + for (j=0, jlen=nodes.length; j<jlen; ++j) { + var node = nodes[j]; + if (node.nodeType != 3) { + attributes[node.getAttribute("name")] = + node.getAttribute("value"); + } + } + } + + response.push( + new OpenLayers.Feature.Vector(geom, attributes, null) + ); + } + return response; + }, + + /** + * Method: getSiblingNodesByTagCriteria + * Recursively searches passed xml node and all it's descendant levels for + * nodes whose tagName contains the passed search string. This returns an + * array of all sibling nodes which match the criteria from the highest + * hierarchial level from which a match is found. + * + * Parameters: + * node - {DOMElement} An xml node + * criteria - {String} Search string which will match some part of a tagName + * + * Returns: + * Array({DOMElement}) An array of sibling xml nodes + */ + getSiblingNodesByTagCriteria: function(node, criteria){ + var nodes = []; + var children, tagName, n, matchNodes, child; + if (node && node.hasChildNodes()) { + children = node.childNodes; + n = children.length; + + for(var k=0; k<n; k++){ + child = children[k]; + while (child && child.nodeType != 1) { + child = child.nextSibling; + k++; + } + tagName = (child ? child.nodeName : ''); + if (tagName.length > 0 && tagName.indexOf(criteria) > -1) { + nodes.push(child); + } else { + matchNodes = this.getSiblingNodesByTagCriteria( + child, criteria); + + if(matchNodes.length > 0){ + (nodes.length == 0) ? + nodes = matchNodes : nodes.push(matchNodes); + } + } + } + + } + return nodes; + }, + + /** + * Method: parseAttributes + * + * Parameters: + * node - {<DOMElement>} + * + * Returns: + * {Object} An attributes object. + * + * Notes: + * Assumes that attributes are direct child xml nodes of the passed node + * and contain only a single text node. + */ + parseAttributes: function(node){ + var attributes = {}; + if (node.nodeType == 1) { + var children = node.childNodes; + var n = children.length; + for (var i = 0; i < n; ++i) { + var child = children[i]; + if (child.nodeType == 1) { + var grandchildren = child.childNodes; + var name = (child.prefix) ? + child.nodeName.split(":")[1] : child.nodeName; + if (grandchildren.length == 0) { + attributes[name] = null; + } else if (grandchildren.length == 1) { + var grandchild = grandchildren[0]; + if (grandchild.nodeType == 3 || + grandchild.nodeType == 4) { + var value = grandchild.nodeValue.replace( + this.regExes.trimSpace, ""); + attributes[name] = value; + } + } + } + } + } + return attributes; + }, + + /** + * Method: parseGeometry + * Parse the geometry and the feature bounds out of the node using + * Format.GML + * + * Parameters: + * node - {<DOMElement>} + * + * Returns: + * {Object} An object containing the geometry and the feature bounds + */ + parseGeometry: function(node) { + // we need to use the old Format.GML parser since we do not know the + // geometry name + if (!this.gmlFormat) { + this.gmlFormat = new OpenLayers.Format.GML(); + } + var feature = this.gmlFormat.parseFeature(node); + var geometry, bounds = null; + if (feature) { + geometry = feature.geometry && feature.geometry.clone(); + bounds = feature.bounds && feature.bounds.clone(); + feature.destroy(); + } + return {geometry: geometry, bounds: bounds}; + }, + + CLASS_NAME: "OpenLayers.Format.WMSGetFeatureInfo" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WMTSCapabilities.js b/misc/openlayers/lib/OpenLayers/Format/WMTSCapabilities.js new file mode 100644 index 0000000..9cff69c --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WMTSCapabilities.js @@ -0,0 +1,230 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML/VersionedOGC.js + */ + +/** + * Class: OpenLayers.Format.WMTSCapabilities + * Read WMTS Capabilities. + * + * Inherits from: + * - <OpenLayers.Format.XML.VersionedOGC> + */ +OpenLayers.Format.WMTSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { + + /** + * APIProperty: defaultVersion + * {String} Version number to assume if none found. Default is "1.0.0". + */ + defaultVersion: "1.0.0", + + /** + * APIProperty: yx + * {Object} Members in the yx object are used to determine if a CRS URN + * corresponds to a CRS with y,x axis order. Member names are CRS URNs + * and values are boolean. By default, the following CRS URN are + * assumed to correspond to a CRS with y,x axis order: + * + * * urn:ogc:def:crs:EPSG::4326 + */ + yx: { + "urn:ogc:def:crs:EPSG::4326": true + }, + + /** + * Constructor: OpenLayers.Format.WMTSCapabilities + * Create a new parser for WMTS capabilities. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Read capabilities data from a string, and return information about + * the service (offering and observedProperty mostly). + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Object} Info about the WMTS Capabilities + */ + + /** + * APIMethod: createLayer + * Create a WMTS layer given a capabilities object. + * + * Parameters: + * capabilities - {Object} The object returned from a <read> call to this + * format. + * config - {Object} Configuration properties for the layer. Defaults for + * the layer will apply if not provided. + * + * Required config properties: + * layer - {String} The layer identifier. + * + * Optional config properties: + * matrixSet - {String} The matrix set identifier, required if there is + * more than one matrix set in the layer capabilities. + * style - {String} The name of the style + * format - {String} Image format for the layer. Default is the first + * format returned in the GetCapabilities response. + * param - {Object} The dimensions values eg: {"Year": "2012"} + * + * Returns: + * {<OpenLayers.Layer.WMTS>} A properly configured WMTS layer. Throws an + * error if an incomplete config is provided. Returns undefined if no + * layer could be created with the provided config. + */ + createLayer: function(capabilities, config) { + var layer; + + // confirm required properties are supplied in config + if (!('layer' in config)) { + throw new Error("Missing property 'layer' in configuration."); + } + + var contents = capabilities.contents; + + // find the layer definition with the given identifier + var layers = contents.layers; + var layerDef; + for (var i=0, ii=contents.layers.length; i<ii; ++i) { + if (contents.layers[i].identifier === config.layer) { + layerDef = contents.layers[i]; + break; + } + } + if (!layerDef) { + throw new Error("Layer not found"); + } + + var format = config.format; + if (!format && layerDef.formats && layerDef.formats.length) { + format = layerDef.formats[0]; + } + + // find the matrixSet definition + var matrixSet; + if (config.matrixSet) { + matrixSet = contents.tileMatrixSets[config.matrixSet]; + } else if (layerDef.tileMatrixSetLinks.length >= 1) { + matrixSet = contents.tileMatrixSets[ + layerDef.tileMatrixSetLinks[0].tileMatrixSet]; + } + if (!matrixSet) { + throw new Error("matrixSet not found"); + } + + // get the default style for the layer + var style; + for (var i=0, ii=layerDef.styles.length; i<ii; ++i) { + style = layerDef.styles[i]; + if (style.isDefault) { + break; + } + } + + var requestEncoding = config.requestEncoding; + if (!requestEncoding) { + requestEncoding = "KVP"; + if (capabilities.operationsMetadata.GetTile.dcp.http) { + var http = capabilities.operationsMetadata.GetTile.dcp.http; + // Get first get method + if (http.get[0].constraints) { + var constraints = http.get[0].constraints; + var allowedValues = constraints.GetEncoding.allowedValues; + + // The OGC documentation is not clear if we should use + // REST or RESTful, ArcGis use RESTful, + // and OpenLayers use REST. + if (!allowedValues.KVP && + (allowedValues.REST || allowedValues.RESTful)) { + requestEncoding = "REST"; + } + } + } + } + + var dimensions = []; + var params = config.params || {}; + // to don't overwrite the changes in the applyDefaults + delete config.params; + for (var id = 0, ld = layerDef.dimensions.length ; id < ld ; id++) { + var dimension = layerDef.dimensions[id]; + dimensions.push(dimension.identifier); + if (!params.hasOwnProperty(dimension.identifier)) { + params[dimension.identifier] = dimension['default']; + } + } + + var projection = config.projection || matrixSet.supportedCRS.replace( + /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, "$1:$3"); + var units = config.units || + (projection === "EPSG:4326" ? "degrees" : "m"); + + var resolutions = []; + for (var mid in matrixSet.matrixIds) { + if (matrixSet.matrixIds.hasOwnProperty(mid)) { + resolutions.push( + matrixSet.matrixIds[mid].scaleDenominator * 0.28E-3 / + OpenLayers.METERS_PER_INCH / + OpenLayers.INCHES_PER_UNIT[units]); + } + } + + var url; + if (requestEncoding === "REST" && layerDef.resourceUrls) { + url = []; + var resourceUrls = layerDef.resourceUrls, + resourceUrl; + for (var t = 0, tt = layerDef.resourceUrls.length; t < tt; ++t) { + resourceUrl = layerDef.resourceUrls[t]; + if (resourceUrl.format === format && resourceUrl.resourceType === "tile") { + url.push(resourceUrl.template); + } + } + } + else { + var httpGet = capabilities.operationsMetadata.GetTile.dcp.http.get; + url = []; + var constraint; + for (var i = 0, ii = httpGet.length; i < ii; i++) { + constraint = httpGet[i].constraints; + if (!constraint || (constraint && constraint. + GetEncoding.allowedValues[requestEncoding])) { + url.push(httpGet[i].url); + } + } + } + + return new OpenLayers.Layer.WMTS( + OpenLayers.Util.applyDefaults(config, { + url: url, + requestEncoding: requestEncoding, + name: layerDef.title, + style: style.identifier, + format: format, + matrixIds: matrixSet.matrixIds, + matrixSet: matrixSet.identifier, + projection: projection, + units: units, + resolutions: config.isBaseLayer === false ? undefined : + resolutions, + serverResolutions: resolutions, + tileFullExtent: matrixSet.bounds, + dimensions: dimensions, + params: params + }) + ); + }, + + CLASS_NAME: "OpenLayers.Format.WMTSCapabilities" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WMTSCapabilities/v1_0_0.js b/misc/openlayers/lib/OpenLayers/Format/WMTSCapabilities/v1_0_0.js new file mode 100644 index 0000000..fda2584 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WMTSCapabilities/v1_0_0.js @@ -0,0 +1,251 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WMTSCapabilities.js + * @requires OpenLayers/Format/OWSCommon/v1_1_0.js + */ + +/** + * Class: OpenLayers.Format.WMTSCapabilities.v1_0_0 + * Read WMTS Capabilities version 1.0.0. + * + * Inherits from: + * - <OpenLayers.Format.WMTSCapabilities> + */ +OpenLayers.Format.WMTSCapabilities.v1_0_0 = OpenLayers.Class( + OpenLayers.Format.OWSCommon.v1_1_0, { + + /** + * Property: version + * {String} The parser version ("1.0.0"). + */ + version: "1.0.0", + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + ows: "http://www.opengis.net/ows/1.1", + wmts: "http://www.opengis.net/wmts/1.0", + xlink: "http://www.w3.org/1999/xlink" + }, + + /** + * Property: yx + * {Object} Members in the yx object are used to determine if a CRS URN + * corresponds to a CRS with y,x axis order. Member names are CRS URNs + * and values are boolean. Defaults come from the + * <OpenLayers.Format.WMTSCapabilities> prototype. + */ + yx: null, + + /** + * Property: defaultPrefix + * {String} The default namespace alias for creating element nodes. + */ + defaultPrefix: "wmts", + + /** + * Constructor: OpenLayers.Format.WMTSCapabilities.v1_0_0 + * Create a new parser for WMTS capabilities version 1.0.0. + * + * 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]); + this.options = options; + var yx = OpenLayers.Util.extend( + {}, OpenLayers.Format.WMTSCapabilities.prototype.yx + ); + this.yx = OpenLayers.Util.extend(yx, this.yx); + }, + + /** + * APIMethod: read + * Read capabilities data from a string, and return info about the WMTS. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Object} Information about the SOS service. + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + if(data && data.nodeType == 9) { + data = data.documentElement; + } + var capabilities = {}; + this.readNode(data, capabilities); + capabilities.version = this.version; + return capabilities; + }, + + /** + * 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: { + "wmts": { + "Capabilities": function(node, obj) { + this.readChildNodes(node, obj); + }, + "Contents": function(node, obj) { + obj.contents = {}; + obj.contents.layers = []; + obj.contents.tileMatrixSets = {}; + this.readChildNodes(node, obj.contents); + }, + "Layer": function(node, obj) { + var layer = { + styles: [], + formats: [], + dimensions: [], + tileMatrixSetLinks: [] + }; + layer.layers = []; + this.readChildNodes(node, layer); + obj.layers.push(layer); + }, + "Style": function(node, obj) { + var style = {}; + style.isDefault = (node.getAttribute("isDefault") === "true"); + this.readChildNodes(node, style); + obj.styles.push(style); + }, + "Format": function(node, obj) { + obj.formats.push(this.getChildValue(node)); + }, + "TileMatrixSetLink": function(node, obj) { + var tileMatrixSetLink = {}; + this.readChildNodes(node, tileMatrixSetLink); + obj.tileMatrixSetLinks.push(tileMatrixSetLink); + }, + "TileMatrixSet": function(node, obj) { + // node could be child of wmts:Contents or wmts:TileMatrixSetLink + // duck type wmts:Contents by looking for layers + if (obj.layers) { + // TileMatrixSet as object type in schema + var tileMatrixSet = { + matrixIds: [] + }; + this.readChildNodes(node, tileMatrixSet); + obj.tileMatrixSets[tileMatrixSet.identifier] = tileMatrixSet; + } else { + // TileMatrixSet as string type in schema + obj.tileMatrixSet = this.getChildValue(node); + } + }, + "TileMatrix": function(node, obj) { + var tileMatrix = { + supportedCRS: obj.supportedCRS + }; + this.readChildNodes(node, tileMatrix); + obj.matrixIds.push(tileMatrix); + }, + "ScaleDenominator": function(node, obj) { + obj.scaleDenominator = parseFloat(this.getChildValue(node)); + }, + "TopLeftCorner": function(node, obj) { + var topLeftCorner = this.getChildValue(node); + var coords = topLeftCorner.split(" "); + // decide on axis order for the given CRS + var yx; + if (obj.supportedCRS) { + // extract out version from URN + var crs = obj.supportedCRS.replace( + /urn:ogc:def:crs:(\w+):.+:(\w+)$/, + "urn:ogc:def:crs:$1::$2" + ); + yx = !!this.yx[crs]; + } + if (yx) { + obj.topLeftCorner = new OpenLayers.LonLat( + coords[1], coords[0] + ); + } else { + obj.topLeftCorner = new OpenLayers.LonLat( + coords[0], coords[1] + ); + } + }, + "TileWidth": function(node, obj) { + obj.tileWidth = parseInt(this.getChildValue(node)); + }, + "TileHeight": function(node, obj) { + obj.tileHeight = parseInt(this.getChildValue(node)); + }, + "MatrixWidth": function(node, obj) { + obj.matrixWidth = parseInt(this.getChildValue(node)); + }, + "MatrixHeight": function(node, obj) { + obj.matrixHeight = parseInt(this.getChildValue(node)); + }, + "ResourceURL": function(node, obj) { + obj.resourceUrl = obj.resourceUrl || {}; + var resourceType = node.getAttribute("resourceType"); + if (!obj.resourceUrls) { + obj.resourceUrls = []; + } + var resourceUrl = obj.resourceUrl[resourceType] = { + format: node.getAttribute("format"), + template: node.getAttribute("template"), + resourceType: resourceType + }; + obj.resourceUrls.push(resourceUrl); + }, + // not used for now, can be added in the future though + /*"Themes": function(node, obj) { + obj.themes = []; + this.readChildNodes(node, obj.themes); + }, + "Theme": function(node, obj) { + var theme = {}; + this.readChildNodes(node, theme); + obj.push(theme); + },*/ + "WSDL": function(node, obj) { + obj.wsdl = {}; + obj.wsdl.href = node.getAttribute("xlink:href"); + // TODO: other attributes of <WSDL> element + }, + "ServiceMetadataURL": function(node, obj) { + obj.serviceMetadataUrl = {}; + obj.serviceMetadataUrl.href = node.getAttribute("xlink:href"); + // TODO: other attributes of <ServiceMetadataURL> element + }, + "LegendURL": function(node, obj) { + obj.legend = {}; + obj.legend.href = node.getAttribute("xlink:href"); + obj.legend.format = node.getAttribute("format"); + }, + "Dimension": function(node, obj) { + var dimension = {values: []}; + this.readChildNodes(node, dimension); + obj.dimensions.push(dimension); + }, + "Default": function(node, obj) { + obj["default"] = this.getChildValue(node); + }, + "Value": function(node, obj) { + obj.values.push(this.getChildValue(node)); + } + }, + "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] + }, + + CLASS_NAME: "OpenLayers.Format.WMTSCapabilities.v1_0_0" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WPSCapabilities.js b/misc/openlayers/lib/OpenLayers/Format/WPSCapabilities.js new file mode 100644 index 0000000..f0d74db --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WPSCapabilities.js @@ -0,0 +1,48 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML/VersionedOGC.js + */ + +/** + * Class: OpenLayers.Format.WPSCapabilities + * Read WPS Capabilities. + * + * Inherits from: + * - <OpenLayers.Format.XML.VersionedOGC> + */ +OpenLayers.Format.WPSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { + + /** + * APIProperty: defaultVersion + * {String} Version number to assume if none found. Default is "1.0.0". + */ + defaultVersion: "1.0.0", + + /** + * Constructor: OpenLayers.Format.WPSCapabilities + * Create a new parser for WPS Capabilities. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Read capabilities data from a string, and return information about + * the service. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Object} Info about the WPS + */ + + CLASS_NAME: "OpenLayers.Format.WPSCapabilities" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WPSCapabilities/v1_0_0.js b/misc/openlayers/lib/OpenLayers/Format/WPSCapabilities/v1_0_0.js new file mode 100644 index 0000000..e6762a9 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WPSCapabilities/v1_0_0.js @@ -0,0 +1,119 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WPSCapabilities.js + * @requires OpenLayers/Format/OWSCommon/v1_1_0.js + */ + +/** + * Class: OpenLayers.Format.WPSCapabilities.v1_0_0 + * Read WPS Capabilities version 1.0.0. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.WPSCapabilities.v1_0_0 = OpenLayers.Class( + OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + ows: "http://www.opengis.net/ows/1.1", + wps: "http://www.opengis.net/wps/1.0.0", + xlink: "http://www.w3.org/1999/xlink" + }, + + /** + * Property: regExes + * Compiled regular expressions for manipulating strings. + */ + regExes: { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g) + }, + + /** + * Constructor: OpenLayers.Format.WPSCapabilities.v1_0_0 + * Create a new parser for WPS capabilities version 1.0.0. + * + * 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]); + }, + + /** + * APIMethod: read + * Read capabilities data from a string, and return info about the WPS. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Object} Information about the WPS service. + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + if(data && data.nodeType == 9) { + data = data.documentElement; + } + var capabilities = {}; + this.readNode(data, capabilities); + return capabilities; + }, + + /** + * 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: { + "wps": { + "Capabilities": function(node, obj) { + this.readChildNodes(node, obj); + }, + "ProcessOfferings": function(node, obj) { + obj.processOfferings = {}; + this.readChildNodes(node, obj.processOfferings); + }, + "Process": function(node, processOfferings) { + var processVersion = this.getAttributeNS(node, this.namespaces.wps, "processVersion"); + var process = {processVersion: processVersion}; + this.readChildNodes(node, process); + processOfferings[process.identifier] = process; + }, + "Languages": function(node, obj) { + obj.languages = []; + this.readChildNodes(node, obj.languages); + }, + "Default": function(node, languages) { + var language = {isDefault: true}; + this.readChildNodes(node, language); + languages.push(language); + }, + "Supported": function(node, languages) { + var language = {}; + this.readChildNodes(node, language); + languages.push(language); + } + }, + "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] + }, + + CLASS_NAME: "OpenLayers.Format.WPSCapabilities.v1_0_0" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WPSDescribeProcess.js b/misc/openlayers/lib/OpenLayers/Format/WPSDescribeProcess.js new file mode 100644 index 0000000..e8f96bb --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WPSDescribeProcess.js @@ -0,0 +1,185 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Format/OWSCommon/v1_1_0.js + */ + +/** + * Class: OpenLayers.Format.WPSDescribeProcess + * Read WPS DescribeProcess responses. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.WPSDescribeProcess = OpenLayers.Class( + OpenLayers.Format.XML, { + + /** + * Constant: VERSION + * {String} 1.0.0 + */ + VERSION: "1.0.0", + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + wps: "http://www.opengis.net/wps/1.0.0", + ows: "http://www.opengis.net/ows/1.1", + xsi: "http://www.w3.org/2001/XMLSchema-instance" + }, + + /** + * Property: schemaLocation + * {String} Schema location + */ + schemaLocation: "http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd", + + /** + * Property: defaultPrefix + */ + defaultPrefix: "wps", + + /** + * Property: regExes + * Compiled regular expressions for manipulating strings. + */ + regExes: { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g) + }, + + /** + * Constructor: OpenLayers.Format.WPSDescribeProcess + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Parse a WPS DescribeProcess and return an object with its information. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Object} + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + if(data && data.nodeType == 9) { + data = data.documentElement; + } + var info = {}; + this.readNode(data, info); + return info; + }, + + /** + * 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: { + "wps": { + "ProcessDescriptions": function(node, obj) { + obj.processDescriptions = {}; + this.readChildNodes(node, obj.processDescriptions); + }, + "ProcessDescription": function(node, processDescriptions) { + var processVersion = this.getAttributeNS(node, this.namespaces.wps, "processVersion"); + var processDescription = { + processVersion: processVersion, + statusSupported: (node.getAttribute("statusSupported") === "true"), + storeSupported: (node.getAttribute("storeSupported") === "true") + }; + this.readChildNodes(node, processDescription); + processDescriptions[processDescription.identifier] = processDescription; + }, + "DataInputs": function(node, processDescription) { + processDescription.dataInputs = []; + this.readChildNodes(node, processDescription.dataInputs); + }, + "ProcessOutputs": function(node, processDescription) { + processDescription.processOutputs = []; + this.readChildNodes(node, processDescription.processOutputs); + }, + "Output": function(node, processOutputs) { + var output = {}; + this.readChildNodes(node, output); + processOutputs.push(output); + }, + "ComplexOutput": function(node, output) { + output.complexOutput = {}; + this.readChildNodes(node, output.complexOutput); + }, + "LiteralOutput": function(node, output) { + output.literalOutput = {}; + this.readChildNodes(node, output.literalOutput); + }, + "Input": function(node, dataInputs) { + var input = { + maxOccurs: parseInt(node.getAttribute("maxOccurs")), + minOccurs: parseInt(node.getAttribute("minOccurs")) + }; + this.readChildNodes(node, input); + dataInputs.push(input); + }, + "BoundingBoxData": function(node, input) { + input.boundingBoxData = {}; + this.readChildNodes(node, input.boundingBoxData); + }, + "CRS": function(node, obj) { + if (!obj.CRSs) { + obj.CRSs = {}; + } + obj.CRSs[this.getChildValue(node)] = true; + }, + "LiteralData": function(node, input) { + input.literalData = {}; + this.readChildNodes(node, input.literalData); + }, + "ComplexData": function(node, input) { + input.complexData = {}; + this.readChildNodes(node, input.complexData); + }, + "Default": function(node, complexData) { + complexData["default"] = {}; + this.readChildNodes(node, complexData["default"]); + }, + "Supported": function(node, complexData) { + complexData["supported"] = {}; + this.readChildNodes(node, complexData["supported"]); + }, + "Format": function(node, obj) { + var format = {}; + this.readChildNodes(node, format); + if (!obj.formats) { + obj.formats = {}; + } + obj.formats[format.mimeType] = true; + }, + "MimeType": function(node, format) { + format.mimeType = this.getChildValue(node); + } + }, + "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] + }, + + CLASS_NAME: "OpenLayers.Format.WPSDescribeProcess" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/WPSExecute.js b/misc/openlayers/lib/OpenLayers/Format/WPSExecute.js new file mode 100644 index 0000000..0795b0d --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/WPSExecute.js @@ -0,0 +1,395 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Format/OWSCommon/v1_1_0.js + * @requires OpenLayers/Format/WCSGetCoverage.js + * @requires OpenLayers/Format/WFST/v1_1_0.js + */ + +/** + * Class: OpenLayers.Format.WPSExecute version 1.0.0 + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.WPSExecute = OpenLayers.Class(OpenLayers.Format.XML, + OpenLayers.Format.Filter.v1_1_0, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + ows: "http://www.opengis.net/ows/1.1", + gml: "http://www.opengis.net/gml", + wps: "http://www.opengis.net/wps/1.0.0", + wfs: "http://www.opengis.net/wfs", + ogc: "http://www.opengis.net/ogc", + wcs: "http://www.opengis.net/wcs", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance" + }, + + /** + * Property: regExes + * Compiled regular expressions for manipulating strings. + */ + regExes: { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g) + }, + + /** + * Constant: VERSION + * {String} 1.0.0 + */ + VERSION: "1.0.0", + + /** + * Property: schemaLocation + * {String} Schema location + */ + schemaLocation: "http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd", + + schemaLocationAttr: function(options) { + return undefined; + }, + + /** + * Constructor: OpenLayers.Format.WPSExecute + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * Method: write + * + * Parameters: + * options - {Object} Optional object. + * + * Returns: + * {String} An WPS Execute request XML string. + */ + write: function(options) { + var doc; + if (window.ActiveXObject) { + doc = new ActiveXObject("Microsoft.XMLDOM"); + this.xmldom = doc; + } else { + doc = document.implementation.createDocument("", "", null); + } + var node = this.writeNode("wps:Execute", options, doc); + this.setAttributeNS( + node, this.namespaces.xsi, + "xsi:schemaLocation", this.schemaLocation + ); + return OpenLayers.Format.XML.prototype.write.apply(this, [node]); + }, + + /** + * APIMethod: read + * Parse a WPS Execute and return an object with its information. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Object} + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + if(data && data.nodeType == 9) { + data = data.documentElement; + } + var info = {}; + this.readNode(data, info); + return info; + }, + + /** + * 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: { + "wps": { + "Execute": function(options) { + var node = this.createElementNSPlus("wps:Execute", { + attributes: { + version: this.VERSION, + service: 'WPS' + } + }); + this.writeNode("ows:Identifier", options.identifier, node); + this.writeNode("wps:DataInputs", options.dataInputs, node); + this.writeNode("wps:ResponseForm", options.responseForm, node); + return node; + }, + "ResponseForm": function(responseForm) { + var node = this.createElementNSPlus("wps:ResponseForm", {}); + if (responseForm.rawDataOutput) { + this.writeNode("wps:RawDataOutput", responseForm.rawDataOutput, node); + } + if (responseForm.responseDocument) { + this.writeNode("wps:ResponseDocument", responseForm.responseDocument, node); + } + return node; + }, + "ResponseDocument": function(responseDocument) { + var node = this.createElementNSPlus("wps:ResponseDocument", { + attributes: { + storeExecuteResponse: responseDocument.storeExecuteResponse, + lineage: responseDocument.lineage, + status: responseDocument.status + } + }); + if (responseDocument.outputs) { + for (var i = 0, len = responseDocument.outputs.length; i < len; i++) { + this.writeNode("wps:Output", responseDocument.outputs[i], node); + } + } + return node; + }, + "Output": function(output) { + var node = this.createElementNSPlus("wps:Output", { + attributes: { + asReference: output.asReference, + mimeType: output.mimeType, + encoding: output.encoding, + schema: output.schema + } + }); + this.writeNode("ows:Identifier", output.identifier, node); + this.writeNode("ows:Title", output.title, node); + this.writeNode("ows:Abstract", output["abstract"], node); + return node; + }, + "RawDataOutput": function(rawDataOutput) { + var node = this.createElementNSPlus("wps:RawDataOutput", { + attributes: { + mimeType: rawDataOutput.mimeType, + encoding: rawDataOutput.encoding, + schema: rawDataOutput.schema + } + }); + this.writeNode("ows:Identifier", rawDataOutput.identifier, node); + return node; + }, + "DataInputs": function(dataInputs) { + var node = this.createElementNSPlus("wps:DataInputs", {}); + for (var i=0, ii=dataInputs.length; i<ii; ++i) { + this.writeNode("wps:Input", dataInputs[i], node); + } + return node; + }, + "Input": function(input) { + var node = this.createElementNSPlus("wps:Input", {}); + this.writeNode("ows:Identifier", input.identifier, node); + if (input.title) { + this.writeNode("ows:Title", input.title, node); + } + if (input.data) { + this.writeNode("wps:Data", input.data, node); + } + if (input.reference) { + this.writeNode("wps:Reference", input.reference, node); + } + if (input.boundingBoxData) { + this.writeNode("wps:BoundingBoxData", input.boundingBoxData, node); + } + return node; + }, + "Data": function(data) { + var node = this.createElementNSPlus("wps:Data", {}); + if (data.literalData) { + this.writeNode("wps:LiteralData", data.literalData, node); + } else if (data.complexData) { + this.writeNode("wps:ComplexData", data.complexData, node); + } else if (data.boundingBoxData) { + this.writeNode("ows:BoundingBox", data.boundingBoxData, node); + } + return node; + }, + "LiteralData": function(literalData) { + var node = this.createElementNSPlus("wps:LiteralData", { + attributes: { + uom: literalData.uom + }, + value: literalData.value + }); + return node; + }, + "ComplexData": function(complexData) { + var node = this.createElementNSPlus("wps:ComplexData", { + attributes: { + mimeType: complexData.mimeType, + encoding: complexData.encoding, + schema: complexData.schema + } + }); + var data = complexData.value; + if (typeof data === "string") { + node.appendChild( + this.getXMLDoc().createCDATASection(complexData.value) + ); + } else { + node.appendChild(data); + } + return node; + }, + "Reference": function(reference) { + var node = this.createElementNSPlus("wps:Reference", { + attributes: { + mimeType: reference.mimeType, + "xlink:href": reference.href, + method: reference.method, + encoding: reference.encoding, + schema: reference.schema + } + }); + if (reference.body) { + this.writeNode("wps:Body", reference.body, node); + } + return node; + }, + "BoundingBoxData": function(node, obj) { + this.writers['ows']['BoundingBox'].apply(this, [node, obj, "wps:BoundingBoxData"]); + }, + "Body": function(body) { + var node = this.createElementNSPlus("wps:Body", {}); + if (body.wcs) { + this.writeNode("wcs:GetCoverage", body.wcs, node); + } + else if (body.wfs) { + // OpenLayers.Format.WFST expects these to be on the + // instance and not in the options + this.featureType = body.wfs.featureType; + this.version = body.wfs.version; + this.writeNode("wfs:GetFeature", body.wfs, node); + } else { + this.writeNode("wps:Execute", body, node); + } + return node; + } + }, + "wcs": OpenLayers.Format.WCSGetCoverage.prototype.writers.wcs, + "wfs": OpenLayers.Format.WFST.v1_1_0.prototype.writers.wfs, + "ogc": OpenLayers.Format.Filter.v1_1_0.prototype.writers.ogc, + "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.writers.ows + }, + + /** + * 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: { + "wps": { + "ExecuteResponse": function(node, obj) { + obj.executeResponse = { + lang: node.getAttribute("lang"), + statusLocation: node.getAttribute("statusLocation"), + serviceInstance: node.getAttribute("serviceInstance"), + service: node.getAttribute("service") + }; + this.readChildNodes(node, obj.executeResponse); + }, + "Process":function(node,obj) { + obj.process = {}; + this.readChildNodes(node, obj.process); + }, + "Status":function(node,obj) { + obj.status = { + creationTime: node.getAttribute("creationTime") + }; + this.readChildNodes(node, obj.status); + }, + "ProcessSucceeded": function(node,obj) { + obj.processSucceeded = true; + }, + "ProcessOutputs": function(node, processDescription) { + processDescription.processOutputs = []; + this.readChildNodes(node, processDescription.processOutputs); + }, + "Output": function(node, processOutputs) { + var output = {}; + this.readChildNodes(node, output); + processOutputs.push(output); + }, + "Reference": function(node, output) { + output.reference = { + href: node.getAttribute("href"), + mimeType: node.getAttribute("mimeType"), + encoding: node.getAttribute("encoding"), + schema: node.getAttribute("schema") + }; + }, + "Data": function(node, output) { + output.data = {}; + this.readChildNodes(node, output); + }, + "LiteralData": function(node, output) { + output.literalData = { + dataType: node.getAttribute("dataType"), + uom: node.getAttribute("uom"), + value: this.getChildValue(node) + }; + }, + "ComplexData": function(node, output) { + output.complexData = { + mimeType: node.getAttribute("mimeType"), + schema: node.getAttribute("schema"), + encoding: node.getAttribute("encoding"), + value: "" + }; + + // try to get *some* value, ignore the empty text values + if (this.isSimpleContent(node)) { + var child; + for(child=node.firstChild; child; child=child.nextSibling) { + switch(child.nodeType) { + case 3: // text node + case 4: // cdata section + output.complexData.value += child.nodeValue; + } + } + } + else { + for(child=node.firstChild; child; child=child.nextSibling) { + if (child.nodeType == 1) { + output.complexData.value = child; + } + } + } + + }, + "BoundingBox": function(node, output) { + output.boundingBoxData = { + dimensions: node.getAttribute("dimensions"), + crs: node.getAttribute("crs") + }; + this.readChildNodes(node, output.boundingBoxData); + } + }, + + // TODO: we should add Exception parsing here + "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] + }, + + CLASS_NAME: "OpenLayers.Format.WPSExecute" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/XLS.js b/misc/openlayers/lib/OpenLayers/Format/XLS.js new file mode 100644 index 0000000..76f3f10 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/XLS.js @@ -0,0 +1,68 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML/VersionedOGC.js + */ + +/** + * Class: OpenLayers.Format.XLS + * Read/Write XLS (OpenLS). Create a new instance with the <OpenLayers.Format.XLS> + * constructor. Currently only implemented for Location Utility Services, more + * specifically only for Geocoding. No support for Reverse Geocoding as yet. + * + * Inherits from: + * - <OpenLayers.Format.XML.VersionedOGC> + */ +OpenLayers.Format.XLS = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { + + /** + * APIProperty: defaultVersion + * {String} Version number to assume if none found. Default is "1.1.0". + */ + defaultVersion: "1.1.0", + + /** + * APIProperty: stringifyOutput + * {Boolean} If true, write will return a string otherwise a DOMElement. + * Default is true. + */ + stringifyOutput: true, + + /** + * Constructor: OpenLayers.Format.XLS + * Create a new parser for XLS. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: write + * Write out an XLS request. + * + * Parameters: + * request - {Object} An object representing the LUS request. + * options - {Object} Optional configuration object. + * + * Returns: + * {String} An XLS document string. + */ + + /** + * APIMethod: read + * Read an XLS doc and return an object representing the result. + * + * Parameters: + * data - {String | DOMElement} Data to read. + * options - {Object} Options for the reader. + * + * Returns: + * {Object} An object representing the GeocodeResponse. + */ + + CLASS_NAME: "OpenLayers.Format.XLS" +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/XLS/v1.js b/misc/openlayers/lib/OpenLayers/Format/XLS/v1.js new file mode 100644 index 0000000..642474f --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/XLS/v1.js @@ -0,0 +1,304 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XLS.js + * @requires OpenLayers/Format/GML/v3.js + */ + +/** + * Class: OpenLayers.Format.XLS.v1 + * Superclass for XLS version 1 parsers. Only supports GeocodeRequest for now. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.XLS.v1 = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + xls: "http://www.opengis.net/xls", + gml: "http://www.opengis.net/gml", + xsi: "http://www.w3.org/2001/XMLSchema-instance" + }, + + /** + * Property: regExes + * Compiled regular expressions for manipulating strings. + */ + regExes: { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g) + }, + + /** + * APIProperty: xy + * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x) + * Changing is not recommended, a new Format should be instantiated. + */ + xy: true, + + /** + * Property: defaultPrefix + */ + defaultPrefix: "xls", + + /** + * Property: schemaLocation + * {String} Schema location for a particular minor version. + */ + schemaLocation: null, + + /** + * Constructor: OpenLayers.Format.XLS.v1 + * Instances of this class are not created directly. Use the + * <OpenLayers.Format.XLS> constructor instead. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * Method: read + * + * Parameters: + * data - {DOMElement} An XLS document element. + * options - {Object} Options for the reader. + * + * Returns: + * {Object} An object representing the XLSResponse. + */ + read: function(data, options) { + options = OpenLayers.Util.applyDefaults(options, this.options); + var xls = {}; + this.readChildNodes(data, xls); + return xls; + }, + + /** + * 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: { + "xls": { + "XLS": function(node, xls) { + xls.version = node.getAttribute("version"); + this.readChildNodes(node, xls); + }, + "Response": function(node, xls) { + this.readChildNodes(node, xls); + }, + "GeocodeResponse": function(node, xls) { + xls.responseLists = []; + this.readChildNodes(node, xls); + }, + "GeocodeResponseList": function(node, xls) { + var responseList = { + features: [], + numberOfGeocodedAddresses: + parseInt(node.getAttribute("numberOfGeocodedAddresses")) + }; + xls.responseLists.push(responseList); + this.readChildNodes(node, responseList); + }, + "GeocodedAddress": function(node, responseList) { + var feature = new OpenLayers.Feature.Vector(); + responseList.features.push(feature); + this.readChildNodes(node, feature); + // post-process geometry + feature.geometry = feature.components[0]; + }, + "GeocodeMatchCode": function(node, feature) { + feature.attributes.matchCode = { + accuracy: parseFloat(node.getAttribute("accuracy")), + matchType: node.getAttribute("matchType") + }; + }, + "Address": function(node, feature) { + var address = { + countryCode: node.getAttribute("countryCode"), + addressee: node.getAttribute("addressee"), + street: [], + place: [] + }; + feature.attributes.address = address; + this.readChildNodes(node, address); + }, + "freeFormAddress": function(node, address) { + address.freeFormAddress = this.getChildValue(node); + }, + "StreetAddress": function(node, address) { + this.readChildNodes(node, address); + }, + "Building": function(node, address) { + address.building = { + 'number': node.getAttribute("number"), + subdivision: node.getAttribute("subdivision"), + buildingName: node.getAttribute("buildingName") + }; + }, + "Street": function(node, address) { + // only support the built-in primitive type for now + address.street.push(this.getChildValue(node)); + }, + "Place": function(node, address) { + // type is one of CountrySubdivision, + // CountrySecondarySubdivision, Municipality or + // MunicipalitySubdivision + address.place[node.getAttribute("type")] = + this.getChildValue(node); + }, + "PostalCode": function(node, address) { + address.postalCode = this.getChildValue(node); + } + }, + "gml": OpenLayers.Format.GML.v3.prototype.readers.gml + }, + + /** + * Method: write + * + * Parameters: + * request - {Object} An object representing the geocode request. + * + * Returns: + * {DOMElement} The root of an XLS document. + */ + write: function(request) { + return this.writers.xls.XLS.apply(this, [request]); + }, + + /** + * 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: { + "xls": { + "XLS": function(request) { + var root = this.createElementNSPlus( + "xls:XLS", + {attributes: { + "version": this.VERSION, + "xsi:schemaLocation": this.schemaLocation + }} + ); + this.writeNode("RequestHeader", request.header, root); + this.writeNode("Request", request, root); + return root; + }, + "RequestHeader": function(header) { + return this.createElementNSPlus("xls:RequestHeader"); + }, + "Request": function(request) { + var node = this.createElementNSPlus("xls:Request", { + attributes: { + methodName: "GeocodeRequest", + requestID: request.requestID || "", + version: this.VERSION + } + }); + this.writeNode("GeocodeRequest", request.addresses, node); + return node; + }, + "GeocodeRequest": function(addresses) { + var node = this.createElementNSPlus("xls:GeocodeRequest"); + for (var i=0, len=addresses.length; i<len; i++) { + this.writeNode("Address", addresses[i], node); + } + return node; + }, + "Address": function(address) { + var node = this.createElementNSPlus("xls:Address", { + attributes: { + countryCode: address.countryCode + } + }); + if (address.freeFormAddress) { + this.writeNode("freeFormAddress", address.freeFormAddress, node); + } else { + if (address.street) { + this.writeNode("StreetAddress", address, node); + } + if (address.municipality) { + this.writeNode("Municipality", address.municipality, node); + } + if (address.countrySubdivision) { + this.writeNode("CountrySubdivision", address.countrySubdivision, node); + } + if (address.postalCode) { + this.writeNode("PostalCode", address.postalCode, node); + } + } + return node; + }, + "freeFormAddress": function(freeFormAddress) { + return this.createElementNSPlus("freeFormAddress", + {value: freeFormAddress}); + }, + "StreetAddress": function(address) { + var node = this.createElementNSPlus("xls:StreetAddress"); + if (address.building) { + this.writeNode(node, "Building", address.building); + } + var street = address.street; + if (!(OpenLayers.Util.isArray(street))) { + street = [street]; + } + for (var i=0, len=street.length; i < len; i++) { + this.writeNode("Street", street[i], node); + } + return node; + }, + "Building": function(building) { + return this.createElementNSPlus("xls:Building", { + attributes: { + "number": building["number"], + "subdivision": building.subdivision, + "buildingName": building.buildingName + } + }); + }, + "Street": function(street) { + return this.createElementNSPlus("xls:Street", {value: street}); + }, + "Municipality": function(municipality) { + return this.createElementNSPlus("xls:Place", { + attributes: { + type: "Municipality" + }, + value: municipality + }); + }, + "CountrySubdivision": function(countrySubdivision) { + return this.createElementNSPlus("xls:Place", { + attributes: { + type: "CountrySubdivision" + }, + value: countrySubdivision + }); + }, + "PostalCode": function(postalCode) { + return this.createElementNSPlus("xls:PostalCode", { + value: postalCode + }); + } + } + }, + + CLASS_NAME: "OpenLayers.Format.XLS.v1" + +}); diff --git a/misc/openlayers/lib/OpenLayers/Format/XLS/v1_1_0.js b/misc/openlayers/lib/OpenLayers/Format/XLS/v1_1_0.js new file mode 100644 index 0000000..7ffca26 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/XLS/v1_1_0.js @@ -0,0 +1,48 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XLS/v1.js + */ + +/** + * Class: OpenLayers.Format.XLS.v1_1_0 + * Read / write XLS version 1.1.0. + * + * Inherits from: + * - <OpenLayers.Format.XLS.v1> + */ +OpenLayers.Format.XLS.v1_1_0 = OpenLayers.Class( + OpenLayers.Format.XLS.v1, { + + /** + * Constant: VERSION + * {String} 1.1 + */ + VERSION: "1.1", + + /** + * Property: schemaLocation + * {String} http://www.opengis.net/xls + * http://schemas.opengis.net/ols/1.1.0/LocationUtilityService.xsd + */ + schemaLocation: "http://www.opengis.net/xls http://schemas.opengis.net/ols/1.1.0/LocationUtilityService.xsd", + + /** + * Constructor: OpenLayers.Format.XLS.v1_1_0 + * Instances of this class are not created directly. Use the + * <OpenLayers.Format.XLS> constructor instead. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + CLASS_NAME: "OpenLayers.Format.XLS.v1_1_0" + +}); + +// Support non standard implementation +OpenLayers.Format.XLS.v1_1 = OpenLayers.Format.XLS.v1_1_0; diff --git a/misc/openlayers/lib/OpenLayers/Format/XML.js b/misc/openlayers/lib/OpenLayers/Format/XML.js new file mode 100644 index 0000000..56f5871 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/XML.js @@ -0,0 +1,897 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format.js + */ + +/** + * Class: OpenLayers.Format.XML + * Read and write XML. For cross-browser XML generation, use methods on an + * instance of the XML format class instead of on <code>document<end>. + * The DOM creation and traversing methods exposed here all mimic the + * W3C XML DOM methods. Create a new parser with the + * <OpenLayers.Format.XML> constructor. + * + * Inherits from: + * - <OpenLayers.Format> + */ +OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. Properties + * of this object should not be set individually. Read-only. All + * XML subclasses should have their own namespaces object. Use + * <setNamespace> to add or set a namespace alias after construction. + */ + namespaces: null, + + /** + * Property: namespaceAlias + * {Object} Mapping of namespace URI to namespace alias. This object + * is read-only. Use <setNamespace> to add or set a namespace alias. + */ + namespaceAlias: null, + + /** + * Property: defaultPrefix + * {String} The default namespace alias for creating element nodes. + */ + defaultPrefix: null, + + /** + * 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: {}, + + /** + * 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: {}, + + /** + * Property: xmldom + * {XMLDom} If this browser uses ActiveX, this will be set to a XMLDOM + * object. It is not intended to be a browser sniffing property. + * Instead, the xmldom property is used instead of <code>document<end> + * where namespaced node creation methods are not supported. In all + * other browsers, this remains null. + */ + xmldom: null, + + /** + * Constructor: OpenLayers.Format.XML + * Construct an XML parser. The parser is used to read and write XML. + * Reading XML from a string returns a DOM element. Writing XML from + * a DOM element returns a string. + * + * Parameters: + * options - {Object} Optional object whose properties will be set on + * the object. + */ + initialize: function(options) { + if(window.ActiveXObject) { + this.xmldom = new ActiveXObject("Microsoft.XMLDOM"); + } + OpenLayers.Format.prototype.initialize.apply(this, [options]); + // clone the namespace object and set all namespace aliases + this.namespaces = OpenLayers.Util.extend({}, this.namespaces); + this.namespaceAlias = {}; + for(var alias in this.namespaces) { + this.namespaceAlias[this.namespaces[alias]] = alias; + } + }, + + /** + * APIMethod: destroy + * Clean up. + */ + destroy: function() { + this.xmldom = null; + OpenLayers.Format.prototype.destroy.apply(this, arguments); + }, + + /** + * Method: setNamespace + * Set a namespace alias and URI for the format. + * + * Parameters: + * alias - {String} The namespace alias (prefix). + * uri - {String} The namespace URI. + */ + setNamespace: function(alias, uri) { + this.namespaces[alias] = uri; + this.namespaceAlias[uri] = alias; + }, + + /** + * APIMethod: read + * Deserialize a XML string and return a DOM node. + * + * Parameters: + * text - {String} A XML string + + * Returns: + * {DOMElement} A DOM node + */ + read: function(text) { + var index = text.indexOf('<'); + if(index > 0) { + text = text.substring(index); + } + var node = OpenLayers.Util.Try( + OpenLayers.Function.bind(( + function() { + var xmldom; + /** + * Since we want to be able to call this method on the prototype + * itself, this.xmldom may not exist even if in IE. + */ + if(window.ActiveXObject && !this.xmldom) { + xmldom = new ActiveXObject("Microsoft.XMLDOM"); + } else { + xmldom = this.xmldom; + + } + xmldom.loadXML(text); + return xmldom; + } + ), this), + function() { + return new DOMParser().parseFromString(text, 'text/xml'); + }, + function() { + var req = new XMLHttpRequest(); + req.open("GET", "data:" + "text/xml" + + ";charset=utf-8," + encodeURIComponent(text), false); + if(req.overrideMimeType) { + req.overrideMimeType("text/xml"); + } + req.send(null); + return req.responseXML; + } + ); + + if(this.keepData) { + this.data = node; + } + + return node; + }, + + /** + * APIMethod: write + * Serialize a DOM node into a XML string. + * + * Parameters: + * node - {DOMElement} A DOM node. + * + * Returns: + * {String} The XML string representation of the input node. + */ + write: function(node) { + var data; + if(this.xmldom) { + data = node.xml; + } else { + var serializer = new XMLSerializer(); + if (node.nodeType == 1) { + // Add nodes to a document before serializing. Everything else + // is serialized as is. This may need more work. See #1218 . + var doc = document.implementation.createDocument("", "", null); + if (doc.importNode) { + node = doc.importNode(node, true); + } + doc.appendChild(node); + data = serializer.serializeToString(doc); + } else { + data = serializer.serializeToString(node); + } + } + return data; + }, + + /** + * APIMethod: createElementNS + * Create a new element with namespace. This node can be appended to + * another node with the standard node.appendChild method. For + * cross-browser support, this method must be used instead of + * document.createElementNS. + * + * Parameters: + * uri - {String} Namespace URI for the element. + * name - {String} The qualified name of the element (prefix:localname). + * + * Returns: + * {Element} A DOM element with namespace. + */ + createElementNS: function(uri, name) { + var element; + if(this.xmldom) { + if(typeof uri == "string") { + element = this.xmldom.createNode(1, name, uri); + } else { + element = this.xmldom.createNode(1, name, ""); + } + } else { + element = document.createElementNS(uri, name); + } + return element; + }, + + /** + * APIMethod: createDocumentFragment + * Create a document fragment node that can be appended to another node + * created by createElementNS. This will call + * document.createDocumentFragment outside of IE. In IE, the ActiveX + * object's createDocumentFragment method is used. + * + * Returns: + * {Element} A document fragment. + */ + createDocumentFragment: function() { + var element; + if (this.xmldom) { + element = this.xmldom.createDocumentFragment(); + } else { + element = document.createDocumentFragment(); + } + return element; + }, + + /** + * APIMethod: createTextNode + * Create a text node. This node can be appended to another node with + * the standard node.appendChild method. For cross-browser support, + * this method must be used instead of document.createTextNode. + * + * Parameters: + * text - {String} The text of the node. + * + * Returns: + * {DOMElement} A DOM text node. + */ + createTextNode: function(text) { + var node; + if (typeof text !== "string") { + text = String(text); + } + if(this.xmldom) { + node = this.xmldom.createTextNode(text); + } else { + node = document.createTextNode(text); + } + return node; + }, + + /** + * APIMethod: getElementsByTagNameNS + * Get a list of elements on a node given the namespace URI and local name. + * To return all nodes in a given namespace, use '*' for the name + * argument. To return all nodes of a given (local) name, regardless + * of namespace, use '*' for the uri argument. + * + * Parameters: + * node - {Element} Node on which to search for other nodes. + * uri - {String} Namespace URI. + * name - {String} Local name of the tag (without the prefix). + * + * Returns: + * {NodeList} A node list or array of elements. + */ + getElementsByTagNameNS: function(node, uri, name) { + var elements = []; + if(node.getElementsByTagNameNS) { + elements = node.getElementsByTagNameNS(uri, name); + } else { + // brute force method + var allNodes = node.getElementsByTagName("*"); + var potentialNode, fullName; + for(var i=0, len=allNodes.length; i<len; ++i) { + potentialNode = allNodes[i]; + fullName = (potentialNode.prefix) ? + (potentialNode.prefix + ":" + name) : name; + if((name == "*") || (fullName == potentialNode.nodeName)) { + if((uri == "*") || (uri == potentialNode.namespaceURI)) { + elements.push(potentialNode); + } + } + } + } + return elements; + }, + + /** + * APIMethod: getAttributeNodeNS + * Get an attribute node given the namespace URI and local name. + * + * Parameters: + * node - {Element} Node on which to search for attribute nodes. + * uri - {String} Namespace URI. + * name - {String} Local name of the attribute (without the prefix). + * + * Returns: + * {DOMElement} An attribute node or null if none found. + */ + getAttributeNodeNS: function(node, uri, name) { + var attributeNode = null; + if(node.getAttributeNodeNS) { + attributeNode = node.getAttributeNodeNS(uri, name); + } else { + var attributes = node.attributes; + var potentialNode, fullName; + for(var i=0, len=attributes.length; i<len; ++i) { + potentialNode = attributes[i]; + if(potentialNode.namespaceURI == uri) { + fullName = (potentialNode.prefix) ? + (potentialNode.prefix + ":" + name) : name; + if(fullName == potentialNode.nodeName) { + attributeNode = potentialNode; + break; + } + } + } + } + return attributeNode; + }, + + /** + * APIMethod: getAttributeNS + * Get an attribute value given the namespace URI and local name. + * + * Parameters: + * node - {Element} Node on which to search for an attribute. + * uri - {String} Namespace URI. + * name - {String} Local name of the attribute (without the prefix). + * + * Returns: + * {String} An attribute value or and empty string if none found. + */ + getAttributeNS: function(node, uri, name) { + var attributeValue = ""; + if(node.getAttributeNS) { + attributeValue = node.getAttributeNS(uri, name) || ""; + } else { + var attributeNode = this.getAttributeNodeNS(node, uri, name); + if(attributeNode) { + attributeValue = attributeNode.nodeValue; + } + } + return attributeValue; + }, + + /** + * APIMethod: getChildValue + * Get the textual value of the node if it exists, or return an + * optional default string. Returns an empty string if no first child + * exists and no default value is supplied. + * + * Parameters: + * node - {DOMElement} The element used to look for a first child value. + * def - {String} Optional string to return in the event that no + * first child value exists. + * + * Returns: + * {String} The value of the first child of the given node. + */ + getChildValue: function(node, def) { + var value = def || ""; + if(node) { + for(var child=node.firstChild; child; child=child.nextSibling) { + switch(child.nodeType) { + case 3: // text node + case 4: // cdata section + value += child.nodeValue; + } + } + } + return value; + }, + + /** + * APIMethod: isSimpleContent + * Test if the given node has only simple content (i.e. no child element + * nodes). + * + * Parameters: + * node - {DOMElement} An element node. + * + * Returns: + * {Boolean} The node has no child element nodes (nodes of type 1). + */ + isSimpleContent: function(node) { + var simple = true; + for(var child=node.firstChild; child; child=child.nextSibling) { + if(child.nodeType === 1) { + simple = false; + break; + } + } + return simple; + }, + + /** + * APIMethod: contentType + * Determine the content type for a given node. + * + * Parameters: + * node - {DOMElement} + * + * Returns: + * {Integer} One of OpenLayers.Format.XML.CONTENT_TYPE.{EMPTY,SIMPLE,COMPLEX,MIXED} + * if the node has no, simple, complex, or mixed content. + */ + contentType: function(node) { + var simple = false, + complex = false; + + var type = OpenLayers.Format.XML.CONTENT_TYPE.EMPTY; + + for(var child=node.firstChild; child; child=child.nextSibling) { + switch(child.nodeType) { + case 1: // element + complex = true; + break; + case 8: // comment + break; + default: + simple = true; + } + if(complex && simple) { + break; + } + } + + if(complex && simple) { + type = OpenLayers.Format.XML.CONTENT_TYPE.MIXED; + } else if(complex) { + return OpenLayers.Format.XML.CONTENT_TYPE.COMPLEX; + } else if(simple) { + return OpenLayers.Format.XML.CONTENT_TYPE.SIMPLE; + } + return type; + }, + + /** + * APIMethod: hasAttributeNS + * Determine whether a node has a particular attribute matching the given + * name and namespace. + * + * Parameters: + * node - {Element} Node on which to search for an attribute. + * uri - {String} Namespace URI. + * name - {String} Local name of the attribute (without the prefix). + * + * Returns: + * {Boolean} The node has an attribute matching the name and namespace. + */ + hasAttributeNS: function(node, uri, name) { + var found = false; + if(node.hasAttributeNS) { + found = node.hasAttributeNS(uri, name); + } else { + found = !!this.getAttributeNodeNS(node, uri, name); + } + return found; + }, + + /** + * APIMethod: setAttributeNS + * Adds a new attribute or changes the value of an attribute with the given + * namespace and name. + * + * Parameters: + * node - {Element} Element node on which to set the attribute. + * uri - {String} Namespace URI for the attribute. + * name - {String} Qualified name (prefix:localname) for the attribute. + * value - {String} Attribute value. + */ + setAttributeNS: function(node, uri, name, value) { + if(node.setAttributeNS) { + node.setAttributeNS(uri, name, value); + } else { + if(this.xmldom) { + if(uri) { + var attribute = node.ownerDocument.createNode( + 2, name, uri + ); + attribute.nodeValue = value; + node.setAttributeNode(attribute); + } else { + node.setAttribute(name, value); + } + } else { + throw "setAttributeNS not implemented"; + } + } + }, + + /** + * 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. + * + * Valid options: + * uri - {String} Optional namespace uri for the element - supply a prefix + * instead if the namespace uri is a property of the format's namespace + * object. + * attributes - {Object} Optional attributes to be set using the + * <setAttributes> method. + * value - {String} Optional text to be appended as a text node. + * + * Returns: + * {Element} An element node. + */ + createElementNSPlus: function(name, options) { + options = options || {}; + // 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) { + var 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); + } + var value = options.value; + if(value != null) { + node.appendChild(this.createTextNode(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, uri; + for(var name in obj) { + if(obj[name] != null && obj[name].toString) { + 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); + } + } + }, + + /** + * Method: readNode + * Shorthand for applying one of the named readers given the node + * namespace and local name. Readers take two args (node, obj) and + * generally extend or modify the second. + * + * Parameters: + * node - {DOMElement} The node to be read (required). + * obj - {Object} The object to be modified (optional). + * + * Returns: + * {Object} The input object, modified (or a new one if none was provided). + */ + readNode: function(node, obj) { + if(!obj) { + obj = {}; + } + var group = this.readers[node.namespaceURI ? this.namespaceAlias[node.namespaceURI]: this.defaultPrefix]; + if(group) { + var local = node.localName || node.nodeName.split(":").pop(); + var reader = group[local] || group["*"]; + if(reader) { + reader.apply(this, [node, obj]); + } + } + return obj; + }, + + /** + * Method: readChildNodes + * Shorthand for applying the named readers to all children of a node. + * For each child of type 1 (element), <readSelf> is called. + * + * Parameters: + * node - {DOMElement} The node to be read (required). + * obj - {Object} The object to be modified (optional). + * + * Returns: + * {Object} The input object, modified. + */ + readChildNodes: function(node, obj) { + if(!obj) { + obj = {}; + } + var children = node.childNodes; + var child; + for(var i=0, len=children.length; i<len; ++i) { + child = children[i]; + if(child.nodeType == 1) { + this.readNode(child, obj); + } + } + return obj; + }, + + /** + * Method: writeNode + * Shorthand for applying one of the named writers and appending the + * results to a node. If a qualified name is not provided for the + * second argument (and a local name is used instead), the namespace + * of the parent node will be assumed. + * + * Parameters: + * name - {String} The name of a node to generate. If a qualified name + * (e.g. "pre:Name") is used, the namespace prefix is assumed to be + * in the <writers> group. If a local name is used (e.g. "Name") then + * the namespace of the parent is assumed. If a local name is used + * and no parent is supplied, then the default namespace is assumed. + * obj - {Object} Structure containing data for the writer. + * parent - {DOMElement} Result will be appended to this node. If no parent + * is supplied, the node will not be appended to anything. + * + * Returns: + * {DOMElement} The child node. + */ + writeNode: function(name, obj, parent) { + var prefix, local; + var split = name.indexOf(":"); + if(split > 0) { + prefix = name.substring(0, split); + local = name.substring(split + 1); + } else { + if(parent) { + prefix = this.namespaceAlias[parent.namespaceURI]; + } else { + prefix = this.defaultPrefix; + } + local = name; + } + var child = this.writers[prefix][local].apply(this, [obj]); + if(parent) { + parent.appendChild(child); + } + return child; + }, + + /** + * APIMethod: getChildEl + * Get the first child element. Optionally only return the first child + * if it matches the given name and namespace URI. + * + * Parameters: + * node - {DOMElement} The parent node. + * name - {String} Optional node name (local) to search for. + * uri - {String} Optional namespace URI to search for. + * + * Returns: + * {DOMElement} The first child. Returns null if no element is found, if + * something significant besides an element is found, or if the element + * found does not match the optional name and uri. + */ + getChildEl: function(node, name, uri) { + return node && this.getThisOrNextEl(node.firstChild, name, uri); + }, + + /** + * APIMethod: getNextEl + * Get the next sibling element. Optionally get the first sibling only + * if it matches the given local name and namespace URI. + * + * Parameters: + * node - {DOMElement} The node. + * name - {String} Optional local name of the sibling to search for. + * uri - {String} Optional namespace URI of the sibling to search for. + * + * Returns: + * {DOMElement} The next sibling element. Returns null if no element is + * found, something significant besides an element is found, or the + * found element does not match the optional name and uri. + */ + getNextEl: function(node, name, uri) { + return node && this.getThisOrNextEl(node.nextSibling, name, uri); + }, + + /** + * Method: getThisOrNextEl + * Return this node or the next element node. Optionally get the first + * sibling with the given local name or namespace URI. + * + * Parameters: + * node - {DOMElement} The node. + * name - {String} Optional local name of the sibling to search for. + * uri - {String} Optional namespace URI of the sibling to search for. + * + * Returns: + * {DOMElement} The next sibling element. Returns null if no element is + * found, something significant besides an element is found, or the + * found element does not match the query. + */ + getThisOrNextEl: function(node, name, uri) { + outer: for(var sibling=node; sibling; sibling=sibling.nextSibling) { + switch(sibling.nodeType) { + case 1: // Element + if((!name || name === (sibling.localName || sibling.nodeName.split(":").pop())) && + (!uri || uri === sibling.namespaceURI)) { + // matches + break outer; + } + sibling = null; + break outer; + case 3: // Text + if(/^\s*$/.test(sibling.nodeValue)) { + break; + } + case 4: // CDATA + case 6: // ENTITY_NODE + case 12: // NOTATION_NODE + case 10: // DOCUMENT_TYPE_NODE + case 11: // DOCUMENT_FRAGMENT_NODE + sibling = null; + break outer; + } // ignore comments and processing instructions + } + return sibling || null; + }, + + /** + * APIMethod: lookupNamespaceURI + * Takes a prefix and returns the namespace URI associated with it on the given + * node if found (and null if not). Supplying null for the prefix will + * return the default namespace. + * + * For browsers that support it, this calls the native lookupNamesapceURI + * function. In other browsers, this is an implementation of + * http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI. + * + * For browsers that don't support the attribute.ownerElement property, this + * method cannot be called on attribute nodes. + * + * Parameters: + * node - {DOMElement} The node from which to start looking. + * prefix - {String} The prefix to lookup or null to lookup the default namespace. + * + * Returns: + * {String} The namespace URI for the given prefix. Returns null if the prefix + * cannot be found or the node is the wrong type. + */ + lookupNamespaceURI: function(node, prefix) { + var uri = null; + if(node) { + if(node.lookupNamespaceURI) { + uri = node.lookupNamespaceURI(prefix); + } else { + outer: switch(node.nodeType) { + case 1: // ELEMENT_NODE + if(node.namespaceURI !== null && node.prefix === prefix) { + uri = node.namespaceURI; + break outer; + } + var len = node.attributes.length; + if(len) { + var attr; + for(var i=0; i<len; ++i) { + attr = node.attributes[i]; + if(attr.prefix === "xmlns" && attr.name === "xmlns:" + prefix) { + uri = attr.value || null; + break outer; + } else if(attr.name === "xmlns" && prefix === null) { + uri = attr.value || null; + break outer; + } + } + } + uri = this.lookupNamespaceURI(node.parentNode, prefix); + break outer; + case 2: // ATTRIBUTE_NODE + uri = this.lookupNamespaceURI(node.ownerElement, prefix); + break outer; + case 9: // DOCUMENT_NODE + uri = this.lookupNamespaceURI(node.documentElement, prefix); + break outer; + case 6: // ENTITY_NODE + case 12: // NOTATION_NODE + case 10: // DOCUMENT_TYPE_NODE + case 11: // DOCUMENT_FRAGMENT_NODE + break outer; + default: + // TEXT_NODE (3), CDATA_SECTION_NODE (4), ENTITY_REFERENCE_NODE (5), + // PROCESSING_INSTRUCTION_NODE (7), COMMENT_NODE (8) + uri = this.lookupNamespaceURI(node.parentNode, prefix); + break outer; + } + } + } + return uri; + }, + + /** + * Method: getXMLDoc + * Get an XML document for nodes that are not supported in HTML (e.g. + * createCDATASection). On IE, this will either return an existing or + * create a new <xmldom> on the instance. On other browsers, this will + * either return an existing or create a new shared document (see + * <OpenLayers.Format.XML.document>). + * + * Returns: + * {XMLDocument} + */ + getXMLDoc: function() { + if (!OpenLayers.Format.XML.document && !this.xmldom) { + if (document.implementation && document.implementation.createDocument) { + OpenLayers.Format.XML.document = + document.implementation.createDocument("", "", null); + } else if (!this.xmldom && window.ActiveXObject) { + this.xmldom = new ActiveXObject("Microsoft.XMLDOM"); + } + } + return OpenLayers.Format.XML.document || this.xmldom; + }, + + CLASS_NAME: "OpenLayers.Format.XML" + +}); + +OpenLayers.Format.XML.CONTENT_TYPE = {EMPTY: 0, SIMPLE: 1, COMPLEX: 2, MIXED: 3}; + +/** + * APIFunction: OpenLayers.Format.XML.lookupNamespaceURI + * Takes a prefix and returns the namespace URI associated with it on the given + * node if found (and null if not). Supplying null for the prefix will + * return the default namespace. + * + * For browsers that support it, this calls the native lookupNamesapceURI + * function. In other browsers, this is an implementation of + * http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI. + * + * For browsers that don't support the attribute.ownerElement property, this + * method cannot be called on attribute nodes. + * + * Parameters: + * node - {DOMElement} The node from which to start looking. + * prefix - {String} The prefix to lookup or null to lookup the default namespace. + * + * Returns: + * {String} The namespace URI for the given prefix. Returns null if the prefix + * cannot be found or the node is the wrong type. + */ +OpenLayers.Format.XML.lookupNamespaceURI = OpenLayers.Function.bind( + OpenLayers.Format.XML.prototype.lookupNamespaceURI, + OpenLayers.Format.XML.prototype +); + +/** + * Property: OpenLayers.Format.XML.document + * {XMLDocument} XML document to reuse for creating non-HTML compliant nodes, + * like document.createCDATASection. + */ +OpenLayers.Format.XML.document = null; diff --git a/misc/openlayers/lib/OpenLayers/Format/XML/VersionedOGC.js b/misc/openlayers/lib/OpenLayers/Format/XML/VersionedOGC.js new file mode 100644 index 0000000..e68d968 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Format/XML/VersionedOGC.js @@ -0,0 +1,212 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Format/OGCExceptionReport.js + */ + +/** + * Class: OpenLayers.Format.XML.VersionedOGC + * Base class for versioned formats, i.e. a format which supports multiple + * versions. + * + * To enable checking if parsing succeeded, you will need to define a property + * called errorProperty on the parser you want to check. The parser will then + * check the returned object to see if that property is present. If it is, it + * assumes the parsing was successful. If it is not present (or is null), it will + * pass the document through an OGCExceptionReport parser. + * + * If errorProperty is undefined for the parser, this error checking mechanism + * will be disabled. + * + * + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.XML.VersionedOGC = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * APIProperty: defaultVersion + * {String} Version number to assume if none found. + */ + defaultVersion: null, + + /** + * APIProperty: version + * {String} Specify a version string if one is known. + */ + version: null, + + /** + * APIProperty: profile + * {String} If provided, use a custom profile. + */ + profile: null, + + /** + * APIProperty: allowFallback + * {Boolean} If a profiled parser cannot be found for the returned version, + * use a non-profiled parser as the fallback. Application code using this + * should take into account that the return object structure might be + * missing the specifics of the profile. Defaults to false. + */ + allowFallback: false, + + /** + * Property: name + * {String} The name of this parser, this is the part of the CLASS_NAME + * except for "OpenLayers.Format." + */ + name: null, + + /** + * APIProperty: stringifyOutput + * {Boolean} If true, write will return a string otherwise a DOMElement. + * Default is false. + */ + stringifyOutput: false, + + /** + * Property: parser + * {Object} Instance of the versioned parser. Cached for multiple read and + * write calls of the same version. + */ + parser: null, + + /** + * Constructor: OpenLayers.Format.XML.VersionedOGC. + * Constructor. + * + * Parameters: + * options - {Object} Optional object whose properties will be set on + * the object. + */ + initialize: function(options) { + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); + var className = this.CLASS_NAME; + this.name = className.substring(className.lastIndexOf(".")+1); + }, + + /** + * Method: getVersion + * Returns the version to use. Subclasses can override this function + * if a different version detection is needed. + * + * Parameters: + * root - {DOMElement} + * options - {Object} Optional configuration object. + * + * Returns: + * {String} The version to use. + */ + getVersion: function(root, options) { + var version; + // read + if (root) { + version = this.version; + if(!version) { + version = root.getAttribute("version"); + if(!version) { + version = this.defaultVersion; + } + } + } else { // write + version = (options && options.version) || + this.version || this.defaultVersion; + } + return version; + }, + + /** + * Method: getParser + * Get an instance of the cached parser if available, otherwise create one. + * + * Parameters: + * version - {String} + * + * Returns: + * {<OpenLayers.Format>} + */ + getParser: function(version) { + version = version || this.defaultVersion; + var profile = this.profile ? "_" + this.profile : ""; + if(!this.parser || this.parser.VERSION != version) { + var format = OpenLayers.Format[this.name][ + "v" + version.replace(/\./g, "_") + profile + ]; + if(!format) { + if (profile !== "" && this.allowFallback) { + // fallback to the non-profiled version of the parser + profile = ""; + format = OpenLayers.Format[this.name][ + "v" + version.replace(/\./g, "_") + ]; + } + if (!format) { + throw "Can't find a " + this.name + " parser for version " + + version + profile; + } + } + this.parser = new format(this.options); + } + return this.parser; + }, + + /** + * APIMethod: write + * Write a document. + * + * Parameters: + * obj - {Object} An object representing the document. + * options - {Object} Optional configuration object. + * + * Returns: + * {String} The document as a string + */ + write: function(obj, options) { + var version = this.getVersion(null, options); + this.parser = this.getParser(version); + var root = this.parser.write(obj, options); + if (this.stringifyOutput === false) { + return root; + } else { + return OpenLayers.Format.XML.prototype.write.apply(this, [root]); + } + }, + + /** + * APIMethod: read + * Read a doc and return an object representing the document. + * + * Parameters: + * data - {String | DOMElement} Data to read. + * options - {Object} Options for the reader. + * + * Returns: + * {Object} An object representing the document. + */ + read: function(data, options) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + var root = data.documentElement; + var version = this.getVersion(root); + this.parser = this.getParser(version); // Select the parser + var obj = this.parser.read(data, options); // Parse the data + + var errorProperty = this.parser.errorProperty || null; + if (errorProperty !== null && obj[errorProperty] === undefined) { + // an error must have happened, so parse it and report back + var format = new OpenLayers.Format.OGCExceptionReport(); + obj.error = format.read(data); + } + obj.version = version; + return obj; + }, + + CLASS_NAME: "OpenLayers.Format.XML.VersionedOGC" +}); |