|
/* 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 <OpenLayers.Format.GML> |
|
* constructor. Supports the GML simple features profile. |
|
* |
|
* Inherits from: |
|
* - <OpenLayers.Format> |
|
*/ |
|
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 { |
|
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<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, |
|