Merge pull request #8519 from NielsCharlier/complex

GML Format Improvements #8516 #8517 #8518
This commit is contained in:
Frédéric Junod
2018-10-16 09:10:09 +02:00
committed by GitHub
6 changed files with 1740 additions and 39 deletions

View File

@@ -828,7 +828,7 @@ class GML3 extends GMLBase {
*/
MULTIGEOMETRY_MEMBER_NODE_FACTORY_(value, objectStack, opt_nodeName) {
const parentNode = objectStack[objectStack.length - 1].node;
return createElementNS('http://www.opengis.net/gml',
return createElementNS(this.namespace,
MULTIGEOMETRY_TO_MEMBER_NODENAME[parentNode.nodeName]);
}
@@ -861,7 +861,7 @@ class GML3 extends GMLBase {
} else {
nodeName = 'Envelope';
}
return createElementNS('http://www.opengis.net/gml',
return createElementNS(this.namespace,
nodeName);
}
@@ -876,7 +876,7 @@ class GML3 extends GMLBase {
*/
writeGeometryNode(geometry, opt_options) {
opt_options = this.adaptOptions(opt_options);
const geom = createElementNS('http://www.opengis.net/gml', 'geom');
const geom = createElementNS(this.namespace, 'geom');
const context = {node: geom, hasZ: this.hasZ, srsName: this.srsName,
curve: this.curve_, surface: this.surface_,
multiSurface: this.multiSurface_, multiCurve: this.multiCurve_};
@@ -898,7 +898,7 @@ class GML3 extends GMLBase {
*/
writeFeaturesNode(features, opt_options) {
opt_options = this.adaptOptions(opt_options);
const node = createElementNS('http://www.opengis.net/gml', 'featureMembers');
const node = createElementNS(this.namespace, 'featureMembers');
node.setAttributeNS(XML_SCHEMA_INSTANCE_URI, 'xsi:schemaLocation', this.schemaLocation);
const context = {
srsName: this.srsName,

386
src/ol/format/GML32.js Normal file
View File

@@ -0,0 +1,386 @@
/**
* @module ol/format/GML32
*/
import GML3 from './GML3.js';
import GMLBase from './GMLBase.js';
import {makeArrayPusher, makeReplacer, makeChildAppender} from '../xml.js';
import {writeStringTextNode} from '../format/xsd.js';
/**
* @classdesc Feature format for reading and writing data in the GML format
* version 3.2.1.
* @api
*/
class GML32 extends GML3 {
/**
* @param {import("./GMLBase.js").Options=} opt_options Optional configuration object.
*/
constructor(opt_options) {
const options = /** @type {import("./GMLBase.js").Options} */ (opt_options ? opt_options : {});
super(options);
/**
* @inheritDoc
*/
this.schemaLocation = options.schemaLocation ?
options.schemaLocation : this.namespace + ' http://schemas.opengis.net/gml/3.2.1/gml.xsd';
}
}
GML32.prototype.namespace = 'http://www.opengis.net/gml/3.2';
/**
* @const
* @type {Object.<string, Object.<string, XmlParser>>}
* @protected
*/
GML32.prototype.GEOMETRY_FLAT_COORDINATES_PARSERS = {
'http://www.opengis.net/gml/3.2': {
'pos': makeReplacer(GML3.prototype.readFlatPos_),
'posList': makeReplacer(GML3.prototype.readFlatPosList_)
}
};
/**
* @const
* @type {Object.<string, Object.<string, XmlParser>>}
* @protected
*/
GML32.prototype.FLAT_LINEAR_RINGS_PARSERS = {
'http://www.opengis.net/gml/3.2': {
'interior': GML3.prototype.interiorParser_,
'exterior': GML3.prototype.exteriorParser_
}
};
/**
* @const
* @type {Object.<string, Object.<string, XmlParser>>}
* @protected
*/
GML32.prototype.GEOMETRY_PARSERS = {
'http://www.opengis.net/gml/3.2': {
'Point': makeReplacer(GMLBase.prototype.readPoint),
'MultiPoint': makeReplacer(
GMLBase.prototype.readMultiPoint),
'LineString': makeReplacer(
GMLBase.prototype.readLineString),
'MultiLineString': makeReplacer(
GMLBase.prototype.readMultiLineString),
'LinearRing': makeReplacer(
GMLBase.prototype.readLinearRing),
'Polygon': makeReplacer(GMLBase.prototype.readPolygon),
'MultiPolygon': makeReplacer(
GMLBase.prototype.readMultiPolygon),
'Surface': makeReplacer(GML32.prototype.readSurface_),
'MultiSurface': makeReplacer(
GML3.prototype.readMultiSurface_),
'Curve': makeReplacer(GML32.prototype.readCurve_),
'MultiCurve': makeReplacer(
GML3.prototype.readMultiCurve_),
'Envelope': makeReplacer(GML32.prototype.readEnvelope_)
}
};
/**
* @const
* @type {Object.<string, Object.<string, XmlParser>>}
* @private
*/
GML32.prototype.MULTICURVE_PARSERS_ = {
'http://www.opengis.net/gml/3.2': {
'curveMember': makeArrayPusher(
GML3.prototype.curveMemberParser_),
'curveMembers': makeArrayPusher(
GML3.prototype.curveMemberParser_)
}
};
/**
* @const
* @type {Object.<string, Object.<string, XmlParser>>}
* @private
*/
GML32.prototype.MULTISURFACE_PARSERS_ = {
'http://www.opengis.net/gml/3.2': {
'surfaceMember': makeArrayPusher(
GML3.prototype.surfaceMemberParser_),
'surfaceMembers': makeArrayPusher(
GML3.prototype.surfaceMemberParser_)
}
};
/**
* @const
* @type {Object.<string, Object.<string, XmlParser>>}
* @private
*/
GML32.prototype.CURVEMEMBER_PARSERS_ = {
'http://www.opengis.net/gml/3.2': {
'LineString': makeArrayPusher(
GMLBase.prototype.readLineString),
'Curve': makeArrayPusher(GML3.prototype.readCurve_)
}
};
/**
* @const
* @type {Object.<string, Object.<string, XmlParser>>}
* @private
*/
GML32.prototype.SURFACEMEMBER_PARSERS_ = {
'http://www.opengis.net/gml/3.2': {
'Polygon': makeArrayPusher(GMLBase.prototype.readPolygon),
'Surface': makeArrayPusher(GML3.prototype.readSurface_)
}
};
/**
* @const
* @type {Object.<string, Object.<string, XmlParser>>}
* @private
*/
GML32.prototype.SURFACE_PARSERS_ = {
'http://www.opengis.net/gml/3.2': {
'patches': makeReplacer(GML3.prototype.readPatch_)
}
};
/**
* @const
* @type {Object.<string, Object.<string, XmlParser>>}
* @private
*/
GML32.prototype.CURVE_PARSERS_ = {
'http://www.opengis.net/gml/3.2': {
'segments': makeReplacer(GML3.prototype.readSegment_)
}
};
/**
* @const
* @type {Object.<string, Object.<string, XmlParser>>}
* @private
*/
GML32.prototype.ENVELOPE_PARSERS_ = {
'http://www.opengis.net/gml/3.2': {
'lowerCorner': makeArrayPusher(
GML3.prototype.readFlatPosList_),
'upperCorner': makeArrayPusher(
GML3.prototype.readFlatPosList_)
}
};
/**
* @const
* @type {Object.<string, Object.<string, XmlParser>>}
* @private
*/
GML32.prototype.PATCHES_PARSERS_ = {
'http://www.opengis.net/gml/3.2': {
'PolygonPatch': makeReplacer(
GML3.prototype.readPolygonPatch_)
}
};
/**
* @const
* @type {Object.<string, Object.<string, XmlParser>>}
* @private
*/
GML32.prototype.SEGMENTS_PARSERS_ = {
'http://www.opengis.net/gml/3.2': {
'LineStringSegment': makeReplacer(
GML3.prototype.readLineStringSegment_)
}
};
/**
* @const
* @type {Object.<string, Object.<string, XmlParser>>}
* @private
*/
GML32.prototype.MULTIPOINT_PARSERS_ = {
'http://www.opengis.net/gml/3.2': {
'pointMember': makeArrayPusher(
GMLBase.prototype.pointMemberParser_),
'pointMembers': makeArrayPusher(
GMLBase.prototype.pointMemberParser_)
}
};
/**
* @const
* @type {Object.<string, Object.<string, XmlParser>>}
* @private
*/
GML32.prototype.MULTILINESTRING_PARSERS_ = {
'http://www.opengis.net/gml/3.2': {
'lineStringMember': makeArrayPusher(
GMLBase.prototype.lineStringMemberParser_),
'lineStringMembers': makeArrayPusher(
GMLBase.prototype.lineStringMemberParser_)
}
};
/**
* @const
* @type {Object.<string, Object.<string, XmlParser>>}
* @private
*/
GML32.prototype.MULTIPOLYGON_PARSERS_ = {
'http://www.opengis.net/gml/3.2': {
'polygonMember': makeArrayPusher(
GMLBase.prototype.polygonMemberParser_),
'polygonMembers': makeArrayPusher(
GMLBase.prototype.polygonMemberParser_)
}
};
/**
* @const
* @type {Object.<string, Object.<string, XmlParser>>}
* @private
*/
GML32.prototype.POINTMEMBER_PARSERS_ = {
'http://www.opengis.net/gml/3.2': {
'Point': makeArrayPusher(
GMLBase.prototype.readFlatCoordinatesFromNode_)
}
};
/**
* @const
* @type {Object.<string, Object.<string, XmlParser>>}
* @private
*/
GML32.prototype.LINESTRINGMEMBER_PARSERS_ = {
'http://www.opengis.net/gml/3.2': {
'LineString': makeArrayPusher(
GMLBase.prototype.readLineString)
}
};
/**
* @const
* @type {Object.<string, Object.<string, XmlParser>>}
* @private
*/
GML32.prototype.POLYGONMEMBER_PARSERS_ = {
'http://www.opengis.net/gml/3.2': {
'Polygon': makeArrayPusher(
GMLBase.prototype.readPolygon)
}
};
/**
* @const
* @type {Object.<string, Object.<string, XmlParser>>}
* @protected
*/
GML32.prototype.RING_PARSERS = {
'http://www.opengis.net/gml/3.2': {
'LinearRing': makeReplacer(
GMLBase.prototype.readFlatLinearRing_)
}
};
/**
* @type {Object.<string, Object.<string, import("../xml.js").Serializer>>}
* @private
*/
GML32.prototype.RING_SERIALIZERS_ = {
'http://www.opengis.net/gml/3.2': {
'exterior': makeChildAppender(GML3.prototype.writeRing_),
'interior': makeChildAppender(GML3.prototype.writeRing_)
}
};
/**
* @type {Object.<string, Object.<string, import("../xml.js").Serializer>>}
* @private
*/
GML32.prototype.ENVELOPE_SERIALIZERS_ = {
'http://www.opengis.net/gml/3.2': {
'lowerCorner': makeChildAppender(writeStringTextNode),
'upperCorner': makeChildAppender(writeStringTextNode)
}
};
/**
* @type {Object.<string, Object.<string, import("../xml.js").Serializer>>}
* @private
*/
GML32.prototype.SURFACEORPOLYGONMEMBER_SERIALIZERS_ = {
'http://www.opengis.net/gml/3.2': {
'surfaceMember': makeChildAppender(
GML3.prototype.writeSurfaceOrPolygonMember_),
'polygonMember': makeChildAppender(
GML3.prototype.writeSurfaceOrPolygonMember_)
}
};
/**
* @type {Object.<string, Object.<string, import("../xml.js").Serializer>>}
* @private
*/
GML32.prototype.POINTMEMBER_SERIALIZERS_ = {
'http://www.opengis.net/gml/3.2': {
'pointMember': makeChildAppender(
GML3.prototype.writePointMember_)
}
};
/**
* @type {Object.<string, Object.<string, import("../xml.js").Serializer>>}
* @private
*/
GML32.prototype.LINESTRINGORCURVEMEMBER_SERIALIZERS_ = {
'http://www.opengis.net/gml/3.2': {
'lineStringMember': makeChildAppender(
GML3.prototype.writeLineStringOrCurveMember_),
'curveMember': makeChildAppender(
GML3.prototype.writeLineStringOrCurveMember_)
}
};
/**
* @type {Object.<string, Object.<string, import("../xml.js").Serializer>>}
* @private
*/
GML32.prototype.GEOMETRY_SERIALIZERS_ = {
'http://www.opengis.net/gml/3.2': {
'Curve': makeChildAppender(
GML3.prototype.writeCurveOrLineString_),
'MultiCurve': makeChildAppender(
GML3.prototype.writeMultiCurveOrLineString_),
'Point': makeChildAppender(GML32.prototype.writePoint_),
'MultiPoint': makeChildAppender(
GML3.prototype.writeMultiPoint_),
'LineString': makeChildAppender(
GML3.prototype.writeCurveOrLineString_),
'MultiLineString': makeChildAppender(
GML3.prototype.writeMultiCurveOrLineString_),
'LinearRing': makeChildAppender(
GML3.prototype.writeLinearRing_),
'Polygon': makeChildAppender(
GML3.prototype.writeSurfaceOrPolygon_),
'MultiPolygon': makeChildAppender(
GML3.prototype.writeMultiSurfaceOrPolygon_),
'Surface': makeChildAppender(
GML3.prototype.writeSurfaceOrPolygon_),
'MultiSurface': makeChildAppender(
GML3.prototype.writeMultiSurfaceOrPolygon_),
'Envelope': makeChildAppender(
GML3.prototype.writeEnvelope)
}
};
export default GML32;

View File

@@ -123,8 +123,8 @@ class GMLBase extends XMLFeature {
* @type {Object<string, Object<string, Object>>}
*/
this.FEATURE_COLLECTION_PARSERS = {};
this.FEATURE_COLLECTION_PARSERS[GMLNS] = {
'featureMember': makeReplacer(this.readFeaturesInternal),
this.FEATURE_COLLECTION_PARSERS[this.namespace] = {
'featureMember': makeArrayPusher(this.readFeaturesInternal),
'featureMembers': makeReplacer(this.readFeaturesInternal)
};
}
@@ -138,15 +138,9 @@ class GMLBase extends XMLFeature {
const localName = node.localName;
let features = null;
if (localName == 'FeatureCollection') {
if (node.namespaceURI === 'http://www.opengis.net/wfs') {
features = pushParseAndPop([],
this.FEATURE_COLLECTION_PARSERS, node,
objectStack, this);
} else {
features = pushParseAndPop(null,
this.FEATURE_COLLECTION_PARSERS, node,
objectStack, this);
}
features = pushParseAndPop([],
this.FEATURE_COLLECTION_PARSERS, node,
objectStack, this);
} else if (localName == 'featureMembers' || localName == 'featureMember') {
const context = objectStack[0];
let featureType = context['featureType'];
@@ -242,42 +236,77 @@ class GMLBase extends XMLFeature {
/**
* @param {Element} node Node.
* @param {Array<*>} objectStack Object stack.
* @return {Feature} Feature.
* @param {boolean} asFeature whether result should be wrapped as a feature.
* @return {Feature} Feature
*/
readFeatureElement(node, objectStack) {
let n;
const fid = node.getAttribute('fid') || getAttributeNS(node, GMLNS, 'id');
const values = {};
readFeatureElementInternal(node, objectStack, asFeature) {
let geometryName;
for (n = node.firstElementChild; n; n = n.nextElementSibling) {
const values = {};
for (let n = node.firstElementChild; n; n = n.nextElementSibling) {
let value;
const localName = n.localName;
// Assume attribute elements have one child node and that the child
// is a text or CDATA node (to be treated as text).
// Otherwise assume it is a geometry node.
if (n.childNodes.length === 0 ||
(n.childNodes.length === 1 &&
(n.firstChild.nodeType === 3 || n.firstChild.nodeType === 4))) {
let value = getAllTextContent(n, false);
// first, check if it is simple attribute
if (n.childNodes.length === 0
|| (n.childNodes.length === 1 && (n.firstChild.nodeType === 3 || n.firstChild.nodeType === 4))) {
value = getAllTextContent(n, false);
if (ONLY_WHITESPACE_RE.test(value)) {
value = undefined;
}
values[localName] = value;
} else {
// boundedBy is an extent and must not be considered as a geometry
if (localName !== 'boundedBy') {
if (asFeature) {
//if feature, try it as a geometry
value = this.readGeometryElement(n, objectStack);
}
if (!value) { //if not a geometry or not a feature, treat it as a complex attribute
value = this.readFeatureElementInternal(n, objectStack, false);
} else if (localName !== 'boundedBy') {
// boundedBy is an extent and must not be considered as a geometry
geometryName = localName;
}
values[localName] = this.readGeometryElement(n, objectStack);
}
if (values[localName]) {
if (!(values[localName] instanceof Array)) {
values[localName] = [values[localName]];
}
values[localName].push(value);
} else {
values[localName] = value;
}
const len = n.attributes.length;
if (len > 0) {
values[localName] = {_content_: values[localName]};
for (let i = 0; i < len; i++) {
const attName = n.attributes[i].name;
values[localName][attName] = n.attributes[i].value;
}
}
}
const feature = new Feature(values);
if (geometryName) {
feature.setGeometryName(geometryName);
if (!asFeature) {
return values;
} else {
const feature = new Feature(values);
if (geometryName) {
feature.setGeometryName(geometryName);
}
const fid = node.getAttribute('fid') ||
getAttributeNS(node, this.namespace, 'id');
if (fid) {
feature.setId(fid);
}
return feature;
}
if (fid) {
feature.setId(fid);
}
return feature;
}
/**
* @param {Node} node Node.
* @param {Array<*>} objectStack Object stack.
* @return {Feature} Feature.
*/
readFeatureElement(node, objectStack) {
return this.readFeatureElementInternal(node, objectStack, true);
}
/**
@@ -472,6 +501,9 @@ class GMLBase extends XMLFeature {
}
GMLBase.prototype.namespace = GMLNS;
/**
* @const
* @type {Object<string, Object<string, import("../xml.js").Parser>>}

View File

@@ -1,6 +1,7 @@
import Feature from '../../../../src/ol/Feature.js';
import GML from '../../../../src/ol/format/GML.js';
import GML2 from '../../../../src/ol/format/GML2.js';
import GML32 from '../../../../src/ol/format/GML32.js';
import LineString from '../../../../src/ol/geom/LineString.js';
import LinearRing from '../../../../src/ol/geom/LinearRing.js';
import MultiLineString from '../../../../src/ol/geom/MultiLineString.js';
@@ -1282,6 +1283,39 @@ describe('ol.format.GML3', function() {
});
describe('when parsing TOPP states GML with multiple featureMember tags', function() {
let features, gmlFormat;
before(function(done) {
afterLoadText('spec/ol/format/gml/topp-states-gml-featureMember.xml', function(xml) {
try {
const schemaLoc = 'http://www.openplans.org/topp ' +
'http://demo.opengeo.org/geoserver/wfs?service=WFS&version=' +
'1.1.0&request=DescribeFeatureType&typeName=topp:states ' +
'http://www.opengis.net/gml ' +
'http://schemas.opengis.net/gml/3.2.1/gml.xsd';
const config = {
'featureNS': 'http://www.openplans.org/topp',
'featureType': 'states',
'multiSurface': true,
'srsName': 'urn:x-ogc:def:crs:EPSG:4326',
'schemaLocation': schemaLoc
};
gmlFormat = new GML(config);
features = gmlFormat.readFeatures(xml);
} catch (e) {
done(e);
}
done();
});
});
it('creates 3 features', function() {
expect(features).to.have.length(3);
});
});
describe('when parsing TOPP states GML from WFS', function() {
let features, feature;
@@ -1567,4 +1601,897 @@ describe('ol.format.GML3', function() {
});
describe('when parsing complex', function() {
let features, gmlFormat;
before(function(done) {
afterLoadText('spec/ol/format/gml/gml-complex.xml', function(xml) {
try {
gmlFormat = new GML();
features = gmlFormat.readFeatures(xml);
} catch (e) {
done(e);
}
done();
});
});
it('creates 3 features', function() {
expect(features).to.have.length(3);
});
it('creates feature with two names', function() {
expect(features[0].values_['name']).to.have.length(2);
});
it('creates nested property', function() {
expect(features[0].values_['observationMethod']['CGI_TermValue']['value']['_content_'])
.to.eql('urn:ogc:def:nil:OGC:missing');
});
it('creates nested attribute', function() {
expect(features[0].values_['observationMethod']['CGI_TermValue']['value']['codeSpace'])
.to.eql('urn:ietf:rfc:2141');
});
});
});
describe('ol.format.GML32', function() {
let format, formatWGS84, formatNoSrs;
beforeEach(function() {
format = new GML32({srsName: 'CRS:84'});
formatWGS84 = new GML32({
srsName: 'urn:x-ogc:def:crs:EPSG:4326'
});
formatNoSrs = new GML32();
});
describe('#readGeometry', function() {
describe('point', function() {
it('can read and write a point geometry', function() {
const text =
'<gml:Point xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:pos srsDimension="2">1 2</gml:pos>' +
'</gml:Point>';
const g = readGeometry(format, text);
expect(g).to.be.an(Point);
expect(g.getCoordinates()).to.eql([1, 2, 0]);
const serialized = format.writeGeometryNode(g);
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
it('can read a point geometry with scientific notation', function() {
let text =
'<gml:Point xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:pos>1E7 2</gml:pos>' +
'</gml:Point>';
let g = readGeometry(format, text);
expect(g).to.be.an(Point);
expect(g.getCoordinates()).to.eql([10000000, 2, 0]);
text =
'<gml:Point xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:pos>1e7 2</gml:pos>' +
'</gml:Point>';
g = readGeometry(format, text);
expect(g).to.be.an(Point);
expect(g.getCoordinates()).to.eql([10000000, 2, 0]);
});
it('can read, transform and write a point geometry', function() {
const config = {
featureProjection: 'EPSG:3857'
};
const text =
'<gml:Point xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:pos>1 2</gml:pos>' +
'</gml:Point>';
const g = readGeometry(format, text, config);
expect(g).to.be.an(Point);
const coordinates = g.getCoordinates();
expect(coordinates.splice(0, 2)).to.eql(
transform([1, 2], 'CRS:84', 'EPSG:3857'));
config.dataProjection = 'CRS:84';
const serialized = format.writeGeometryNode(g, config);
const pos = serialized.firstElementChild.firstElementChild.textContent;
const coordinate = pos.split(' ');
expect(coordinate[0]).to.roughlyEqual(1, 1e-9);
expect(coordinate[1]).to.roughlyEqual(2, 1e-9);
});
it('can detect SRS, read and transform a point geometry', function() {
const config = {
featureProjection: 'EPSG:3857'
};
const text =
'<gml:Point xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:pos>1 2</gml:pos>' +
'</gml:Point>';
const g = readGeometry(formatNoSrs, text, config);
expect(g).to.be.an(Point);
const coordinates = g.getCoordinates();
expect(coordinates.splice(0, 2)).to.eql(
transform([1, 2], 'CRS:84', 'EPSG:3857'));
});
it('can read and write a point geometry in EPSG:4326', function() {
const text =
'<gml:Point xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="urn:x-ogc:def:crs:EPSG:4326">' +
' <gml:pos srsDimension="2">2 1</gml:pos>' +
'</gml:Point>';
const g = readGeometry(formatWGS84, text);
expect(g).to.be.an(Point);
expect(g.getCoordinates()).to.eql([1, 2, 0]);
const serialized = formatWGS84.writeGeometryNode(g);
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
});
describe('linestring', function() {
it('can read and write a linestring geometry', function() {
const text =
'<gml:LineString xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:posList srsDimension="2">1 2 3 4</gml:posList>' +
'</gml:LineString>';
const g = readGeometry(format, text);
expect(g).to.be.an(LineString);
expect(g.getCoordinates()).to.eql([[1, 2, 0], [3, 4, 0]]);
const serialized = format.writeGeometryNode(g);
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
it('can read, transform and write a linestring geometry', function() {
const config = {
dataProjection: 'CRS:84',
featureProjection: 'EPSG:3857'
};
const text =
'<gml:LineString xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:posList>1 2 3 4</gml:posList>' +
'</gml:LineString>';
const g = readGeometry(format, text, config);
expect(g).to.be.an(LineString);
const coordinates = g.getCoordinates();
expect(coordinates[0].slice(0, 2)).to.eql(
transform([1, 2], 'CRS:84', 'EPSG:3857'));
expect(coordinates[1].slice(0, 2)).to.eql(
transform([3, 4], 'CRS:84', 'EPSG:3857'));
const serialized = format.writeGeometryNode(g, config);
const poss = serialized.firstElementChild.firstElementChild.textContent;
const coordinate = poss.split(' ');
expect(coordinate[0]).to.roughlyEqual(1, 1e-9);
expect(coordinate[1]).to.roughlyEqual(2, 1e-9);
expect(coordinate[2]).to.roughlyEqual(3, 1e-9);
expect(coordinate[3]).to.roughlyEqual(4, 1e-9);
});
it('can read and write a linestring geometry in EPSG:4326', function() {
const text =
'<gml:LineString xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="urn:x-ogc:def:crs:EPSG:4326">' +
' <gml:posList srsDimension="2">2 1 4 3</gml:posList>' +
'</gml:LineString>';
const g = readGeometry(formatWGS84, text);
expect(g).to.be.an(LineString);
expect(g.getCoordinates()).to.eql([[1, 2, 0], [3, 4, 0]]);
const serialized = formatWGS84.writeGeometryNode(g);
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
});
describe('axis order', function() {
it('can read and write a linestring geometry with ' +
'correct axis order',
function() {
const text =
'<gml:LineString xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="urn:x-ogc:def:crs:EPSG:4326">' +
' <gml:posList srsDimension="2">-90 -180 90 180</gml:posList>' +
'</gml:LineString>';
const g = readGeometry(format, text);
expect(g).to.be.an(LineString);
expect(g.getCoordinates()).to.eql([[-180, -90, 0], [180, 90, 0]]);
const serialized = formatWGS84.writeGeometryNode(g);
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
it('can read and write a point geometry with correct axis order',
function() {
const text =
'<gml:Point xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="urn:x-ogc:def:crs:EPSG:4326">' +
' <gml:pos srsDimension="2">-90 -180</gml:pos>' +
'</gml:Point>';
const g = readGeometry(format, text);
expect(g).to.be.an(Point);
expect(g.getCoordinates()).to.eql([-180, -90, 0]);
const serialized = formatWGS84.writeGeometryNode(g);
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
it('can read and write a surface geometry with right axis order',
function() {
const text =
'<gml:MultiSurface xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="urn:x-ogc:def:crs:EPSG:4326">' +
' <gml:surfaceMember>' +
' <gml:Polygon srsName="urn:x-ogc:def:crs:EPSG:4326">' +
' <gml:exterior>' +
' <gml:LinearRing srsName=' +
' "urn:x-ogc:def:crs:EPSG:4326">' +
' <gml:posList srsDimension="2">' +
' 38.9661 -77.0081 38.9931 -77.0421 ' +
' 38.9321 -77.1221 38.9151 -77.0781 38.8861 ' +
' -77.0671 38.8621 -77.0391 38.8381 -77.0401 ' +
' 38.8291 -77.0451 38.8131 -77.0351 38.7881 ' +
' -77.0451 38.8891 -76.9111 38.9661 -77.0081' +
' </gml:posList>' +
' </gml:LinearRing>' +
' </gml:exterior>' +
' </gml:Polygon>' +
' </gml:surfaceMember>' +
'</gml:MultiSurface>';
const g = readGeometry(format, text);
expect(g.getCoordinates()[0][0][0][0]).to.equal(-77.0081);
expect(g.getCoordinates()[0][0][0][1]).to.equal(38.9661);
format = new GML32({
srsName: 'urn:x-ogc:def:crs:EPSG:4326',
surface: false});
const serialized = format.writeGeometryNode(g);
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
});
describe('linestring 3D', function() {
it('can read a linestring 3D geometry', function() {
const text =
'<gml:LineString xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84" srsDimension="3">' +
' <gml:posList>1 2 3 4 5 6</gml:posList>' +
'</gml:LineString>';
const g = readGeometry(format, text);
expect(g).to.be.an(LineString);
expect(g.getCoordinates()).to.eql([[1, 2, 3], [4, 5, 6]]);
});
});
describe('linearring', function() {
it('can read and write a linearring geometry', function() {
const text =
'<gml:LinearRing xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:posList srsDimension="2">1 2 3 4 5 6 1 2</gml:posList>' +
'</gml:LinearRing>';
const g = readGeometry(format, text);
expect(g).to.be.an(LinearRing);
expect(g.getCoordinates()).to.eql(
[[1, 2, 0], [3, 4, 0], [5, 6, 0], [1, 2, 0]]);
const serialized = format.writeGeometryNode(g);
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
});
describe('polygon', function() {
it('can read and write a polygon geometry', function() {
const text =
'<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:exterior>' +
' <gml:LinearRing srsName="CRS:84">' +
' <gml:posList srsDimension="2">1 2 3 2 3 4 1 2</gml:posList>' +
' </gml:LinearRing>' +
' </gml:exterior>' +
' <gml:interior>' +
' <gml:LinearRing srsName="CRS:84">' +
' <gml:posList srsDimension="2">2 3 2 5 4 5 2 3</gml:posList>' +
' </gml:LinearRing>' +
' </gml:interior>' +
' <gml:interior>' +
' <gml:LinearRing srsName="CRS:84">' +
' <gml:posList srsDimension="2">3 4 3 6 5 6 3 4</gml:posList>' +
' </gml:LinearRing>' +
' </gml:interior>' +
'</gml:Polygon>';
const g = readGeometry(format, text);
expect(g).to.be.an(Polygon);
expect(g.getCoordinates()).to.eql([[[1, 2, 0], [3, 2, 0], [3, 4, 0],
[1, 2, 0]], [[2, 3, 0], [2, 5, 0], [4, 5, 0], [2, 3, 0]],
[[3, 4, 0], [3, 6, 0], [5, 6, 0], [3, 4, 0]]]);
const serialized = format.writeGeometryNode(g);
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
});
describe('surface', function() {
it('can read and write a surface geometry', function() {
const text =
'<gml:Surface xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:patches>' +
' <gml:PolygonPatch>' +
' <gml:exterior>' +
' <gml:LinearRing srsName="CRS:84">' +
' <gml:posList srsDimension="2">' +
' 1 2 3 2 3 4 1 2' +
' </gml:posList>' +
' </gml:LinearRing>' +
' </gml:exterior>' +
' <gml:interior>' +
' <gml:LinearRing srsName="CRS:84">' +
' <gml:posList srsDimension="2">' +
' 2 3 2 5 4 5 2 3' +
' </gml:posList>' +
' </gml:LinearRing>' +
' </gml:interior>' +
' <gml:interior>' +
' <gml:LinearRing srsName="CRS:84">' +
' <gml:posList srsDimension="2">' +
' 3 4 3 6 5 6 3 4' +
' </gml:posList>' +
' </gml:LinearRing>' +
' </gml:interior>' +
' </gml:PolygonPatch>' +
' </gml:patches>' +
'</gml:Surface>';
const g = readGeometry(format, text);
expect(g).to.be.an(Polygon);
expect(g.getCoordinates()).to.eql([[[1, 2, 0], [3, 2, 0], [3, 4, 0],
[1, 2, 0]], [[2, 3, 0], [2, 5, 0], [4, 5, 0], [2, 3, 0]],
[[3, 4, 0], [3, 6, 0], [5, 6, 0], [3, 4, 0]]]);
format = new GML32({srsName: 'CRS:84', surface: true});
const serialized = format.writeGeometryNode(g);
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
});
describe('curve', function() {
it('can read and write a curve geometry', function() {
const text =
'<gml:Curve xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:segments>' +
' <gml:LineStringSegment>' +
' <gml:posList srsDimension="2">1 2 3 4</gml:posList>' +
' </gml:LineStringSegment>' +
' </gml:segments>' +
'</gml:Curve>';
const g = readGeometry(format, text);
expect(g).to.be.an(LineString);
expect(g.getCoordinates()).to.eql([[1, 2, 0], [3, 4, 0]]);
format = new GML32({srsName: 'CRS:84', curve: true});
const serialized = format.writeGeometryNode(g);
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
});
describe('envelope', function() {
it('can read an envelope geometry', function() {
const text =
'<gml:Envelope xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:lowerCorner>1 2</gml:lowerCorner>' +
' <gml:upperCorner>3 4</gml:upperCorner>' +
'</gml:Envelope>';
const g = readGeometry(format, text);
expect(g).to.eql([1, 2, 3, 4]);
});
});
describe('multipoint', function() {
it('can read and write a singular multipoint geometry', function() {
const text =
'<gml:MultiPoint xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:pointMember>' +
' <gml:Point srsName="CRS:84">' +
' <gml:pos srsDimension="2">1 2</gml:pos>' +
' </gml:Point>' +
' </gml:pointMember>' +
' <gml:pointMember>' +
' <gml:Point srsName="CRS:84">' +
' <gml:pos srsDimension="2">2 3</gml:pos>' +
' </gml:Point>' +
' </gml:pointMember>' +
' <gml:pointMember>' +
' <gml:Point srsName="CRS:84">' +
' <gml:pos srsDimension="2">3 4</gml:pos>' +
' </gml:Point>' +
' </gml:pointMember>' +
'</gml:MultiPoint>';
const g = readGeometry(format, text);
expect(g).to.be.an(MultiPoint);
expect(g.getCoordinates()).to.eql([[1, 2, 0], [2, 3, 0], [3, 4, 0]]);
const serialized = format.writeGeometryNode(g);
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
it('can read a plural multipoint geometry', function() {
const text =
'<gml:MultiPoint xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:pointMembers>' +
' <gml:Point>' +
' <gml:pos>1 2</gml:pos>' +
' </gml:Point>' +
' <gml:Point>' +
' <gml:pos>2 3</gml:pos>' +
' </gml:Point>' +
' <gml:Point>' +
' <gml:pos>3 4</gml:pos>' +
' </gml:Point>' +
' </gml:pointMembers>' +
'</gml:MultiPoint>';
const g = readGeometry(format, text);
expect(g).to.be.an(MultiPoint);
expect(g.getCoordinates()).to.eql([[1, 2, 0], [2, 3, 0], [3, 4, 0]]);
});
});
describe('multilinestring', function() {
it('can read and write a singular multilinestring geometry', function() {
const text =
'<gml:MultiLineString xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:lineStringMember>' +
' <gml:LineString srsName="CRS:84">' +
' <gml:posList srsDimension="2">1 2 2 3</gml:posList>' +
' </gml:LineString>' +
' </gml:lineStringMember>' +
' <gml:lineStringMember>' +
' <gml:LineString srsName="CRS:84">' +
' <gml:posList srsDimension="2">3 4 4 5</gml:posList>' +
' </gml:LineString>' +
' </gml:lineStringMember>' +
'</gml:MultiLineString>';
const g = readGeometry(format, text);
expect(g).to.be.an(MultiLineString);
expect(g.getCoordinates()).to.eql(
[[[1, 2, 0], [2, 3, 0]], [[3, 4, 0], [4, 5, 0]]]);
format = new GML32({srsName: 'CRS:84', multiCurve: false});
const serialized = format.writeGeometryNode(g);
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
it('can read a plural multilinestring geometry', function() {
const text =
'<gml:MultiLineString xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:lineStringMembers>' +
' <gml:LineString>' +
' <gml:posList>1 2 2 3</gml:posList>' +
' </gml:LineString>' +
' <gml:LineString>' +
' <gml:posList>3 4 4 5</gml:posList>' +
' </gml:LineString>' +
' </gml:lineStringMembers>' +
'</gml:MultiLineString>';
const g = readGeometry(format, text);
expect(g).to.be.an(MultiLineString);
expect(g.getCoordinates()).to.eql(
[[[1, 2, 0], [2, 3, 0]], [[3, 4, 0], [4, 5, 0]]]);
});
});
describe('multipolygon', function() {
it('can read and write a singular multipolygon geometry', function() {
const text =
'<gml:MultiPolygon xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:polygonMember>' +
' <gml:Polygon srsName="CRS:84">' +
' <gml:exterior>' +
' <gml:LinearRing srsName="CRS:84">' +
' <gml:posList srsDimension="2">' +
' 1 2 3 2 3 4 1 2' +
' </gml:posList>' +
' </gml:LinearRing>' +
' </gml:exterior>' +
' <gml:interior>' +
' <gml:LinearRing srsName="CRS:84">' +
' <gml:posList srsDimension="2">' +
' 2 3 2 5 4 5 2 3' +
' </gml:posList>' +
' </gml:LinearRing>' +
' </gml:interior>' +
' <gml:interior>' +
' <gml:LinearRing srsName="CRS:84">' +
' <gml:posList srsDimension="2">' +
' 3 4 3 6 5 6 3 4' +
' </gml:posList>' +
' </gml:LinearRing>' +
' </gml:interior>' +
' </gml:Polygon>' +
' </gml:polygonMember>' +
' <gml:polygonMember>' +
' <gml:Polygon srsName="CRS:84">' +
' <gml:exterior>' +
' <gml:LinearRing srsName="CRS:84">' +
' <gml:posList srsDimension="2">' +
' 1 2 3 2 3 4 1 2' +
' </gml:posList>' +
' </gml:LinearRing>' +
' </gml:exterior>' +
' </gml:Polygon>' +
' </gml:polygonMember>' +
'</gml:MultiPolygon>';
const g = readGeometry(format, text);
expect(g).to.be.an(MultiPolygon);
expect(g.getCoordinates()).to.eql([
[[[1, 2, 0], [3, 2, 0], [3, 4, 0],
[1, 2, 0]], [[2, 3, 0], [2, 5, 0], [4, 5, 0], [2, 3, 0]],
[[3, 4, 0], [3, 6, 0], [5, 6, 0], [3, 4, 0]]],
[[[1, 2, 0], [3, 2, 0], [3, 4, 0], [1, 2, 0]]]]);
format = new GML32({srsName: 'CRS:84', multiSurface: false});
const serialized = format.writeGeometryNode(g);
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
it('can read a plural multipolygon geometry', function() {
const text =
'<gml:MultiPolygon xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:polygonMembers>' +
' <gml:Polygon>' +
' <gml:exterior>' +
' <gml:LinearRing>' +
' <gml:posList>1 2 3 2 3 4 1 2</gml:posList>' +
' </gml:LinearRing>' +
' </gml:exterior>' +
' <gml:interior>' +
' <gml:LinearRing>' +
' <gml:posList>2 3 2 5 4 5 2 3</gml:posList>' +
' </gml:LinearRing>' +
' </gml:interior>' +
' <gml:interior>' +
' <gml:LinearRing>' +
' <gml:posList>3 4 3 6 5 6 3 4</gml:posList>' +
' </gml:LinearRing>' +
' </gml:interior>' +
' </gml:Polygon>' +
' <gml:Polygon>' +
' <gml:exterior>' +
' <gml:LinearRing>' +
' <gml:posList>1 2 3 2 3 4 1 2</gml:posList>' +
' </gml:LinearRing>' +
' </gml:exterior>' +
' </gml:Polygon>' +
' </gml:polygonMembers>' +
'</gml:MultiPolygon>';
const g = readGeometry(format, text);
expect(g).to.be.an(MultiPolygon);
expect(g.getCoordinates()).to.eql([
[[[1, 2, 0], [3, 2, 0], [3, 4, 0],
[1, 2, 0]], [[2, 3, 0], [2, 5, 0], [4, 5, 0], [2, 3, 0]],
[[3, 4, 0], [3, 6, 0], [5, 6, 0], [3, 4, 0]]],
[[[1, 2, 0], [3, 2, 0], [3, 4, 0], [1, 2, 0]]]]);
});
});
describe('multicurve', function() {
it('can read and write a singular multicurve-linestring geometry',
function() {
const text =
'<gml:MultiCurve xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:curveMember>' +
' <gml:LineString srsName="CRS:84">' +
' <gml:posList srsDimension="2">1 2 2 3</gml:posList>' +
' </gml:LineString>' +
' </gml:curveMember>' +
' <gml:curveMember>' +
' <gml:LineString srsName="CRS:84">' +
' <gml:posList srsDimension="2">3 4 4 5</gml:posList>' +
' </gml:LineString>' +
' </gml:curveMember>' +
'</gml:MultiCurve>';
const g = readGeometry(format, text);
expect(g).to.be.an(MultiLineString);
expect(g.getCoordinates()).to.eql(
[[[1, 2, 0], [2, 3, 0]], [[3, 4, 0], [4, 5, 0]]]);
const serialized = format.writeGeometryNode(g);
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
it('can read and write a singular multicurve-curve geometry', function() {
const text =
'<gml:MultiCurve xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:curveMember>' +
' <gml:Curve srsName="CRS:84">' +
' <gml:segments>' +
' <gml:LineStringSegment>' +
' <gml:posList srsDimension="2">1 2 2 3</gml:posList>' +
' </gml:LineStringSegment>' +
' </gml:segments>' +
' </gml:Curve>' +
' </gml:curveMember>' +
' <gml:curveMember>' +
' <gml:Curve srsName="CRS:84">' +
' <gml:segments>' +
' <gml:LineStringSegment>' +
' <gml:posList srsDimension="2">3 4 4 5</gml:posList>' +
' </gml:LineStringSegment>' +
' </gml:segments>' +
' </gml:Curve>' +
' </gml:curveMember>' +
'</gml:MultiCurve>';
const g = readGeometry(format, text);
expect(g).to.be.an(MultiLineString);
expect(g.getCoordinates()).to.eql(
[[[1, 2, 0], [2, 3, 0]], [[3, 4, 0], [4, 5, 0]]]);
format = new GML32({srsName: 'CRS:84', curve: true});
const serialized = format.writeGeometryNode(g);
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
});
describe('multisurface', function() {
it('can read and write a singular multisurface geometry', function() {
const text =
'<gml:MultiSurface xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:surfaceMember>' +
' <gml:Polygon srsName="CRS:84">' +
' <gml:exterior>' +
' <gml:LinearRing srsName="CRS:84">' +
' <gml:posList srsDimension="2">' +
' 1 2 3 2 3 4 1 2' +
' </gml:posList>' +
' </gml:LinearRing>' +
' </gml:exterior>' +
' <gml:interior>' +
' <gml:LinearRing srsName="CRS:84">' +
' <gml:posList srsDimension="2">' +
' 2 3 2 5 4 5 2 3' +
' </gml:posList>' +
' </gml:LinearRing>' +
' </gml:interior>' +
' <gml:interior>' +
' <gml:LinearRing srsName="CRS:84">' +
' <gml:posList srsDimension="2">' +
' 3 4 3 6 5 6 3 4' +
' </gml:posList>' +
' </gml:LinearRing>' +
' </gml:interior>' +
' </gml:Polygon>' +
' </gml:surfaceMember>' +
' <gml:surfaceMember>' +
' <gml:Polygon srsName="CRS:84">' +
' <gml:exterior>' +
' <gml:LinearRing srsName="CRS:84">' +
' <gml:posList srsDimension="2">' +
' 1 2 3 2 3 4 1 2' +
' </gml:posList>' +
' </gml:LinearRing>' +
' </gml:exterior>' +
' </gml:Polygon>' +
' </gml:surfaceMember>' +
'</gml:MultiSurface>';
const g = readGeometry(format, text);
expect(g).to.be.an(MultiPolygon);
expect(g.getCoordinates()).to.eql([
[[[1, 2, 0], [3, 2, 0], [3, 4, 0],
[1, 2, 0]], [[2, 3, 0], [2, 5, 0], [4, 5, 0], [2, 3, 0]],
[[3, 4, 0], [3, 6, 0], [5, 6, 0], [3, 4, 0]]],
[[[1, 2, 0], [3, 2, 0], [3, 4, 0], [1, 2, 0]]]]);
const serialized = format.writeGeometryNode(g);
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
it('can read a plural multisurface geometry', function() {
const text =
'<gml:MultiSurface xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:surfaceMembers>' +
' <gml:Polygon>' +
' <gml:exterior>' +
' <gml:LinearRing>' +
' <gml:posList>1 2 3 2 3 4 1 2</gml:posList>' +
' </gml:LinearRing>' +
' </gml:exterior>' +
' <gml:interior>' +
' <gml:LinearRing>' +
' <gml:posList>2 3 2 5 4 5 2 3</gml:posList>' +
' </gml:LinearRing>' +
' </gml:interior>' +
' <gml:interior>' +
' <gml:LinearRing>' +
' <gml:posList>3 4 3 6 5 6 3 4</gml:posList>' +
' </gml:LinearRing>' +
' </gml:interior>' +
' </gml:Polygon>' +
' </gml:surfaceMembers>' +
' <gml:surfaceMembers>' +
' <gml:Polygon>' +
' <gml:exterior>' +
' <gml:LinearRing>' +
' <gml:posList>1 2 3 2 3 4 1 2</gml:posList>' +
' </gml:LinearRing>' +
' </gml:exterior>' +
' </gml:Polygon>' +
' </gml:surfaceMembers>' +
'</gml:MultiSurface>';
const g = readGeometry(format, text);
expect(g).to.be.an(MultiPolygon);
expect(g.getCoordinates()).to.eql([
[[[1, 2, 0], [3, 2, 0], [3, 4, 0],
[1, 2, 0]], [[2, 3, 0], [2, 5, 0], [4, 5, 0], [2, 3, 0]],
[[3, 4, 0], [3, 6, 0], [5, 6, 0], [3, 4, 0]]],
[[[1, 2, 0], [3, 2, 0], [3, 4, 0], [1, 2, 0]]]]);
});
it('can read and write a multisurface-surface geometry', function() {
const text =
'<gml:MultiSurface xmlns:gml="http://www.opengis.net/gml/3.2" ' +
' srsName="CRS:84">' +
' <gml:surfaceMember>' +
' <gml:Surface srsName="CRS:84">' +
' <gml:patches>' +
' <gml:PolygonPatch>' +
' <gml:exterior>' +
' <gml:LinearRing srsName="CRS:84">' +
' <gml:posList srsDimension="2">' +
' 1 2 3 2 3 4 1 2' +
' </gml:posList>' +
' </gml:LinearRing>' +
' </gml:exterior>' +
' <gml:interior>' +
' <gml:LinearRing srsName="CRS:84">' +
' <gml:posList srsDimension="2">' +
' 2 3 2 5 4 5 2 3' +
' </gml:posList>' +
' </gml:LinearRing>' +
' </gml:interior>' +
' <gml:interior>' +
' <gml:LinearRing srsName="CRS:84">' +
' <gml:posList srsDimension="2">' +
' 3 4 3 6 5 6 3 4' +
' </gml:posList>' +
' </gml:LinearRing>' +
' </gml:interior>' +
' </gml:PolygonPatch>' +
' </gml:patches>' +
' </gml:Surface>' +
' </gml:surfaceMember>' +
' <gml:surfaceMember>' +
' <gml:Surface srsName="CRS:84">' +
' <gml:patches>' +
' <gml:PolygonPatch>' +
' <gml:exterior>' +
' <gml:LinearRing srsName="CRS:84">' +
' <gml:posList srsDimension="2">' +
' 1 2 3 2 3 4 1 2' +
' </gml:posList>' +
' </gml:LinearRing>' +
' </gml:exterior>' +
' </gml:PolygonPatch>' +
' </gml:patches>' +
' </gml:Surface>' +
' </gml:surfaceMember>' +
'</gml:MultiSurface>';
const g = readGeometry(format, text);
expect(g).to.be.an(MultiPolygon);
expect(g.getCoordinates()).to.eql([
[[[1, 2, 0], [3, 2, 0], [3, 4, 0],
[1, 2, 0]], [[2, 3, 0], [2, 5, 0], [4, 5, 0], [2, 3, 0]],
[[3, 4, 0], [3, 6, 0], [5, 6, 0], [3, 4, 0]]],
[[[1, 2, 0], [3, 2, 0], [3, 4, 0], [1, 2, 0]]]]);
format = new GML32({srsName: 'CRS:84', surface: true});
const serialized = format.writeGeometryNode(g);
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
});
});
describe('when parsing empty attribute', function() {
it('generates undefined value', function() {
const text =
'<gml:featureMembers xmlns:gml="http://www.opengis.net/gml/3.2">' +
' <topp:gnis_pop gml:id="gnis_pop.148604" xmlns:topp="' +
'http://www.openplans.org/topp">' +
' <gml:name>Aflu</gml:name>' +
' <topp:the_geom>' +
' <gml:Point srsName="urn:x-ogc:def:crs:EPSG:4326">' +
' <gml:pos>34.12 2.09</gml:pos>' +
' </gml:Point>' +
' </topp:the_geom>' +
' <topp:population>84683</topp:population>' +
' <topp:country>Algeria</topp:country>' +
' <topp:type>place</topp:type>' +
' <topp:name>Aflu</topp:name>' +
' <topp:empty></topp:empty>' +
' </topp:gnis_pop>' +
'</gml:featureMembers>';
const config = {
'featureNS': 'http://www.openplans.org/topp',
'featureType': 'gnis_pop'
};
const features = new GML32(config).readFeatures(text);
const feature = features[0];
expect(feature.get('empty')).to.be(undefined);
});
});
describe('when parsing CDATA attribute', function() {
let features;
before(function(done) {
try {
const text =
'<gml:featureMembers xmlns:gml="http://www.opengis.net/gml/3.2">' +
' <topp:gnis_pop gml:id="gnis_pop.148604" xmlns:topp="' +
'http://www.openplans.org/topp">' +
' <gml:name>Aflu</gml:name>' +
' <topp:the_geom>' +
' <gml:Point srsName="urn:x-ogc:def:crs:EPSG:4326">' +
' <gml:pos>34.12 2.09</gml:pos>' +
' </gml:Point>' +
' </topp:the_geom>' +
' <topp:population>84683</topp:population>' +
' <topp:country>Algeria</topp:country>' +
' <topp:type>place</topp:type>' +
' <topp:name>Aflu</topp:name>' +
' <topp:cdata><![CDATA[<a>b</a>]]></topp:cdata>' +
' </topp:gnis_pop>' +
'</gml:featureMembers>';
const config = {
'featureNS': 'http://www.openplans.org/topp',
'featureType': 'gnis_pop'
};
features = new GML32(config).readFeatures(text);
} catch (e) {
done(e);
}
done();
});
it('creates 1 feature', function() {
expect(features).to.have.length(1);
});
it('converts XML attribute to text', function() {
expect(features[0].get('cdata')).to.be('<a>b</a>');
});
});
});

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<wfs:FeatureCollection xmlns:wfs="http://www.opengis.net/wfs"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tut="http://example.org/tutorial"
xmlns:gml="http://www.opengis.net/gml" xmlns:gsml="urn:cgi:xmlns:CGI:GeoSciML:2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" numberOfFeatures="3"
timeStamp="2018-08-15T11:52:11.366Z"
xsi:schemaLocation="urn:cgi:xmlns:CGI:GeoSciML:2.0 http://www.geosciml.org/geosciml/2.0/xsd/geosciml.xsd http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<gml:featureMember>
<gsml:MappedFeature gml:id="mf.25699">
<gml:name>Some basalt</gml:name>
<gml:name>urn:x-test:GeologicUnit:16777549126931093</gml:name>
<gsml:observationMethod>
<gsml:CGI_TermValue>
<gsml:value codeSpace="urn:ietf:rfc:2141">urn:ogc:def:nil:OGC:missing</gsml:value>
</gsml:CGI_TermValue>
</gsml:observationMethod>
<gsml:positionalAccuracy>
<gsml:CGI_TermValue>
<gsml:value codeSpace="urn:ietf:rfc:2141">urn:ogc:def:nil:OGC:missing</gsml:value>
</gsml:CGI_TermValue>
</gsml:positionalAccuracy>
<gsml:specification href="urn:x-test:GeologicUnit:16777549126931093" />
<gsml:shape>
<gml:Polygon srsDimension="2"
srsName="http://www.opengis.net/gml/srs/epsg.xml#3857">
<gml:exterior>
<gml:LinearRing srsDimension="2">
<gml:posList>1610340.1935838535 4284512.166074015
1610314.9870748299 4284503.122122704 1610322.4187882338
4284519.894649132 1610316.759094497 4284523.101981014
1610321.0122971204 4284531.491206108 1610318.0495807002
4284532.8242770685 1610319.6410451748 4284536.6111539425
1610319.099298857 4284537.417781517 1610321.247194622
4284537.699439952 1610317.932103093 4284554.413021458
1610326.2462194602 4284557.157338472 1610328.402928607
4284555.819838275 1610343.9490912845 4284513.26614925
1610340.1935838535 4284512.166074015</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gsml:shape>
</gsml:MappedFeature>
</gml:featureMember>
<gml:featureMember>
<gsml:MappedFeature gml:id="mf.25764">
<gml:name>More basalt</gml:name>
<gml:name>urn:x-test:GeologicUnit:16777549126931093</gml:name>
<gsml:observationMethod>
<gsml:CGI_TermValue>
<gsml:value codeSpace="urn:ietf:rfc:2141">urn:ogc:def:nil:OGC:missing</gsml:value>
</gsml:CGI_TermValue>
</gsml:observationMethod>
<gsml:positionalAccuracy>
<gsml:CGI_TermValue>
<gsml:value codeSpace="urn:ietf:rfc:2141">urn:ogc:def:nil:OGC:missing</gsml:value>
</gsml:CGI_TermValue>
</gsml:positionalAccuracy>
<gsml:specification href="urn:x-test:GeologicUnit:16777549126931093" />
<gsml:shape>
<gml:Polygon srsDimension="2"
srsName="http://www.opengis.net/gml/srs/epsg.xml#3857">
<gml:exterior>
<gml:LinearRing srsDimension="2">
<gml:posList>1610718.9221517597 4284805.42784805
1610707.3895121815 4284814.000918856 1610690.0555121175
4284839.544424725 1610688.6493659448 4284851.141369273
1610698.3130323582 4284852.813339175 1610705.8316511428
4284853.6639760295 1610706.7412747787 4284834.507828795
1610734.9743371184 4284830.61366508 1610750.0961105193
4284816.66263084 1610763.83073235 4284810.800250375
1610756.6916036862 4284789.441324945 1610725.3908253086
4284801.684887575 1610730.1263850513 4284820.332010645
1610726.08892804 4284821.659368354 1610723.710210181
4284814.359796638 1610718.9221517597 4284805.42784805
</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gsml:shape>
</gsml:MappedFeature>
</gml:featureMember>
<gml:featureMember>
<gsml:MappedFeature gml:id="mf.26106">
<gml:name>Some mudstone</gml:name>
<gml:name>urn:x-test:GeologicUnit:16777549126931077</gml:name>
<gsml:observationMethod>
<gsml:CGI_TermValue>
<gsml:value codeSpace="urn:ietf:rfc:2141">urn:ogc:def:nil:OGC:missing</gsml:value>
</gsml:CGI_TermValue>
</gsml:observationMethod>
<gsml:positionalAccuracy>
<gsml:CGI_TermValue>
<gsml:value codeSpace="urn:ietf:rfc:2141">urn:ogc:def:nil:OGC:missing</gsml:value>
</gsml:CGI_TermValue>
</gsml:positionalAccuracy>
<gsml:specification href="urn:x-test:GeologicUnit:16777549126931077" />
<gsml:shape>
<gml:Polygon srsDimension="2"
srsName="http://www.opengis.net/gml/srs/epsg.xml#3857">
<gml:exterior>
<gml:LinearRing srsDimension="2">
<gml:posList>1610399.8069898037 4284790.189299587
1610398.8760062372 4284763.736632759 1610381.1448500715
4284763.369532419 1610380.8659049459 4284765.257112044
1610366.8844742253 4284767.069534708 1610366.554168919
4284778.402387972 1610363.857132307 4284780.276704736
1610358.2706932572 4284769.990881423 1610363.6662297642
4284765.9723890135 1610352.2305719855 4284744.319844696
1610332.5497155024 4284756.625971695 1610332.5306289664
4284760.134211061 1610339.4369314983 4284774.745249511
1610350.0724354137 4284795.313982406 1610366.7215974482
4284797.024567371 1610374.5176296765 4284796.257709886
1610399.8069898037 4284790.189299587</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gsml:shape>
</gsml:MappedFeature>
</gml:featureMember>
</wfs:FeatureCollection>

View File

@@ -0,0 +1,236 @@
<?xml version="1.0" encoding="UTF-8"?>
<gml:FeatureCollection
xmlns:ogc="http://www.opengis.net/ogc" xmlns:opengeo="http://open-geo.com"
xmlns:tiger="http://www.census.gov" xmlns:wfs="http://www.opengis.net/wfs"
xmlns:topp="http://www.openplans.org/topp" xmlns:seb="http://seb.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ows="http://www.opengis.net/ows"
xmlns:gml="http://www.opengis.net/gml" xmlns:xlink="http://www.w3.org/1999/xlink">
<gml:featureMember>
<topp:states gml:id="states.1">
<gml:boundedBy>
<gml:Envelope srsName="urn:x-ogc:def:crs:EPSG:4326">
<gml:lowerCorner>36.986 -91.516</gml:lowerCorner>
<gml:upperCorner>42.509 -87.507</gml:upperCorner>
</gml:Envelope>
</gml:boundedBy>
<topp:the_geom>
<gml:MultiSurface srsName="urn:x-ogc:def:crs:EPSG:4326">
<gml:surfaceMember>
<gml:Polygon>
<gml:exterior>
<gml:LinearRing>
<gml:posList>37.511 -88.071 37.476 -88.087 37.442 -88.311 37.409
-88.359 37.421 -88.419 37.401 -88.467 37.296 -88.511 37.257
-88.501 37.205 -88.451 37.156 -88.422 37.098 -88.451 37.072
-88.476 37.068 -88.491 37.064 -88.517 37.072 -88.559 37.109
-88.614 37.135 -88.688 37.141 -88.739 37.152 -88.746 37.202
-88.863 37.218 -88.932 37.221 -88.993 37.185 -89.065 37.112
-89.116 37.093 -89.146 37.064 -89.169 37.025 -89.174 36.998
-89.151 36.988 -89.129 36.986 -89.193 37.028 -89.211 37.041
-89.237 37.087 -89.264 37.091 -89.284 37.085 -89.303 37.061
-89.309 37.027 -89.264 37.008 -89.262 36.999 -89.282 37.009
-89.311 37.049 -89.382 37.099 -89.379 37.137 -89.423 37.165
-89.441 37.224 -89.468 37.253 -89.465 37.256 -89.489 37.276
-89.513 37.304 -89.513 37.329 -89.501 37.339 -89.468 37.355
-89.435 37.411 -89.427 37.453 -89.453 37.491 -89.494 37.571
-89.524 37.615 -89.513 37.651 -89.519 37.679 -89.513 37.694
-89.521 37.706 -89.581 37.745 -89.666 37.783 -89.675 37.804
-89.691 37.841 -89.728 37.905 -89.851 37.905 -89.861 37.891
-89.866 37.875 -89.901 37.878 -89.937 37.911 -89.978 37.963
-89.958 37.969 -90.011 37.993 -90.041 38.032 -90.119 38.053
-90.134 38.088 -90.207 38.122 -90.254 38.166 -90.289 38.188
-90.336 38.234 -90.364 38.323 -90.369 38.365 -90.358 38.391
-90.339 38.427 -90.301 38.518 -90.265 38.532 -90.261 38.562
-90.241 38.611 -90.183 38.658 -90.183 38.701 -90.202 38.723
-90.196 38.773 -90.163 38.785 -90.135 38.801 -90.121 38.831
-90.113 38.853 -90.132 38.914 -90.243 38.924 -90.278 38.924
-90.319 38.962 -90.413 38.959 -90.469 38.891 -90.531 38.871
-90.571 38.881 -90.627 38.935 -90.668 39.037 -90.706 39.058
-90.707 39.093 -90.691 39.144 -90.716 39.195 -90.718 39.224
-90.732 39.247 -90.738 39.296 -90.779 39.351 -90.851 39.401
-90.947 39.444 -91.036 39.473 -91.064 39.528 -91.093 39.552
-91.156 39.601 -91.203 39.685 -91.317 39.724 -91.367 39.761
-91.373 39.803 -91.381 39.863 -91.449 39.885 -91.451 39.901
-91.434 39.921 -91.431 39.946 -91.447 40.005 -91.487 40.066
-91.504 40.134 -91.516 40.201 -91.506 40.251 -91.498 40.309
-91.486 40.371 -91.448 40.386 -91.418 40.392 -91.385 40.402
-91.372 40.447 -91.385 40.503 -91.374 40.528 -91.382 40.547
-91.412 40.572 -91.411 40.603 -91.375 40.639 -91.262 40.643
-91.214 40.656 -91.162 40.682 -91.129 40.705 -91.119 40.761
-91.092 40.833 -91.088 40.879 -91.049 40.923 -90.983 40.951
-90.961 41.071 -90.954 41.104 -90.957 41.144 -90.991 41.165
-91.018 41.176 -91.056 41.231 -91.101 41.267 -91.102 41.334
-91.073 41.401 -91.055 41.423 -91.027 41.431 -91.001 41.421
-90.949 41.444 -90.844 41.449 -90.779 41.451 -90.708 41.462
-90.658 41.509 -90.601 41.525 -90.541 41.527 -90.454 41.543
-90.434 41.567 -90.423 41.586 -90.348 41.602 -90.339 41.649
-90.341 41.722 -90.326 41.756 -90.304 41.781 -90.255 41.806
-90.195 41.931 -90.154 41.983 -90.142 42.033 -90.151 42.061
-90.168 42.103 -90.166 42.121 -90.176 42.122 -90.191 42.159
-90.231 42.197 -90.323 42.211 -90.367 42.242 -90.407 42.263
-90.417 42.341 -90.427 42.361 -90.441 42.388 -90.491 42.421
-90.563 42.461 -90.605 42.475 -90.648 42.494 -90.651 42.509
-90.638 42.508 -90.419 42.504 -89.923 42.503 -89.834 42.497
-89.401 42.497 -89.359 42.491 -88.939 42.491 -88.764 42.489
-88.706 42.491 -88.297 42.489 -88.194 42.489 -87.797 42.314
-87.836 42.156 -87.761 42.059 -87.671 41.847 -87.612 41.723
-87.529 41.469 -87.532 41.301 -87.532 41.173 -87.531 41.009
-87.532 40.745 -87.532 40.494 -87.537 40.483 -87.535 40.166
-87.535 39.887 -87.535 39.609 -87.535 39.477 -87.538 39.351
-87.541 39.338 -87.597 39.307 -87.625 39.297 -87.611 39.281
-87.615 39.258 -87.606 39.248 -87.584 39.208 -87.588 39.198
-87.594 39.196 -87.607 39.168 -87.644 39.146 -87.671 39.131
-87.659 39.113 -87.662 39.103 -87.631 39.088 -87.631 39.084
-87.612 39.062 -87.585 38.995 -87.581 38.994 -87.591 38.977
-87.547 38.963 -87.533 38.931 -87.531 38.904 -87.539 38.869
-87.559 38.857 -87.551 38.795 -87.507 38.776 -87.519 38.769
-87.508 38.736 -87.508 38.685 -87.543 38.672 -87.588 38.642
-87.625 38.622 -87.628 38.599 -87.619 38.593 -87.641 38.573
-87.652 38.547 -87.672 38.515 -87.651 38.501 -87.653 38.504
-87.679 38.481 -87.692 38.466 -87.756 38.457 -87.758 38.445
-87.738 38.417 -87.748 38.378 -87.784 38.352 -87.834 38.286
-87.851 38.285 -87.863 38.316 -87.874 38.315 -87.883 38.301
-87.888 38.281 -87.914 38.302 -87.913 38.304 -87.925 38.241
-87.981 38.234 -87.986 38.201 -87.977 38.171 -87.932 38.157
-87.931 38.136 -87.951 38.131 -87.973 38.103 -88.018 38.092
-88.012 38.096 -87.964 38.073 -87.975 38.054 -88.034 38.045
-88.043 38.038 -88.041 38.033 -88.021 38.008 -88.029 37.975
-88.021 37.956 -88.042 37.934 -88.041 37.929 -88.064 37.944
-88.078 37.923 -88.084 37.917 -88.031 37.905 -88.026 37.896
-88.044 37.906 -88.101 37.895 -88.101 37.867 -88.075 37.843
-88.034 37.827 -88.042 37.831 -88.089 37.817 -88.086 37.805
-88.035 37.735 -88.072 37.701 -88.133 37.661 -88.159 37.628
-88.157 37.583 -88.134 37.511 -88.071</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</topp:the_geom>
<topp:STATE_NAME>Illinois</topp:STATE_NAME>
<topp:STATE_FIPS>17</topp:STATE_FIPS>
<topp:SUB_REGION>E N Cen</topp:SUB_REGION>
<topp:STATE_ABBR>IL</topp:STATE_ABBR>
<topp:LAND_KM>143986.61</topp:LAND_KM>
<topp:WATER_KM>1993.335</topp:WATER_KM>
<topp:PERSONS>1.143E7</topp:PERSONS>
<topp:FAMILIES>2924880.0</topp:FAMILIES>
<topp:HOUSHOLD>4202240.0</topp:HOUSHOLD>
<topp:MALE>5552233.0</topp:MALE>
<topp:FEMALE>5878369.0</topp:FEMALE>
<topp:WORKERS>4199206.0</topp:WORKERS>
<topp:DRVALONE>3741715.0</topp:DRVALONE>
<topp:CARPOOL>652603.0</topp:CARPOOL>
<topp:PUBTRANS>538071.0</topp:PUBTRANS>
<topp:EMPLOYED>5417967.0</topp:EMPLOYED>
<topp:UNEMPLOY>385040.0</topp:UNEMPLOY>
<topp:SERVICE>1360159.0</topp:SERVICE>
<topp:MANUAL>828906.0</topp:MANUAL>
<topp:P_MALE>0.486</topp:P_MALE>
<topp:P_FEMALE>0.514</topp:P_FEMALE>
<topp:SAMP_POP>1747776.0</topp:SAMP_POP>
</topp:states>
</gml:featureMember>
<gml:featureMember>
<topp:states gml:id="states.2">
<gml:boundedBy>
<gml:Envelope srsName="urn:x-ogc:def:crs:EPSG:4326">
<gml:lowerCorner>38.788 -77.122</gml:lowerCorner>
<gml:upperCorner>38.993 -76.911</gml:upperCorner>
</gml:Envelope>
</gml:boundedBy>
<topp:the_geom>
<gml:MultiSurface srsName="urn:x-ogc:def:crs:EPSG:4326">
<gml:surfaceMember>
<gml:Polygon>
<gml:exterior>
<gml:LinearRing>
<gml:posList>38.966 -77.008 38.889 -76.911 38.788 -77.045 38.813
-77.035 38.829 -77.045 38.838 -77.041 38.862 -77.039 38.886
-77.067 38.915 -77.078 38.932 -77.122 38.993 -77.042 38.966
-77.008</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</topp:the_geom>
<topp:STATE_NAME>District of Columbia</topp:STATE_NAME>
<topp:STATE_FIPS>11</topp:STATE_FIPS>
<topp:SUB_REGION>S Atl</topp:SUB_REGION>
<topp:STATE_ABBR>DC</topp:STATE_ABBR>
<topp:LAND_KM>159.055</topp:LAND_KM>
<topp:WATER_KM>17.991</topp:WATER_KM>
<topp:PERSONS>606900.0</topp:PERSONS>
<topp:FAMILIES>122087.0</topp:FAMILIES>
<topp:HOUSHOLD>249634.0</topp:HOUSHOLD>
<topp:MALE>282970.0</topp:MALE>
<topp:FEMALE>323930.0</topp:FEMALE>
<topp:WORKERS>229975.0</topp:WORKERS>
<topp:DRVALONE>106694.0</topp:DRVALONE>
<topp:CARPOOL>36621.0</topp:CARPOOL>
<topp:PUBTRANS>111422.0</topp:PUBTRANS>
<topp:EMPLOYED>303994.0</topp:EMPLOYED>
<topp:UNEMPLOY>23442.0</topp:UNEMPLOY>
<topp:SERVICE>65498.0</topp:SERVICE>
<topp:MANUAL>22407.0</topp:MANUAL>
<topp:P_MALE>0.466</topp:P_MALE>
<topp:P_FEMALE>0.534</topp:P_FEMALE>
<topp:SAMP_POP>72696.0</topp:SAMP_POP>
</topp:states>
</gml:featureMember>
<gml:featureMember>
<topp:states gml:id="states.3">
<gml:boundedBy>
<gml:Envelope srsName="urn:x-ogc:def:crs:EPSG:4326">
<gml:lowerCorner>38.449 -75.791</gml:lowerCorner>
<gml:upperCorner>39.841 -75.045</gml:upperCorner>
</gml:Envelope>
</gml:boundedBy>
<topp:the_geom>
<gml:MultiSurface srsName="urn:x-ogc:def:crs:EPSG:4326">
<gml:surfaceMember>
<gml:Polygon>
<gml:exterior>
<gml:LinearRing>
<gml:posList>38.557 -75.707 38.649 -75.711 38.831 -75.724 39.141
-75.752 39.247 -75.761 39.295 -75.764 39.383 -75.772 39.723
-75.791 39.724 -75.775 39.774 -75.745 39.821 -75.695 39.838
-75.644 39.841 -75.583 39.826 -75.471 39.798 -75.421 39.789
-75.412 39.778 -75.428 39.763 -75.461 39.741 -75.475 39.719
-75.476 39.714 -75.489 39.612 -75.611 39.566 -75.562 39.463
-75.591 39.366 -75.515 39.257 -75.402 39.073 -75.397 39.012
-75.324 38.945 -75.307 38.808 -75.191 38.799 -75.083 38.449
-75.045 38.449 -75.068 38.451 -75.093 38.455 -75.351 38.463
-75.699 38.557 -75.707</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</topp:the_geom>
<topp:STATE_NAME>Delaware</topp:STATE_NAME>
<topp:STATE_FIPS>10</topp:STATE_FIPS>
<topp:SUB_REGION>S Atl</topp:SUB_REGION>
<topp:STATE_ABBR>DE</topp:STATE_ABBR>
<topp:LAND_KM>5062.456</topp:LAND_KM>
<topp:WATER_KM>1385.022</topp:WATER_KM>
<topp:PERSONS>666168.0</topp:PERSONS>
<topp:FAMILIES>175867.0</topp:FAMILIES>
<topp:HOUSHOLD>247497.0</topp:HOUSHOLD>
<topp:MALE>322968.0</topp:MALE>
<topp:FEMALE>343200.0</topp:FEMALE>
<topp:WORKERS>247566.0</topp:WORKERS>
<topp:DRVALONE>258087.0</topp:DRVALONE>
<topp:CARPOOL>42968.0</topp:CARPOOL>
<topp:PUBTRANS>8069.0</topp:PUBTRANS>
<topp:EMPLOYED>335147.0</topp:EMPLOYED>
<topp:UNEMPLOY>13945.0</topp:UNEMPLOY>
<topp:SERVICE>87973.0</topp:SERVICE>
<topp:MANUAL>44140.0</topp:MANUAL>
<topp:P_MALE>0.485</topp:P_MALE>
<topp:P_FEMALE>0.515</topp:P_FEMALE>
<topp:SAMP_POP>102776.0</topp:SAMP_POP>
</topp:states>
</gml:featureMember>
</gml:FeatureCollection>