GML parser.

This adds a parser (read/write) for GML v2 and v3. GML v3 is limited to the
simple features profile of GML 3.1.1, just like OpenLayers 2 was. This will
be the basis for the WFS parser, but it only makes sense to continue this work
once feature modification (insert, update, delete) is in place in ol3. So the
WFS parser will be another pull request.
This commit is contained in:
Bart van den Eijnden
2013-05-13 10:23:19 +02:00
parent 42cc4d7683
commit 5ad4734c24
55 changed files with 2679 additions and 0 deletions
+422
View File
@@ -0,0 +1,422 @@
goog.provide('ol.parser.ogc.GML_v3');
goog.require('goog.dom.xml');
goog.require('goog.object');
goog.require('ol.geom.GeometryType');
goog.require('ol.parser.ogc.GML');
/**
* @constructor
* @param {ol.parser.GML3Options=} opt_options Optional configuration object.
* @extends {ol.parser.ogc.GML}
*/
ol.parser.ogc.GML_v3 = function(opt_options) {
this.schemaLocation = 'http://www.opengis.net/gml ' +
'http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/' +
'1.0.0/gmlsf.xsd';
goog.base(this, opt_options);
if (!goog.isDef(this.surface)) {
this.surface = false;
}
if (!goog.isDef(this.curve)) {
this.curve = false;
}
if (!goog.isDef(this.multiCurve)) {
this.multiCurve = true;
}
if (!goog.isDef(this.multiSurface)) {
this.multiSurface = true;
}
this.featureNSWiters_['_geometry'] = function(geometry) {
var node = this.createElementNS('feature:' + this.geometryName,
this.featureNS);
var type = geometry.getType(), child;
if (type === ol.geom.GeometryType.POINT) {
child = this.writeNode('Point', geometry, null, node);
} else if (type === ol.geom.GeometryType.MULTIPOINT) {
child = this.writeNode('MultiPoint', geometry, null, node);
} else if (type === ol.geom.GeometryType.LINESTRING) {
if (this.curve === true) {
child = this.writeNode('Curve', geometry, null, node);
} else {
child = this.writeNode('LineString', geometry, null, node);
}
} else if (type === ol.geom.GeometryType.LINEARRING) {
child = this.writeNode('LinearRing', geometry.getCoordinates(), null,
node);
} else if (type === ol.geom.GeometryType.MULTILINESTRING) {
if (this.multiCurve === false) {
child = this.writeNode('MultiLineString', geometry, null, node);
} else {
child = this.writeNode('MultiCurve', geometry, null, node);
}
} else if (type === ol.geom.GeometryType.POLYGON) {
if (this.surface === true) {
child = this.writeNode('Surface', geometry, null, node);
} else {
child = this.writeNode('Polygon', geometry, null, node);
}
} else if (type === ol.geom.GeometryType.MULTIPOLYGON) {
if (this.multiSurface === false) {
child = this.writeNode('MultiPolygon', geometry, null, node);
} else {
child = this.writeNode('MultiSurface', geometry, null, node);
}
} else if (type === ol.geom.GeometryType.GEOMETRYCOLLECTION) {
child = this.writeNode('MultiGeometry', geometry, null, node);
}
if (goog.isDef(this.srsName)) {
this.setAttributeNS(child, null, 'srsName', this.srsName);
}
return node;
};
goog.object.extend(this.readers['http://www.opengis.net/gml'], {
'_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 coordinates = [];
this.readers[this.defaultNamespaceURI]['_inherit'].apply(this,
[node, coordinates, container]);
this.readChildNodes(node, coordinates);
var linestring = {
type: ol.geom.GeometryType.LINESTRING,
coordinates: coordinates[0]
};
// in the case of a multi geometry this is parts
if (goog.isArray(container)) {
container.push(linestring);
} else {
container.geometry = linestring;
}
},
'segments': function(node, obj) {
this.readChildNodes(node, obj);
},
'LineStringSegment': function(node, container) {
var coordinates = [];
this.readChildNodes(node, coordinates);
container.push(coordinates[0]);
},
'pos': function(node, obj) {
var str = this.getChildValue(node).replace(
this.regExes.trimSpace, '');
var coords = str.split(this.regExes.splitSpace).map(parseFloat);
if (this.xy) {
obj.push([coords]);
} else {
if (coords.length === 2) {
obj.push([coords.reverse()]);
} else if (coords.length === 3) {
obj.push([coords[1], coords[0], coords[2]]);
}
}
},
'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, ii = coords.length; i < ii; i += dim) {
x = parseFloat(coords[i]);
y = parseFloat(coords[i + 1]);
if (dim === 3) {
if (this.xy) {
points[i / dim] = [x, y, parseFloat(coords[i + 2])];
} else {
points[i / dim] = [y, x, parseFloat(coords[i + 2])];
}
} else if (dim === 2) {
if (this.xy) {
points[i / dim] = [x, y];
} else {
points[i / dim] = [y, x];
}
}
}
obj.push(points);
},
'Surface': function(node, obj) {
this.readChildNodes(node, obj);
},
'patches': function(node, obj) {
this.readChildNodes(node, obj);
},
'PolygonPatch': function(node, obj) {
this.readers[this.defaultNamespaceURI]['Polygon'].apply(this,
[node, obj]);
},
'exterior': function(node, container) {
var coordinates = [];
this.readChildNodes(node, coordinates);
container.outer = coordinates[0][0];
},
'interior': function(node, container) {
var coordinates = [];
this.readChildNodes(node, coordinates);
container.inner.push(coordinates[0][0]);
},
'MultiCurve': function(node, container) {
var parts = [];
this.readers[this.defaultNamespaceURI]['_inherit'].apply(this,
[node, parts, container]);
this.readChildNodes(node, parts);
container.geometry = {
type: ol.geom.GeometryType.MULTILINESTRING,
parts: parts
};
},
'curveMember': function(node, obj) {
this.readChildNodes(node, obj);
},
'MultiSurface': function(node, container) {
var parts = [];
this.readers[this.defaultNamespaceURI]['_inherit'].apply(this,
[node, parts, container]);
this.readChildNodes(node, parts);
container.geometry = {
type: ol.geom.GeometryType.MULTIPOLYGON,
parts: parts
};
},
'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 coordinates = [];
this.readChildNodes(node, coordinates);
container.bounds = [coordinates[0][0][0][0], coordinates[1][0][0][0],
coordinates[0][0][0][1], coordinates[1][0][0][1]];
},
'lowerCorner': function(node, envelope) {
var coordinates = [];
this.readers[this.defaultNamespaceURI]['pos'].apply(this,
[node, coordinates]);
envelope.push(coordinates);
},
'upperCorner': function(node, envelope) {
var coordinates = [];
this.readers[this.defaultNamespaceURI]['pos'].apply(this,
[node, coordinates]);
envelope.push(coordinates);
}
});
goog.object.extend(this.writers['http://www.opengis.net/gml'], {
'featureMembers': function(features) {
var node = this.createElementNS('gml:featureMembers');
for (var i = 0, ii = features.length; i < ii; ++i) {
this.writeNode('_typeName', features[i], this.featureNS, node);
}
return node;
},
'Point': function(geometry) {
var node = this.createElementNS('gml:Point');
this.writeNode('pos', geometry.getCoordinates(), null, node);
return node;
},
'pos': function(point) {
// only 2d for simple features profile
var pos;
if (this.xy) {
pos = (point[0] + ' ' + point[1]);
} else {
pos = (point[1] + ' ' + point[0]);
}
var node = this.createElementNS('gml:pos');
node.appendChild(this.createTextNode(pos));
return node;
},
'LineString': function(geometry) {
var node = this.createElementNS('gml:LineString');
this.writeNode('posList', geometry.getCoordinates(), null, node);
return node;
},
'Curve': function(geometry) {
var node = this.createElementNS('gml:Curve');
this.writeNode('segments', geometry, null, node);
return node;
},
'segments': function(geometry) {
var node = this.createElementNS('gml:segments');
this.writeNode('LineStringSegment', geometry, null, node);
return node;
},
'LineStringSegment': function(geometry) {
var node = this.createElementNS('gml:LineStringSegment');
this.writeNode('posList', geometry.getCoordinates(), null, 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[0] + ' ' + point[1];
} else {
parts[i] = point[1] + ' ' + point[0];
}
}
var node = this.createElementNS('gml:posList');
node.appendChild(this.createTextNode(parts.join(' ')));
return node;
},
'Surface': function(geometry) {
var node = this.createElementNS('gml:Surface');
this.writeNode('patches', geometry, null, node);
return node;
},
'patches': function(geometry) {
var node = this.createElementNS('gml:patches');
this.writeNode('PolygonPatch', geometry, null, node);
return node;
},
'PolygonPatch': function(geometry) {
var node = this.createElementNS('gml:PolygonPatch');
node.setAttribute('interpolation', 'planar');
var coordinates = geometry.getCoordinates();
this.writeNode('exterior', coordinates[0], null, node);
for (var i = 1, len = coordinates.length; i < len; ++i) {
this.writeNode('interior', coordinates[i], null, node);
}
return node;
},
'Polygon': function(geometry) {
var node = this.createElementNS('gml:Polygon');
var coordinates = geometry.getCoordinates();
this.writeNode('exterior', coordinates[0], null, node);
for (var i = 1, len = coordinates.length; i < len; ++i) {
this.writeNode('interior', coordinates[i], null, node);
}
return node;
},
'exterior': function(ring) {
var node = this.createElementNS('gml:exterior');
this.writeNode('LinearRing', ring, null, node);
return node;
},
'interior': function(ring) {
var node = this.createElementNS('gml:interior');
this.writeNode('LinearRing', ring, null, node);
return node;
},
'LinearRing': function(ring) {
var node = this.createElementNS('gml:LinearRing');
this.writeNode('posList', ring, null, node);
return node;
},
'MultiCurve': function(geometry) {
var node = this.createElementNS('gml:MultiCurve');
for (var i = 0, len = geometry.components.length; i < len; ++i) {
this.writeNode('curveMember', geometry.components[i], null, node);
}
return node;
},
'curveMember': function(geometry) {
var node = this.createElementNS('gml:curveMember');
if (this.curve) {
this.writeNode('Curve', geometry, null, node);
} else {
this.writeNode('LineString', geometry, null, node);
}
return node;
},
'MultiSurface': function(geometry) {
var node = this.createElementNS('gml:MultiSurface');
for (var i = 0, len = geometry.components.length; i < len; ++i) {
this.writeNode('surfaceMember', geometry.components[i], null, node);
}
return node;
},
'surfaceMember': function(polygon) {
var node = this.createElementNS('gml:surfaceMember');
if (this.surface) {
this.writeNode('Surface', polygon, null, node);
} else {
this.writeNode('Polygon', polygon, null, node);
}
return node;
},
'Envelope': function(bounds) {
var node = this.createElementNS('gml:Envelope');
this.writeNode('lowerCorner', bounds, null, node);
this.writeNode('upperCorner', bounds, null, 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;
if (this.xy) {
pos = (bounds.left + ' ' + bounds.bottom);
} else {
pos = (bounds.bottom + ' ' + bounds.left);
}
var node = this.createElementNS('gml:lowerCorner');
node.appendChild(this.createTextNode(pos));
return node;
},
'upperCorner': function(bounds) {
// only 2d for simple features profile
var pos;
if (this.xy) {
pos = (bounds.right + ' ' + bounds.top);
} else {
pos = (bounds.top + ' ' + bounds.right);
}
var node = this.createElementNS('gml:upperCorner');
node.appendChild(this.createTextNode(pos));
return node;
}
});
};
goog.inherits(ol.parser.ogc.GML_v3, ol.parser.ogc.GML);
/**
* @param {Object} obj Object structure to write out as XML.
* @return {string} An string representing the XML document.
*/
ol.parser.ogc.GML_v3.prototype.write = function(obj) {
var root = this.writeNode('featureMembers', obj.features);
this.setAttributeNS(
root, 'http://www.w3.org/2001/XMLSchema-instance',
'xsi:schemaLocation', this.schemaLocation);
return this.serialize(root);
};