/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the Clear BSD license. * See http://svn.openlayers.org/trunk/openlayers/license.txt for the * full text of the license. */ /** * @requires OpenLayers/Format/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 * @requires OpenLayers/Console.js */ /** * Class: OpenLayers.Format.GML * Read/Wite GML. Create a new instance with the * constructor. Supports the GML simple features profile. * * Inherits from: * - */ 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()} 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 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 { OpenLayers.Console.error(OpenLayers.i18n( "unsupportedGeometryType", {'geomType':type})); } // stop looking for different geometry types break; } } var bounds; var boxNodes = this.getElementsByTagNameNS(node, this.gmlns, "Box"); for(i=0; i} A point geometry. */ point: function(node) { /** * Three coordinate variations to consider: * 1) x y z * 2) x, y, z * 3) xy */ var nodeList, coordString; var coords = []; // look for 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 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 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: * {} 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} A linestring geometry. */ linestring: function(node, ring) { /** * Two coordinate variations to consider: * 1) x0 y0 z0 x1 y1 z1 * 2) x0, y0, z0 x1, y1, z1 */ var nodeList, coordString; var coords = []; var points = []; // look for 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 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} 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} 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} 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 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: * {} 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 - {} * * 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 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()} List of features to * serialize into a string. * * Returns: * {String} A string representing the GML document. */ write: function(features) { if(!(features instanceof Array)) { features = [features]; } var gml = this.createElementNS("http://www.opengis.net/wfs", "wfs:" + this.collectionName); for(var i=0; i} 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 - {} 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 - {} 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} 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 - {} 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} 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 - {} 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} 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} 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) * ... * (end) * Parameters: * 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