From 717db8b78837b5df3e3643dffa300627c7ea9d65 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Wed, 26 Feb 2014 15:12:30 +0100 Subject: [PATCH 01/24] Add write support for gml:Point --- src/objectliterals.jsdoc | 1 + src/ol/format/gmlformat.js | 105 ++++++++++++++++++++++++++ test/spec/ol/format/gmlformat.test.js | 8 +- 3 files changed, 111 insertions(+), 3 deletions(-) diff --git a/src/objectliterals.jsdoc b/src/objectliterals.jsdoc index 55fbe40143..5663a6b486 100644 --- a/src/objectliterals.jsdoc +++ b/src/objectliterals.jsdoc @@ -308,6 +308,7 @@ * @typedef {Object} olx.format.GMLOptions * @property {string} featureNS Feature namespace. * @property {string} featureType Feature type to parse. + * @property {string} srsName srsName to use when writing geometries. */ /** diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index 3a91cf8b77..725a738e5a 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -9,6 +9,8 @@ goog.require('goog.string'); goog.require('ol.Feature'); goog.require('ol.extent'); goog.require('ol.format.XMLFeature'); +goog.require('ol.format.XSD'); +goog.require('ol.geom.Geometry'); goog.require('ol.geom.LineString'); goog.require('ol.geom.MultiLineString'); goog.require('ol.geom.MultiPoint'); @@ -43,6 +45,12 @@ ol.format.GML = function(opt_options) { */ this.featureNS_ = options.featureNS; + /** + * @private + * @type {string} + */ + this.srsName_ = options.srsName; + goog.base(this); }; goog.inherits(ol.format.GML, ol.format.XMLFeature); @@ -973,3 +981,100 @@ ol.format.GML.prototype.readFeaturesFromNode = function(node) { }]; return ol.format.GML.readFeatures_(node, objectStack); }; + + +/** + * @param {Node} node Node. + * @param {ol.geom.Point} value Point geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writePos_ = function(node, value, objectStack) { + var layout = value.getLayout(); + node.setAttribute('srsDimension', + (layout == ol.geom.GeometryLayout.XYZ) ? '3' : '2'); + ol.format.XSD.writeStringTextNode(node, value.getCoordinates().join(' ')); +}; + + +/** + * @const + * @param {*} value Value. + * @param {Array.<*>} objectStack Object stack. + * @param {string=} opt_nodeName Node name. + * @return {Node|undefined} Node. + * @private + */ +ol.format.GML.POS_NODE_FACTORY_ = ol.xml.makeSimpleNodeFactory('pos'); + + +/** + * @type {Object.>} + * @private + */ +ol.format.GML.POS_SERIALIZERS_ = { + 'http://www.opengis.net/gml': { + 'pos': ol.xml.makeChildAppender(ol.format.GML.writePos_), + 'pos_': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode) + } +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.Point} geometry Point geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writePoint_ = function(node, geometry, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + if (goog.isDefAndNotNull(srsName)) { + node.setAttribute('srsName', srsName); + } + ol.xml.pushSerializeAndPop({node: node}, ol.format.GML.POS_SERIALIZERS_, + ol.format.GML.POS_NODE_FACTORY_, [geometry], []); +}; + + +/** + * @type {Object.>} + * @private + */ +ol.format.GML.GEOMETRY_SERIALIZERS_ = { + 'http://www.opengis.net/gml': { + 'Point': ol.xml.makeChildAppender(ol.format.GML.writePoint_) + } +}; + + +/** + * @const + * @param {*} value Value. + * @param {Array.<*>} objectStack Object stack. + * @param {string=} opt_nodeName Node name. + * @return {Node|undefined} Node. + * @private + */ +ol.format.GML.GEOMETRY_NODE_FACTORY_ = function(value, objectStack, + opt_nodeName) { + goog.asserts.assertInstanceof(value, ol.geom.Geometry); + var parentNode = objectStack[objectStack.length - 1].node; + goog.asserts.assert(ol.xml.isNode(parentNode)); + return ol.xml.createElementNS(parentNode.namespaceURI, + value.getType()); +}; + + +/** + * @inheritDoc + */ +ol.format.GML.prototype.writeGeometryNode = function(geometry) { + var geom = ol.xml.createElementNS('http://www.opengis.net/gml', 'geom'); + var context = {node: geom, srsName: this.srsName_}; + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ + (context), ol.format.GML.GEOMETRY_SERIALIZERS_, + ol.format.GML.GEOMETRY_NODE_FACTORY_, [geometry], []); + return geom; +}; diff --git a/test/spec/ol/format/gmlformat.test.js b/test/spec/ol/format/gmlformat.test.js index 6f952fe3ed..c21e4b227a 100644 --- a/test/spec/ol/format/gmlformat.test.js +++ b/test/spec/ol/format/gmlformat.test.js @@ -12,22 +12,24 @@ describe('ol.format.GML', function() { var format; beforeEach(function() { - format = new ol.format.GML(); + format = new ol.format.GML({srsName: 'CRS:84'}); }); describe('#readGeometry', function() { describe('point', function() { - it('can read a point geometry', function() { + it('can read and write a point geometry', function() { var text = '' + - ' 1 2' + + ' 1 2 0' + ''; var g = readGeometry(format, text); expect(g).to.be.an(ol.geom.Point); expect(g.getCoordinates()).to.eql([1, 2, 0]); + var serialized = format.writeGeometry(g); + expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); }); From 083d8d9890e0cdd1a6eab8373862b029497a5979 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Wed, 26 Feb 2014 16:26:28 +0100 Subject: [PATCH 02/24] Add write support for gml:LineString --- src/ol/format/gmlformat.js | 73 ++++++++++++++++++++++++--- test/spec/ol/format/gmlformat.test.js | 4 +- 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index 725a738e5a..d0402222cc 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -680,10 +680,14 @@ ol.format.GML.readFlatPosList_ = function(node, objectStack) { } var coords = s.split(/\s+/); // The "dimension" attribute is from the GML 3.0.1 spec. - var dim = parseInt(node.getAttribute('srsDimension') || - node.getAttribute('dimension'), 10) || - (!goog.isNull(containerDimension)) ? - parseInt(containerDimension, 10) : 2; + var dim = 2; + if (!goog.isNull(node.getAttribute('srsDimension'))) { + dim = parseInt(node.getAttribute('srsDimension'), 10); + } else if (!goog.isNull(node.getAttribute('dimension'))) { + dim = parseInt(node.getAttribute('dimension'), 10); + } else if (!goog.isNull(containerDimension)) { + dim = parseInt(containerDimension, 10); + } var x, y, z; var flatCoordinates = []; for (var i = 0, ii = coords.length; i < ii; i += dim) { @@ -997,6 +1001,27 @@ ol.format.GML.writePos_ = function(node, value, objectStack) { }; +/** + * @param {Node} node Node. + * @param {ol.geom.Point} value Point geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writePosList_ = function(node, value, objectStack) { + // only 2d for simple features profile + var points = value.getCoordinates(); + var len = points.length; + var parts = new Array(len); + var point; + for (var i = 0; i < len; ++i) { + point = points[i]; + // TODO axis orientation + parts[i] = point[0] + ' ' + point[1]; + } + ol.format.XSD.writeStringTextNode(node, parts.join(' ')); +}; + + /** * @const * @param {*} value Value. @@ -1008,14 +1033,25 @@ ol.format.GML.writePos_ = function(node, value, objectStack) { ol.format.GML.POS_NODE_FACTORY_ = ol.xml.makeSimpleNodeFactory('pos'); +/** + * @const + * @param {*} value Value. + * @param {Array.<*>} objectStack Object stack. + * @param {string=} opt_nodeName Node name. + * @return {Node|undefined} Node. + * @private + */ +ol.format.GML.POSLIST_NODE_FACTORY_ = ol.xml.makeSimpleNodeFactory('posList'); + + /** * @type {Object.>} * @private */ -ol.format.GML.POS_SERIALIZERS_ = { +ol.format.GML.FLAT_COORDINATES_SERIALIZERS_ = { 'http://www.opengis.net/gml': { 'pos': ol.xml.makeChildAppender(ol.format.GML.writePos_), - 'pos_': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode) + 'posList': ol.xml.makeChildAppender(ol.format.GML.writePosList_) } }; @@ -1033,18 +1069,39 @@ ol.format.GML.writePoint_ = function(node, geometry, objectStack) { if (goog.isDefAndNotNull(srsName)) { node.setAttribute('srsName', srsName); } - ol.xml.pushSerializeAndPop({node: node}, ol.format.GML.POS_SERIALIZERS_, + ol.xml.pushSerializeAndPop({node: node}, + ol.format.GML.FLAT_COORDINATES_SERIALIZERS_, ol.format.GML.POS_NODE_FACTORY_, [geometry], []); }; +/** + * @param {Node} node Node. + * @param {ol.geom.LineString} geometry LineString geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writeLineString_ = function(node, geometry, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + if (goog.isDefAndNotNull(srsName)) { + node.setAttribute('srsName', srsName); + } + ol.xml.pushSerializeAndPop({node: node}, + ol.format.GML.FLAT_COORDINATES_SERIALIZERS_, + ol.format.GML.POSLIST_NODE_FACTORY_, [geometry], []); +}; + + /** * @type {Object.>} * @private */ ol.format.GML.GEOMETRY_SERIALIZERS_ = { 'http://www.opengis.net/gml': { - 'Point': ol.xml.makeChildAppender(ol.format.GML.writePoint_) + 'Point': ol.xml.makeChildAppender(ol.format.GML.writePoint_), + 'LineString': ol.xml.makeChildAppender(ol.format.GML.writeLineString_) } }; diff --git a/test/spec/ol/format/gmlformat.test.js b/test/spec/ol/format/gmlformat.test.js index c21e4b227a..c974ef2276 100644 --- a/test/spec/ol/format/gmlformat.test.js +++ b/test/spec/ol/format/gmlformat.test.js @@ -36,7 +36,7 @@ describe('ol.format.GML', function() { describe('linestring', function() { - it('can read a linestring geometry', function() { + it('can read and write a linestring geometry', function() { var text = '' + @@ -45,6 +45,8 @@ describe('ol.format.GML', function() { var g = readGeometry(format, text); expect(g).to.be.an(ol.geom.LineString); expect(g.getCoordinates()).to.eql([[1, 2, 0], [3, 4, 0]]); + var serialized = format.writeGeometry(g); + expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); }); From 37a78dc753e0e21d005c53bb293898901029d559 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Wed, 26 Feb 2014 16:53:37 +0100 Subject: [PATCH 03/24] Use correct axis order in write --- src/ol/format/gmlformat.js | 17 ++++++++++++++--- test/spec/ol/format/gmlformat.test.js | 26 ++++++++++++++++---------- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index d0402222cc..21c102646a 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -1008,6 +1008,13 @@ ol.format.GML.writePos_ = function(node, value, objectStack) { * @private */ ol.format.GML.writePosList_ = function(node, value, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + var axisOrientation = 'enu'; + if (goog.isDefAndNotNull(srsName)) { + axisOrientation = ol.proj.get(srsName).getAxisOrientation(); + } // only 2d for simple features profile var points = value.getCoordinates(); var len = points.length; @@ -1015,8 +1022,11 @@ ol.format.GML.writePosList_ = function(node, value, objectStack) { var point; for (var i = 0; i < len; ++i) { point = points[i]; - // TODO axis orientation - parts[i] = point[0] + ' ' + point[1]; + if (axisOrientation === 'enu') { + parts[i] = point[0] + ' ' + point[1]; + } else { + parts[i] = point[1] + ' ' + point[0]; + } } ol.format.XSD.writeStringTextNode(node, parts.join(' ')); }; @@ -1088,7 +1098,8 @@ ol.format.GML.writeLineString_ = function(node, geometry, objectStack) { if (goog.isDefAndNotNull(srsName)) { node.setAttribute('srsName', srsName); } - ol.xml.pushSerializeAndPop({node: node}, + var context = {node: node, srsName: srsName}; + ol.xml.pushSerializeAndPop(context, ol.format.GML.FLAT_COORDINATES_SERIALIZERS_, ol.format.GML.POSLIST_NODE_FACTORY_, [geometry], []); }; diff --git a/test/spec/ol/format/gmlformat.test.js b/test/spec/ol/format/gmlformat.test.js index c974ef2276..37039947e8 100644 --- a/test/spec/ol/format/gmlformat.test.js +++ b/test/spec/ol/format/gmlformat.test.js @@ -53,16 +53,22 @@ describe('ol.format.GML', function() { describe('axis order', function() { - it('can read a linestring geometry with correct axis order', function() { - var text = - '' + - ' -90 -180 90 180' + - ''; - var g = readGeometry(format, text); - expect(g).to.be.an(ol.geom.LineString); - expect(g.getCoordinates()).to.eql([[-180, -90, 0], [180, 90, 0]]); - }); + it('can read and write a linestring geometry with ' + + 'correct axis order', function() { + var text = + '' + + ' -90 -180 90 180' + + ''; + format = new ol.format.GML({ + srsName: 'urn:x-ogc:def:crs:EPSG:4326' + }); + var g = readGeometry(format, text); + expect(g).to.be.an(ol.geom.LineString); + expect(g.getCoordinates()).to.eql([[-180, -90, 0], [180, 90, 0]]); + var serialized = format.writeGeometry(g); + expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); + }); it('can read a point geometry with correct axis order', function() { var text = From 5240929a534391a052b862492115bb8168eae2e2 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Wed, 26 Feb 2014 17:37:16 +0100 Subject: [PATCH 04/24] Correct axis order for gml:pos --- src/ol/format/gmlformat.js | 27 +++++++++++++++++++------- test/spec/ol/format/gmlformat.test.js | 28 ++++++++++++++++----------- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index 21c102646a..0817d2cbca 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -694,7 +694,7 @@ ol.format.GML.readFlatPosList_ = function(node, objectStack) { x = parseFloat(coords[i]); y = parseFloat(coords[i + 1]); z = (dim === 3) ? parseFloat(coords[i + 2]) : 0; - if (axisOrientation === 'enu') { + if (axisOrientation.substr(0, 2) === 'en') { flatCoordinates.push(x, y, z); } else { flatCoordinates.push(y, x, z); @@ -994,10 +994,22 @@ ol.format.GML.prototype.readFeaturesFromNode = function(node) { * @private */ ol.format.GML.writePos_ = function(node, value, objectStack) { - var layout = value.getLayout(); - node.setAttribute('srsDimension', - (layout == ol.geom.GeometryLayout.XYZ) ? '3' : '2'); - ol.format.XSD.writeStringTextNode(node, value.getCoordinates().join(' ')); + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + var axisOrientation = 'enu'; + if (goog.isDefAndNotNull(srsName)) { + axisOrientation = ol.proj.get(srsName).getAxisOrientation(); + } + var point = value.getCoordinates(); + var coords; + // only 2d for simple features profile + if (axisOrientation.substr(0, 2) === 'en') { + coords = (point[0] + ' ' + point[1]); + } else { + coords = (point[1] + ' ' + point[0]); + } + ol.format.XSD.writeStringTextNode(node, coords); }; @@ -1022,7 +1034,7 @@ ol.format.GML.writePosList_ = function(node, value, objectStack) { var point; for (var i = 0; i < len; ++i) { point = points[i]; - if (axisOrientation === 'enu') { + if (axisOrientation.substr(0, 2) === 'en') { parts[i] = point[0] + ' ' + point[1]; } else { parts[i] = point[1] + ' ' + point[0]; @@ -1079,7 +1091,8 @@ ol.format.GML.writePoint_ = function(node, geometry, objectStack) { if (goog.isDefAndNotNull(srsName)) { node.setAttribute('srsName', srsName); } - ol.xml.pushSerializeAndPop({node: node}, + var context = {node: node, srsName: srsName}; + ol.xml.pushSerializeAndPop(context, ol.format.GML.FLAT_COORDINATES_SERIALIZERS_, ol.format.GML.POS_NODE_FACTORY_, [geometry], []); }; diff --git a/test/spec/ol/format/gmlformat.test.js b/test/spec/ol/format/gmlformat.test.js index 37039947e8..bf1f6cadae 100644 --- a/test/spec/ol/format/gmlformat.test.js +++ b/test/spec/ol/format/gmlformat.test.js @@ -23,7 +23,7 @@ describe('ol.format.GML', function() { var text = '' + - ' 1 2 0' + + ' 1 2' + ''; var g = readGeometry(format, text); expect(g).to.be.an(ol.geom.Point); @@ -70,16 +70,22 @@ describe('ol.format.GML', function() { expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); - it('can read a point geometry with correct axis order', function() { - var text = - '' + - ' -90 -180' + - ''; - var g = readGeometry(format, text); - expect(g).to.be.an(ol.geom.Point); - expect(g.getCoordinates()).to.eql([-180, -90, 0]); - }); + it('can read and write a point geometry with correct axis order', + function() { + var text = + '' + + ' -90 -180' + + ''; + format = new ol.format.GML({ + srsName: 'urn:x-ogc:def:crs:EPSG:4326' + }); + var g = readGeometry(format, text); + expect(g).to.be.an(ol.geom.Point); + expect(g.getCoordinates()).to.eql([-180, -90, 0]); + var serialized = format.writeGeometry(g); + expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); + }); it('can read multi surface geometry with right axis order', function() { var text = From 476bd901f065aa1cf1983a4de5917ba93887662a Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Wed, 26 Feb 2014 20:45:52 +0100 Subject: [PATCH 05/24] Add write support for gml:Polygon --- src/ol/format/gmlformat.js | 83 +++++++++++++++++++++++++-- test/spec/ol/format/gmlformat.test.js | 67 ++++++++++----------- 2 files changed, 112 insertions(+), 38 deletions(-) diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index 0817d2cbca..94ff07260e 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -1091,8 +1091,7 @@ ol.format.GML.writePoint_ = function(node, geometry, objectStack) { if (goog.isDefAndNotNull(srsName)) { node.setAttribute('srsName', srsName); } - var context = {node: node, srsName: srsName}; - ol.xml.pushSerializeAndPop(context, + ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, ol.format.GML.FLAT_COORDINATES_SERIALIZERS_, ol.format.GML.POS_NODE_FACTORY_, [geometry], []); }; @@ -1111,13 +1110,85 @@ ol.format.GML.writeLineString_ = function(node, geometry, objectStack) { if (goog.isDefAndNotNull(srsName)) { node.setAttribute('srsName', srsName); } - var context = {node: node, srsName: srsName}; - ol.xml.pushSerializeAndPop(context, + ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, ol.format.GML.FLAT_COORDINATES_SERIALIZERS_, ol.format.GML.POSLIST_NODE_FACTORY_, [geometry], []); }; +/** + * @param {Node} node Node. + * @param {ol.geom.LinearRing} geometry LinearRing geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writeLinearRing_ = function(node, geometry, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + if (goog.isDefAndNotNull(srsName)) { + node.setAttribute('srsName', srsName); + } + ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, + ol.format.GML.FLAT_COORDINATES_SERIALIZERS_, + ol.format.GML.POSLIST_NODE_FACTORY_, [geometry], []); +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.Polygon} geometry Polygon geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writePolygon_ = function(node, geometry, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + if (goog.isDefAndNotNull(srsName)) { + node.setAttribute('srsName', srsName); + } + var rings = geometry.getLinearRings(); + for (var i = 0, ii = rings.length; i < ii; ++i) { + if (i === 0) { + ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, + ol.format.GML.RING_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('exterior'), [rings[i]], objectStack); + } else { + ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, + ol.format.GML.RING_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('interior'), [rings[i]], objectStack); + } + } +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.LinearRing} ring LinearRing geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writeRing_ = function(node, ring, objectStack) { + var context = {node: node}; + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ + (context), ol.format.GML.GEOMETRY_SERIALIZERS_, + ol.format.GML.GEOMETRY_NODE_FACTORY_, [ring], []); +}; + + +/** + * @type {Object.>} + * @private + */ +ol.format.GML.RING_SERIALIZERS_ = { + 'http://www.opengis.net/gml': { + 'exterior': ol.xml.makeChildAppender(ol.format.GML.writeRing_), + 'interior': ol.xml.makeChildAppender(ol.format.GML.writeRing_) + } +}; + + /** * @type {Object.>} * @private @@ -1125,7 +1196,9 @@ ol.format.GML.writeLineString_ = function(node, geometry, objectStack) { ol.format.GML.GEOMETRY_SERIALIZERS_ = { 'http://www.opengis.net/gml': { 'Point': ol.xml.makeChildAppender(ol.format.GML.writePoint_), - 'LineString': ol.xml.makeChildAppender(ol.format.GML.writeLineString_) + 'LineString': ol.xml.makeChildAppender(ol.format.GML.writeLineString_), + 'LinearRing': ol.xml.makeChildAppender(ol.format.GML.writeLinearRing_), + 'Polygon': ol.xml.makeChildAppender(ol.format.GML.writePolygon_) } }; diff --git a/test/spec/ol/format/gmlformat.test.js b/test/spec/ol/format/gmlformat.test.js index bf1f6cadae..ca8b8218a1 100644 --- a/test/spec/ol/format/gmlformat.test.js +++ b/test/spec/ol/format/gmlformat.test.js @@ -10,9 +10,10 @@ var readGeometry = function(format, text) { describe('ol.format.GML', function() { - var format; + var format, formatWGS84; beforeEach(function() { format = new ol.format.GML({srsName: 'CRS:84'}); + formatWGS84 = new ol.format.GML({srsName: 'urn:x-ogc:def:crs:EPSG:4326'}); }); describe('#readGeometry', function() { @@ -60,13 +61,10 @@ describe('ol.format.GML', function() { ' srsName="urn:x-ogc:def:crs:EPSG:4326">' + ' -90 -180 90 180' + ''; - format = new ol.format.GML({ - srsName: 'urn:x-ogc:def:crs:EPSG:4326' - }); var g = readGeometry(format, text); expect(g).to.be.an(ol.geom.LineString); expect(g.getCoordinates()).to.eql([[-180, -90, 0], [180, 90, 0]]); - var serialized = format.writeGeometry(g); + var serialized = formatWGS84.writeGeometry(g); expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); @@ -77,38 +75,37 @@ describe('ol.format.GML', function() { ' srsName="urn:x-ogc:def:crs:EPSG:4326">' + ' -90 -180' + ''; - format = new ol.format.GML({ - srsName: 'urn:x-ogc:def:crs:EPSG:4326' - }); var g = readGeometry(format, text); expect(g).to.be.an(ol.geom.Point); expect(g.getCoordinates()).to.eql([-180, -90, 0]); - var serialized = format.writeGeometry(g); + var serialized = formatWGS84.writeGeometry(g); expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); - it('can read multi surface geometry with right axis order', function() { - var text = - '' + - ' ' + - ' ' + - ' ' + - ' ' + - ' 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' + - ' ' + - ' ' + - ' ' + - ' ' + - ''; - var 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); - }); + it('can read and write multi surface geometry with right axis order', + function() { + var text = + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' 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' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ''; + var 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); + }); }); @@ -129,7 +126,7 @@ describe('ol.format.GML', function() { describe('linearring', function() { - it('can read a linearring geometry', function() { + it('can read and write a linearring geometry', function() { var text = '' + @@ -139,13 +136,15 @@ describe('ol.format.GML', function() { expect(g).to.be.an(ol.geom.Polygon); expect(g.getCoordinates()).to.eql( [[[1, 2, 0], [3, 4, 0], [5, 6, 0], [1, 2, 0]]]); + var serialized = format.writeGeometry(g.getLinearRings()[0]); + expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); }); describe('polygon', function() { - it('can read a polygon geometry', function() { + it('can read and write a polygon geometry', function() { var text = '' + @@ -170,6 +169,8 @@ describe('ol.format.GML', function() { 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]]]); + var serialized = format.writeGeometry(g); + expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); }); From cbb38c10e00f8d982d5152ec064b74def7baff1d Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Thu, 27 Feb 2014 14:06:04 +0100 Subject: [PATCH 06/24] Add write support for gml:MultiSurface --- src/ol/format/gmlformat.js | 97 ++++++++++++++++++++++----- test/spec/ol/format/gmlformat.test.js | 9 ++- 2 files changed, 86 insertions(+), 20 deletions(-) diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index 94ff07260e..27bac21dd6 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -12,6 +12,7 @@ goog.require('ol.format.XMLFeature'); goog.require('ol.format.XSD'); goog.require('ol.geom.Geometry'); goog.require('ol.geom.LineString'); +goog.require('ol.geom.LinearRing'); goog.require('ol.geom.MultiLineString'); goog.require('ol.geom.MultiPoint'); goog.require('ol.geom.MultiPolygon'); @@ -496,7 +497,7 @@ ol.format.GML.readFlatLinearRing_ = function(node, objectStack) { * @param {Node} node Node. * @param {Array.<*>} objectStack Object stack. * @private - * @return {ol.geom.Polygon|undefined} Polygon. + * @return {ol.geom.LinearRing|undefined} LinearRing. */ ol.format.GML.readLinearRing_ = function(node, objectStack) { goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT); @@ -504,10 +505,9 @@ ol.format.GML.readLinearRing_ = function(node, objectStack) { var flatCoordinates = ol.format.GML.readFlatCoordinatesFromNode_(node, objectStack); if (goog.isDef(flatCoordinates)) { - var polygon = new ol.geom.Polygon(null); - polygon.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates, - [flatCoordinates.length]); - return polygon; + var ring = new ol.geom.LinearRing(null); + ring.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates); + return ring; } else { return undefined; } @@ -1126,7 +1126,8 @@ ol.format.GML.writeLinearRing_ = function(node, geometry, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var srsName = goog.object.get(context, 'srsName'); - if (goog.isDefAndNotNull(srsName)) { + var writeSrsName = goog.object.get(context, 'writeSrsName'); + if (writeSrsName !== false && goog.isDefAndNotNull(srsName)) { node.setAttribute('srsName', srsName); } ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, @@ -1145,24 +1146,49 @@ ol.format.GML.writePolygon_ = function(node, geometry, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var srsName = goog.object.get(context, 'srsName'); - if (goog.isDefAndNotNull(srsName)) { + var writeSrsName = goog.object.get(context, 'writeSrsName'); + if (writeSrsName !== false && goog.isDefAndNotNull(srsName)) { node.setAttribute('srsName', srsName); } var rings = geometry.getLinearRings(); for (var i = 0, ii = rings.length; i < ii; ++i) { if (i === 0) { - ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, - ol.format.GML.RING_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('exterior'), [rings[i]], objectStack); + ol.xml.pushSerializeAndPop({node: node, srsName: srsName, + writeSrsName: false}, ol.format.GML.RING_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('exterior'), [rings[i]], objectStack); } else { - ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, - ol.format.GML.RING_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('interior'), [rings[i]], objectStack); + ol.xml.pushSerializeAndPop({node: node, srsName: srsName, + writeSrsName: false}, ol.format.GML.RING_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('interior'), [rings[i]], objectStack); } } }; +/** + * @param {Node} node Node. + * @param {ol.geom.MultiPolygon} geometry MultiPolygon geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writeMultiSurface_ = function(node, geometry, + objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + if (goog.isDefAndNotNull(srsName)) { + node.setAttribute('srsName', srsName); + } + var polygons = geometry.getPolygons(); + for (var i = 0, ii = polygons.length; i < ii; ++i) { + ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, + ol.format.GML.SURFACEMEMBER_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('surfaceMember'), [polygons[i]], + objectStack); + } +}; + + /** * @param {Node} node Node. * @param {ol.geom.LinearRing} ring LinearRing geometry. @@ -1170,13 +1196,45 @@ ol.format.GML.writePolygon_ = function(node, geometry, objectStack) { * @private */ ol.format.GML.writeRing_ = function(node, ring, objectStack) { - var context = {node: node}; + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + var writeSrsName = goog.object.get(context, 'writeSrsName'); ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - (context), ol.format.GML.GEOMETRY_SERIALIZERS_, + ({node: node, srsName: srsName, writeSrsName: writeSrsName}), + ol.format.GML.GEOMETRY_SERIALIZERS_, ol.format.GML.GEOMETRY_NODE_FACTORY_, [ring], []); }; +/** + * @param {Node} node Node. + * @param {ol.geom.Polygon} polygon Polygon geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writeSurfaceMember_ = function(node, polygon, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ + ({node: node, srsName: srsName, writeSrsName: false}), + ol.format.GML.GEOMETRY_SERIALIZERS_, + ol.format.GML.GEOMETRY_NODE_FACTORY_, [polygon], []); +}; + + +/** + * @type {Object.>} + * @private + */ +ol.format.GML.SURFACEMEMBER_SERIALIZERS_ = { + 'http://www.opengis.net/gml': { + 'surfaceMember': ol.xml.makeChildAppender(ol.format.GML.writeSurfaceMember_) + } +}; + + /** * @type {Object.>} * @private @@ -1198,7 +1256,8 @@ ol.format.GML.GEOMETRY_SERIALIZERS_ = { 'Point': ol.xml.makeChildAppender(ol.format.GML.writePoint_), 'LineString': ol.xml.makeChildAppender(ol.format.GML.writeLineString_), 'LinearRing': ol.xml.makeChildAppender(ol.format.GML.writeLinearRing_), - 'Polygon': ol.xml.makeChildAppender(ol.format.GML.writePolygon_) + 'Polygon': ol.xml.makeChildAppender(ol.format.GML.writePolygon_), + 'MultiSurface': ol.xml.makeChildAppender(ol.format.GML.writeMultiSurface_) } }; @@ -1216,8 +1275,12 @@ ol.format.GML.GEOMETRY_NODE_FACTORY_ = function(value, objectStack, goog.asserts.assertInstanceof(value, ol.geom.Geometry); var parentNode = objectStack[objectStack.length - 1].node; goog.asserts.assert(ol.xml.isNode(parentNode)); + var nodeName = value.getType(); + if (nodeName === 'MultiPolygon') { + nodeName = 'MultiSurface'; + } return ol.xml.createElementNS(parentNode.namespaceURI, - value.getType()); + nodeName); }; diff --git a/test/spec/ol/format/gmlformat.test.js b/test/spec/ol/format/gmlformat.test.js index ca8b8218a1..afc377fc5b 100644 --- a/test/spec/ol/format/gmlformat.test.js +++ b/test/spec/ol/format/gmlformat.test.js @@ -105,6 +105,8 @@ describe('ol.format.GML', function() { var 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); + var serialized = formatWGS84.writeGeometry(g); + expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); }); @@ -133,10 +135,10 @@ describe('ol.format.GML', function() { ' 1 2 3 4 5 6 1 2' + ''; var g = readGeometry(format, text); - expect(g).to.be.an(ol.geom.Polygon); + expect(g).to.be.an(ol.geom.LinearRing); expect(g.getCoordinates()).to.eql( - [[[1, 2, 0], [3, 4, 0], [5, 6, 0], [1, 2, 0]]]); - var serialized = format.writeGeometry(g.getLinearRings()[0]); + [[1, 2, 0], [3, 4, 0], [5, 6, 0], [1, 2, 0]]); + var serialized = format.writeGeometry(g); expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); @@ -764,6 +766,7 @@ goog.require('goog.dom'); goog.require('goog.dom.TagName'); goog.require('ol.format.GML'); goog.require('ol.geom.LineString'); +goog.require('ol.geom.LinearRing'); goog.require('ol.geom.MultiPoint'); goog.require('ol.geom.MultiLineString'); goog.require('ol.geom.MultiPolygon'); From a6d6317d9e876c90aa03711a5ffa3f78c2d83b37 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Thu, 27 Feb 2014 20:15:32 +0100 Subject: [PATCH 07/24] Serialize polygon as surface --- src/objectliterals.jsdoc | 3 ++ src/ol/format/gmlformat.js | 75 ++++++++++++++++++++++++++- test/spec/ol/format/gmlformat.test.js | 11 ++-- 3 files changed, 84 insertions(+), 5 deletions(-) diff --git a/src/objectliterals.jsdoc b/src/objectliterals.jsdoc index 5663a6b486..bade290338 100644 --- a/src/objectliterals.jsdoc +++ b/src/objectliterals.jsdoc @@ -309,6 +309,9 @@ * @property {string} featureNS Feature namespace. * @property {string} featureType Feature type to parse. * @property {string} srsName srsName to use when writing geometries. + * @property {boolean|undefined} surface Write gml:Surface instead of + * gml:Polygon elements. This also affects the elements in multi-part + * geometries. Default is `false´. */ /** diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index 27bac21dd6..6e37f63e0e 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -52,6 +52,13 @@ ol.format.GML = function(opt_options) { */ this.srsName_ = options.srsName; + /** + * @private + * @type {boolean} + */ + this.surface_ = goog.isDef(options.surface) ? + options.surface : false; + goog.base(this); }; goog.inherits(ol.format.GML, ol.format.XMLFeature); @@ -1165,6 +1172,26 @@ ol.format.GML.writePolygon_ = function(node, geometry, objectStack) { }; +/** + * @param {Node} node Node. + * @param {ol.geom.Polygon} geometry Polygon geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writeSurface_ = function(node, geometry, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + if (goog.isDefAndNotNull(srsName)) { + node.setAttribute('srsName', srsName); + } + ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, + ol.format.GML.PATCH_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('patches'), [geometry], + objectStack); +}; + + /** * @param {Node} node Node. * @param {ol.geom.MultiPolygon} geometry MultiPolygon geometry. @@ -1224,6 +1251,23 @@ ol.format.GML.writeSurfaceMember_ = function(node, polygon, objectStack) { }; +/** + * @param {Node} node Node. + * @param {ol.geom.Polygon} polygon Polygon geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writeSurfacePatches_ = function(node, polygon, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ + ({node: node, srsName: srsName, writeSrsName: false}), + ol.format.GML.SURFACE_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('PolygonPatch'), [polygon], []); +}; + + /** * @type {Object.>} * @private @@ -1235,6 +1279,17 @@ ol.format.GML.SURFACEMEMBER_SERIALIZERS_ = { }; +/** + * @type {Object.>} + * @private + */ +ol.format.GML.PATCH_SERIALIZERS_ = { + 'http://www.opengis.net/gml': { + 'patches': ol.xml.makeChildAppender(ol.format.GML.writeSurfacePatches_) + } +}; + + /** * @type {Object.>} * @private @@ -1247,6 +1302,17 @@ ol.format.GML.RING_SERIALIZERS_ = { }; +/** + * @type {Object.>} + * @private + */ +ol.format.GML.SURFACE_SERIALIZERS_ = { + 'http://www.opengis.net/gml': { + 'PolygonPatch': ol.xml.makeChildAppender(ol.format.GML.writePolygon_) + } +}; + + /** * @type {Object.>} * @private @@ -1257,6 +1323,7 @@ ol.format.GML.GEOMETRY_SERIALIZERS_ = { 'LineString': ol.xml.makeChildAppender(ol.format.GML.writeLineString_), 'LinearRing': ol.xml.makeChildAppender(ol.format.GML.writeLinearRing_), 'Polygon': ol.xml.makeChildAppender(ol.format.GML.writePolygon_), + 'Surface': ol.xml.makeChildAppender(ol.format.GML.writeSurface_), 'MultiSurface': ol.xml.makeChildAppender(ol.format.GML.writeMultiSurface_) } }; @@ -1272,6 +1339,9 @@ ol.format.GML.GEOMETRY_SERIALIZERS_ = { */ ol.format.GML.GEOMETRY_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var surface = goog.object.get(context, 'surface'); goog.asserts.assertInstanceof(value, ol.geom.Geometry); var parentNode = objectStack[objectStack.length - 1].node; goog.asserts.assert(ol.xml.isNode(parentNode)); @@ -1279,6 +1349,9 @@ ol.format.GML.GEOMETRY_NODE_FACTORY_ = function(value, objectStack, if (nodeName === 'MultiPolygon') { nodeName = 'MultiSurface'; } + if (nodeName === 'Polygon' && surface === true) { + nodeName = 'Surface'; + } return ol.xml.createElementNS(parentNode.namespaceURI, nodeName); }; @@ -1289,7 +1362,7 @@ ol.format.GML.GEOMETRY_NODE_FACTORY_ = function(value, objectStack, */ ol.format.GML.prototype.writeGeometryNode = function(geometry) { var geom = ol.xml.createElementNS('http://www.opengis.net/gml', 'geom'); - var context = {node: geom, srsName: this.srsName_}; + var context = {node: geom, srsName: this.srsName_, surface: this.surface_}; ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (context), ol.format.GML.GEOMETRY_SERIALIZERS_, ol.format.GML.GEOMETRY_NODE_FACTORY_, [geometry], []); diff --git a/test/spec/ol/format/gmlformat.test.js b/test/spec/ol/format/gmlformat.test.js index afc377fc5b..d48e8616b7 100644 --- a/test/spec/ol/format/gmlformat.test.js +++ b/test/spec/ol/format/gmlformat.test.js @@ -179,12 +179,12 @@ describe('ol.format.GML', function() { describe('surface', function() { - it('can read a surface geometry', function() { + it('can read and write a surface geometry', function() { var text = '' + ' ' + - ' ' + + ' ' + ' ' + ' ' + ' 1 2 3 2 3 4 1 2' + @@ -208,6 +208,9 @@ describe('ol.format.GML', function() { 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 ol.format.GML({srsName: 'CRS:84', surface: true}); + var serialized = format.writeGeometry(g); + expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); }); @@ -573,7 +576,7 @@ describe('ol.format.GML', function() { ' ' + ' ' + ' ' + - ' ' + + ' ' + ' ' + ' ' + ' 1 2 3 2 3 4 1 2' + @@ -596,7 +599,7 @@ describe('ol.format.GML', function() { ' ' + ' ' + ' ' + - ' ' + + ' ' + ' ' + ' ' + ' 1 2 3 2 3 4 1 2' + From c4c53a7ac31ba611229c15c76d55bcfe3e931b49 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Thu, 27 Feb 2014 20:55:50 +0100 Subject: [PATCH 08/24] Add write support for gml:Curve --- src/objectliterals.jsdoc | 3 ++ src/ol/format/gmlformat.js | 78 ++++++++++++++++++++++++++- test/spec/ol/format/gmlformat.test.js | 5 +- 3 files changed, 83 insertions(+), 3 deletions(-) diff --git a/src/objectliterals.jsdoc b/src/objectliterals.jsdoc index bade290338..97a4e5e9bc 100644 --- a/src/objectliterals.jsdoc +++ b/src/objectliterals.jsdoc @@ -312,6 +312,9 @@ * @property {boolean|undefined} surface Write gml:Surface instead of * gml:Polygon elements. This also affects the elements in multi-part * geometries. Default is `false´. + * @property {boolean|undefined} curve Write gml:Curve instead of + * gml:LineString elements. This also affects the elements in multi-part + * geometries. Default is `false´. */ /** diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index 6e37f63e0e..ff22bd19f2 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -59,6 +59,13 @@ ol.format.GML = function(opt_options) { this.surface_ = goog.isDef(options.surface) ? options.surface : false; + /** + * @private + * @type {boolean} + */ + this.curve_ = goog.isDef(options.curve) ? + options.curve : false; + goog.base(this); }; goog.inherits(ol.format.GML, ol.format.XMLFeature); @@ -1114,7 +1121,8 @@ ol.format.GML.writeLineString_ = function(node, geometry, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var srsName = goog.object.get(context, 'srsName'); - if (goog.isDefAndNotNull(srsName)) { + var writeSrsName = goog.object.get(context, 'writeSrsName'); + if (goog.isDefAndNotNull(srsName) && writeSrsName !== false) { node.setAttribute('srsName', srsName); } ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, @@ -1192,6 +1200,26 @@ ol.format.GML.writeSurface_ = function(node, geometry, objectStack) { }; +/** + * @param {Node} node Node. + * @param {ol.geom.LineString} geometry LineString geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writeCurve_ = function(node, geometry, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + if (goog.isDefAndNotNull(srsName)) { + node.setAttribute('srsName', srsName); + } + ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, + ol.format.GML.SEGMENT_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('segments'), [geometry], + objectStack); +}; + + /** * @param {Node} node Node. * @param {ol.geom.MultiPolygon} geometry MultiPolygon geometry. @@ -1268,6 +1296,23 @@ ol.format.GML.writeSurfacePatches_ = function(node, polygon, objectStack) { }; +/** + * @param {Node} node Node. + * @param {ol.geom.LineString} line LineString geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writeCurveSegments_ = function(node, line, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ + ({node: node, srsName: srsName, writeSrsName: false}), + ol.format.GML.CURVE_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('LineStringSegment'), [line], []); +}; + + /** * @type {Object.>} * @private @@ -1290,6 +1335,17 @@ ol.format.GML.PATCH_SERIALIZERS_ = { }; +/** + * @type {Object.>} + * @private + */ +ol.format.GML.SEGMENT_SERIALIZERS_ = { + 'http://www.opengis.net/gml': { + 'segments': ol.xml.makeChildAppender(ol.format.GML.writeCurveSegments_) + } +}; + + /** * @type {Object.>} * @private @@ -1313,12 +1369,25 @@ ol.format.GML.SURFACE_SERIALIZERS_ = { }; +/** + * @type {Object.>} + * @private + */ +ol.format.GML.CURVE_SERIALIZERS_ = { + 'http://www.opengis.net/gml': { + 'LineStringSegment': ol.xml.makeChildAppender( + ol.format.GML.writeLineString_) + } +}; + + /** * @type {Object.>} * @private */ ol.format.GML.GEOMETRY_SERIALIZERS_ = { 'http://www.opengis.net/gml': { + 'Curve': ol.xml.makeChildAppender(ol.format.GML.writeCurve_), 'Point': ol.xml.makeChildAppender(ol.format.GML.writePoint_), 'LineString': ol.xml.makeChildAppender(ol.format.GML.writeLineString_), 'LinearRing': ol.xml.makeChildAppender(ol.format.GML.writeLinearRing_), @@ -1342,6 +1411,7 @@ ol.format.GML.GEOMETRY_NODE_FACTORY_ = function(value, objectStack, var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var surface = goog.object.get(context, 'surface'); + var curve = goog.object.get(context, 'curve'); goog.asserts.assertInstanceof(value, ol.geom.Geometry); var parentNode = objectStack[objectStack.length - 1].node; goog.asserts.assert(ol.xml.isNode(parentNode)); @@ -1352,6 +1422,9 @@ ol.format.GML.GEOMETRY_NODE_FACTORY_ = function(value, objectStack, if (nodeName === 'Polygon' && surface === true) { nodeName = 'Surface'; } + if (nodeName === 'LineString' && curve === true) { + nodeName = 'Curve'; + } return ol.xml.createElementNS(parentNode.namespaceURI, nodeName); }; @@ -1362,7 +1435,8 @@ ol.format.GML.GEOMETRY_NODE_FACTORY_ = function(value, objectStack, */ ol.format.GML.prototype.writeGeometryNode = function(geometry) { var geom = ol.xml.createElementNS('http://www.opengis.net/gml', 'geom'); - var context = {node: geom, srsName: this.srsName_, surface: this.surface_}; + var context = {node: geom, srsName: this.srsName_, + curve: this.curve_, surface: this.surface_}; ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (context), ol.format.GML.GEOMETRY_SERIALIZERS_, ol.format.GML.GEOMETRY_NODE_FACTORY_, [geometry], []); diff --git a/test/spec/ol/format/gmlformat.test.js b/test/spec/ol/format/gmlformat.test.js index d48e8616b7..6d824ee1df 100644 --- a/test/spec/ol/format/gmlformat.test.js +++ b/test/spec/ol/format/gmlformat.test.js @@ -217,7 +217,7 @@ describe('ol.format.GML', function() { describe('curve', function() { - it('can read a curve geometry', function() { + it('can read and write a curve geometry', function() { var text = '' + @@ -230,6 +230,9 @@ describe('ol.format.GML', function() { var g = readGeometry(format, text); expect(g).to.be.an(ol.geom.LineString); expect(g.getCoordinates()).to.eql([[1, 2, 0], [3, 4, 0]]); + format = new ol.format.GML({srsName: 'CRS:84', curve: true}); + var serialized = format.writeGeometry(g); + expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); }); From a79f8442c7d4a1fd180aa2ce0251d7ed11f1c34e Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Thu, 27 Feb 2014 21:05:59 +0100 Subject: [PATCH 09/24] Add write support for gml:MultiPoint --- src/ol/format/gmlformat.js | 56 ++++++++++++++++++++++++++- test/spec/ol/format/gmlformat.test.js | 4 +- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index ff22bd19f2..6c1a3cb112 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -1102,7 +1102,8 @@ ol.format.GML.writePoint_ = function(node, geometry, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var srsName = goog.object.get(context, 'srsName'); - if (goog.isDefAndNotNull(srsName)) { + var writeSrsName = goog.object.get(context, 'writeSrsName'); + if (goog.isDefAndNotNull(srsName) && writeSrsName !== false) { node.setAttribute('srsName', srsName); } ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, @@ -1244,6 +1245,30 @@ ol.format.GML.writeMultiSurface_ = function(node, geometry, }; +/** + * @param {Node} node Node. + * @param {ol.geom.MultiPoint} geometry MultiPoint geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writeMultiPoint_ = function(node, geometry, + objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + if (goog.isDefAndNotNull(srsName)) { + node.setAttribute('srsName', srsName); + } + var points = geometry.getPoints(); + for (var i = 0, ii = points.length; i < ii; ++i) { + ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, + ol.format.GML.POINTMEMBER_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('pointMember'), [points[i]], + objectStack); + } +}; + + /** * @param {Node} node Node. * @param {ol.geom.LinearRing} ring LinearRing geometry. @@ -1279,6 +1304,23 @@ ol.format.GML.writeSurfaceMember_ = function(node, polygon, objectStack) { }; +/** + * @param {Node} node Node. + * @param {ol.geom.Point} point Point geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writePointMember_ = function(node, point, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ + ({node: node, srsName: srsName, writeSrsName: false}), + ol.format.GML.GEOMETRY_SERIALIZERS_, + ol.format.GML.GEOMETRY_NODE_FACTORY_, [point], []); +}; + + /** * @param {Node} node Node. * @param {ol.geom.Polygon} polygon Polygon geometry. @@ -1324,6 +1366,17 @@ ol.format.GML.SURFACEMEMBER_SERIALIZERS_ = { }; +/** + * @type {Object.>} + * @private + */ +ol.format.GML.POINTMEMBER_SERIALIZERS_ = { + 'http://www.opengis.net/gml': { + 'pointMember': ol.xml.makeChildAppender(ol.format.GML.writePointMember_) + } +}; + + /** * @type {Object.>} * @private @@ -1389,6 +1442,7 @@ ol.format.GML.GEOMETRY_SERIALIZERS_ = { 'http://www.opengis.net/gml': { 'Curve': ol.xml.makeChildAppender(ol.format.GML.writeCurve_), 'Point': ol.xml.makeChildAppender(ol.format.GML.writePoint_), + 'MultiPoint': ol.xml.makeChildAppender(ol.format.GML.writeMultiPoint_), 'LineString': ol.xml.makeChildAppender(ol.format.GML.writeLineString_), 'LinearRing': ol.xml.makeChildAppender(ol.format.GML.writeLinearRing_), 'Polygon': ol.xml.makeChildAppender(ol.format.GML.writePolygon_), diff --git a/test/spec/ol/format/gmlformat.test.js b/test/spec/ol/format/gmlformat.test.js index 6d824ee1df..8a1bfdc1ee 100644 --- a/test/spec/ol/format/gmlformat.test.js +++ b/test/spec/ol/format/gmlformat.test.js @@ -254,7 +254,7 @@ describe('ol.format.GML', function() { describe('multipoint', function() { - it('can read a singular multipoint geometry', function() { + it('can read and write a singular multipoint geometry', function() { var text = '' + @@ -277,6 +277,8 @@ describe('ol.format.GML', function() { var g = readGeometry(format, text); expect(g).to.be.an(ol.geom.MultiPoint); expect(g.getCoordinates()).to.eql([[1, 2, 0], [2, 3, 0], [3, 4, 0]]); + var serialized = format.writeGeometry(g); + expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); it('can read a plural multipoint geometry', function() { From 414c6e2a127533c940d5bfb9e0ca781b3151c8bd Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Thu, 27 Feb 2014 21:13:09 +0100 Subject: [PATCH 10/24] Add write support for gml:MultiLineString --- src/ol/format/gmlformat.js | 55 +++++++++++++++++++++++++++ test/spec/ol/format/gmlformat.test.js | 4 +- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index 6c1a3cb112..54b56f58bf 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -1269,6 +1269,30 @@ ol.format.GML.writeMultiPoint_ = function(node, geometry, }; +/** + * @param {Node} node Node. + * @param {ol.geom.MultiLineString} geometry MultiLineString geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writeMultiLineString_ = function(node, geometry, + objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + if (goog.isDefAndNotNull(srsName)) { + node.setAttribute('srsName', srsName); + } + var lines = geometry.getLineStrings(); + for (var i = 0, ii = lines.length; i < ii; ++i) { + ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, + ol.format.GML.LINESTRINGMEMBER_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('lineStringMember'), [lines[i]], + objectStack); + } +}; + + /** * @param {Node} node Node. * @param {ol.geom.LinearRing} ring LinearRing geometry. @@ -1321,6 +1345,23 @@ ol.format.GML.writePointMember_ = function(node, point, objectStack) { }; +/** + * @param {Node} node Node. + * @param {ol.geom.LineString} line LineString geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writeLineStringMember_ = function(node, line, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ + ({node: node, srsName: srsName, writeSrsName: false}), + ol.format.GML.GEOMETRY_SERIALIZERS_, + ol.format.GML.GEOMETRY_NODE_FACTORY_, [line], []); +}; + + /** * @param {Node} node Node. * @param {ol.geom.Polygon} polygon Polygon geometry. @@ -1377,6 +1418,18 @@ ol.format.GML.POINTMEMBER_SERIALIZERS_ = { }; +/** + * @type {Object.>} + * @private + */ +ol.format.GML.LINESTRINGMEMBER_SERIALIZERS_ = { + 'http://www.opengis.net/gml': { + 'lineStringMember': ol.xml.makeChildAppender( + ol.format.GML.writeLineStringMember_) + } +}; + + /** * @type {Object.>} * @private @@ -1444,6 +1497,8 @@ ol.format.GML.GEOMETRY_SERIALIZERS_ = { 'Point': ol.xml.makeChildAppender(ol.format.GML.writePoint_), 'MultiPoint': ol.xml.makeChildAppender(ol.format.GML.writeMultiPoint_), 'LineString': ol.xml.makeChildAppender(ol.format.GML.writeLineString_), + 'MultiLineString': ol.xml.makeChildAppender( + ol.format.GML.writeMultiLineString_), 'LinearRing': ol.xml.makeChildAppender(ol.format.GML.writeLinearRing_), 'Polygon': ol.xml.makeChildAppender(ol.format.GML.writePolygon_), 'Surface': ol.xml.makeChildAppender(ol.format.GML.writeSurface_), diff --git a/test/spec/ol/format/gmlformat.test.js b/test/spec/ol/format/gmlformat.test.js index 8a1bfdc1ee..da05ccd515 100644 --- a/test/spec/ol/format/gmlformat.test.js +++ b/test/spec/ol/format/gmlformat.test.js @@ -306,7 +306,7 @@ describe('ol.format.GML', function() { describe('multilinestring', function() { - it('can read a singular multilinestring geometry', function() { + it('can read and write a singular multilinestring geometry', function() { var text = '' + @@ -325,6 +325,8 @@ describe('ol.format.GML', function() { expect(g).to.be.an(ol.geom.MultiLineString); expect(g.getCoordinates()).to.eql( [[[1, 2, 0], [2, 3, 0]], [[3, 4, 0], [4, 5, 0]]]); + var serialized = format.writeGeometry(g); + expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); it('can read a plural multilinestring geometry', function() { From 86d90d2f8a9fb1b7a249ac87ac1206baaec038aa Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Thu, 27 Feb 2014 21:29:55 +0100 Subject: [PATCH 11/24] Add write support for gml:MultiPolygon --- src/ol/format/gmlformat.js | 39 +++++++++++++++++++++++---- test/spec/ol/format/gmlformat.test.js | 8 +++--- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index 54b56f58bf..bca113ca33 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -1238,13 +1238,37 @@ ol.format.GML.writeMultiSurface_ = function(node, geometry, var polygons = geometry.getPolygons(); for (var i = 0, ii = polygons.length; i < ii; ++i) { ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, - ol.format.GML.SURFACEMEMBER_SERIALIZERS_, + ol.format.GML.SURFACEORPOLYGONMEMBER_SERIALIZERS_, ol.xml.makeSimpleNodeFactory('surfaceMember'), [polygons[i]], objectStack); } }; +/** + * @param {Node} node Node. + * @param {ol.geom.MultiPolygon} geometry MultiPolygon geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writeMultiPolygon_ = function(node, geometry, + objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + if (goog.isDefAndNotNull(srsName)) { + node.setAttribute('srsName', srsName); + } + var polygons = geometry.getPolygons(); + for (var i = 0, ii = polygons.length; i < ii; ++i) { + ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, + ol.format.GML.SURFACEORPOLYGONMEMBER_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('polygonMember'), [polygons[i]], + objectStack); + } +}; + + /** * @param {Node} node Node. * @param {ol.geom.MultiPoint} geometry MultiPoint geometry. @@ -1317,7 +1341,8 @@ ol.format.GML.writeRing_ = function(node, ring, objectStack) { * @param {Array.<*>} objectStack Node stack. * @private */ -ol.format.GML.writeSurfaceMember_ = function(node, polygon, objectStack) { +ol.format.GML.writeSurfaceOrPolygonMember_ = function(node, polygon, + objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var srsName = goog.object.get(context, 'srsName'); @@ -1400,9 +1425,12 @@ ol.format.GML.writeCurveSegments_ = function(node, line, objectStack) { * @type {Object.>} * @private */ -ol.format.GML.SURFACEMEMBER_SERIALIZERS_ = { +ol.format.GML.SURFACEORPOLYGONMEMBER_SERIALIZERS_ = { 'http://www.opengis.net/gml': { - 'surfaceMember': ol.xml.makeChildAppender(ol.format.GML.writeSurfaceMember_) + 'SURFACEORsurfaceMember': ol.xml.makeChildAppender( + ol.format.GML.writeSurfaceOrPolygonMember_), + 'polygonMember': ol.xml.makeChildAppender( + ol.format.GML.writeSurfaceOrPolygonMember_) } }; @@ -1501,6 +1529,7 @@ ol.format.GML.GEOMETRY_SERIALIZERS_ = { ol.format.GML.writeMultiLineString_), 'LinearRing': ol.xml.makeChildAppender(ol.format.GML.writeLinearRing_), 'Polygon': ol.xml.makeChildAppender(ol.format.GML.writePolygon_), + 'MultiPolygon': ol.xml.makeChildAppender(ol.format.GML.writeMultiPolygon_), 'Surface': ol.xml.makeChildAppender(ol.format.GML.writeSurface_), 'MultiSurface': ol.xml.makeChildAppender(ol.format.GML.writeMultiSurface_) } @@ -1525,7 +1554,7 @@ ol.format.GML.GEOMETRY_NODE_FACTORY_ = function(value, objectStack, var parentNode = objectStack[objectStack.length - 1].node; goog.asserts.assert(ol.xml.isNode(parentNode)); var nodeName = value.getType(); - if (nodeName === 'MultiPolygon') { + if (nodeName === 'MultiPolygon' && surface === true) { nodeName = 'MultiSurface'; } if (nodeName === 'Polygon' && surface === true) { diff --git a/test/spec/ol/format/gmlformat.test.js b/test/spec/ol/format/gmlformat.test.js index da05ccd515..826efb0c56 100644 --- a/test/spec/ol/format/gmlformat.test.js +++ b/test/spec/ol/format/gmlformat.test.js @@ -82,7 +82,7 @@ describe('ol.format.GML', function() { expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); - it('can read and write multi surface geometry with right axis order', + it('can read a surface geometry with right axis order', function() { var text = '' + @@ -392,6 +390,8 @@ describe('ol.format.GML', function() { [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]]]]); + var serialized = format.writeGeometry(g); + expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); it('can read a plural multipolygon geometry', function() { From 6cd9e4bcf474451996451c844bcc9160bb142463 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Thu, 27 Feb 2014 21:53:19 +0100 Subject: [PATCH 12/24] Add write support for gml:MultiCurve --- src/objectliterals.jsdoc | 6 +++ src/ol/format/gmlformat.js | 66 ++++++++++++++++++++++----- test/spec/ol/format/gmlformat.test.js | 51 ++++++++++++--------- 3 files changed, 91 insertions(+), 32 deletions(-) diff --git a/src/objectliterals.jsdoc b/src/objectliterals.jsdoc index 97a4e5e9bc..4342676075 100644 --- a/src/objectliterals.jsdoc +++ b/src/objectliterals.jsdoc @@ -315,6 +315,12 @@ * @property {boolean|undefined} curve Write gml:Curve instead of * gml:LineString elements. This also affects the elements in multi-part * geometries. Default is `false´. + * @property {boolean|undefined} multiCurve Write gml:MultiCurve instead of + * gml:MultiLineString. Since the latter is deprecated in GML 3, the + * default is `true´. + * @property {boolean|undefined} multiSurface Write gml:multiSurface instead + * of gml:MultiPolygon. Since the latter is deprecated in GML 3, the + * default is `true´. */ /** diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index bca113ca33..fdc147d1e3 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -66,6 +66,20 @@ ol.format.GML = function(opt_options) { this.curve_ = goog.isDef(options.curve) ? options.curve : false; + /** + * @private + * @type {boolean} + */ + this.multiCurve_ = goog.isDef(options.multiCurve) ? + options.multiCurve : true; + + /** + * @private + * @type {boolean} + */ + this.multiSurface_ = goog.isDef(options.multiSurface) ? + options.multiSurface : true; + goog.base(this); }; goog.inherits(ol.format.GML, ol.format.XMLFeature); @@ -1310,13 +1324,36 @@ ol.format.GML.writeMultiLineString_ = function(node, geometry, var lines = geometry.getLineStrings(); for (var i = 0, ii = lines.length; i < ii; ++i) { ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, - ol.format.GML.LINESTRINGMEMBER_SERIALIZERS_, + ol.format.GML.LINESTRINGORCURVEMEMBER_SERIALIZERS_, ol.xml.makeSimpleNodeFactory('lineStringMember'), [lines[i]], objectStack); } }; +/** + * @param {Node} node Node. + * @param {ol.geom.MultiLineString} geometry MultiLineString geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writeMultiCurve_ = function(node, geometry, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + if (goog.isDefAndNotNull(srsName)) { + node.setAttribute('srsName', srsName); + } + var lines = geometry.getLineStrings(); + for (var i = 0, ii = lines.length; i < ii; ++i) { + ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, + ol.format.GML.LINESTRINGORCURVEMEMBER_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('curveMember'), [lines[i]], + objectStack); + } +}; + + /** * @param {Node} node Node. * @param {ol.geom.LinearRing} ring LinearRing geometry. @@ -1376,7 +1413,8 @@ ol.format.GML.writePointMember_ = function(node, point, objectStack) { * @param {Array.<*>} objectStack Node stack. * @private */ -ol.format.GML.writeLineStringMember_ = function(node, line, objectStack) { +ol.format.GML.writeLineStringOrCurveMember_ = function(node, line, + objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var srsName = goog.object.get(context, 'srsName'); @@ -1427,7 +1465,7 @@ ol.format.GML.writeCurveSegments_ = function(node, line, objectStack) { */ ol.format.GML.SURFACEORPOLYGONMEMBER_SERIALIZERS_ = { 'http://www.opengis.net/gml': { - 'SURFACEORsurfaceMember': ol.xml.makeChildAppender( + 'surfaceMember': ol.xml.makeChildAppender( ol.format.GML.writeSurfaceOrPolygonMember_), 'polygonMember': ol.xml.makeChildAppender( ol.format.GML.writeSurfaceOrPolygonMember_) @@ -1450,10 +1488,12 @@ ol.format.GML.POINTMEMBER_SERIALIZERS_ = { * @type {Object.>} * @private */ -ol.format.GML.LINESTRINGMEMBER_SERIALIZERS_ = { +ol.format.GML.LINESTRINGORCURVEMEMBER_SERIALIZERS_ = { 'http://www.opengis.net/gml': { 'lineStringMember': ol.xml.makeChildAppender( - ol.format.GML.writeLineStringMember_) + ol.format.GML.writeLineStringOrCurveMember_), + 'curveMember': ol.xml.makeChildAppender( + ol.format.GML.writeLineStringOrCurveMember_) } }; @@ -1522,6 +1562,7 @@ ol.format.GML.CURVE_SERIALIZERS_ = { ol.format.GML.GEOMETRY_SERIALIZERS_ = { 'http://www.opengis.net/gml': { 'Curve': ol.xml.makeChildAppender(ol.format.GML.writeCurve_), + 'MultiCurve': ol.xml.makeChildAppender(ol.format.GML.writeMultiCurve_), 'Point': ol.xml.makeChildAppender(ol.format.GML.writePoint_), 'MultiPoint': ol.xml.makeChildAppender(ol.format.GML.writeMultiPoint_), 'LineString': ol.xml.makeChildAppender(ol.format.GML.writeLineString_), @@ -1548,20 +1589,22 @@ ol.format.GML.GEOMETRY_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); + var multiSurface = goog.object.get(context, 'multiSurface'); var surface = goog.object.get(context, 'surface'); var curve = goog.object.get(context, 'curve'); + var multiCurve = goog.object.get(context, 'multiCurve'); goog.asserts.assertInstanceof(value, ol.geom.Geometry); var parentNode = objectStack[objectStack.length - 1].node; goog.asserts.assert(ol.xml.isNode(parentNode)); var nodeName = value.getType(); - if (nodeName === 'MultiPolygon' && surface === true) { + if (nodeName === 'MultiPolygon' && multiSurface === true) { nodeName = 'MultiSurface'; - } - if (nodeName === 'Polygon' && surface === true) { + } else if (nodeName === 'Polygon' && surface === true) { nodeName = 'Surface'; - } - if (nodeName === 'LineString' && curve === true) { + } else if (nodeName === 'LineString' && curve === true) { nodeName = 'Curve'; + } else if (nodeName === 'MultiLineString' && multiCurve === true) { + nodeName = 'MultiCurve'; } return ol.xml.createElementNS(parentNode.namespaceURI, nodeName); @@ -1574,7 +1617,8 @@ ol.format.GML.GEOMETRY_NODE_FACTORY_ = function(value, objectStack, ol.format.GML.prototype.writeGeometryNode = function(geometry) { var geom = ol.xml.createElementNS('http://www.opengis.net/gml', 'geom'); var context = {node: geom, srsName: this.srsName_, - curve: this.curve_, surface: this.surface_}; + curve: this.curve_, surface: this.surface_, + multiSurface: this.multiSurface_, multiCurve: this.multiCurve_}; ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (context), ol.format.GML.GEOMETRY_SERIALIZERS_, ol.format.GML.GEOMETRY_NODE_FACTORY_, [geometry], []); diff --git a/test/spec/ol/format/gmlformat.test.js b/test/spec/ol/format/gmlformat.test.js index 826efb0c56..dd094643ef 100644 --- a/test/spec/ol/format/gmlformat.test.js +++ b/test/spec/ol/format/gmlformat.test.js @@ -82,7 +82,7 @@ describe('ol.format.GML', function() { expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); - it('can read a surface geometry with right axis order', + it('can read and write a surface geometry with right axis order', function() { var text = '' + - ' ' + - ' ' + - ' 1 2 2 3' + - ' ' + - ' ' + - ' ' + - ' ' + - ' 3 4 4 5' + - ' ' + - ' ' + - ''; - var g = readGeometry(format, text); - expect(g).to.be.an(ol.geom.MultiLineString); - expect(g.getCoordinates()).to.eql( - [[[1, 2, 0], [2, 3, 0]], [[3, 4, 0], [4, 5, 0]]]); - }); + it('can read and write a singular multicurve-linestring geometry', + function() { + var text = + '' + + ' ' + + ' ' + + ' 1 2 2 3' + + ' ' + + ' ' + + ' ' + + ' ' + + ' 3 4 4 5' + + ' ' + + ' ' + + ''; + var g = readGeometry(format, text); + expect(g).to.be.an(ol.geom.MultiLineString); + expect(g.getCoordinates()).to.eql( + [[[1, 2, 0], [2, 3, 0]], [[3, 4, 0], [4, 5, 0]]]); + var serialized = format.writeGeometry(g); + expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); + }); it('can read a singular multicurve-curve geometry', function() { var text = From 3e09ea4a00c9a58ab49069891bb1679885cd88b2 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Fri, 28 Feb 2014 10:53:57 +0100 Subject: [PATCH 13/24] Finish off writeGeometry --- src/ol/format/gmlformat.js | 18 ++++++++++++------ test/spec/ol/format/gmlformat.test.js | 14 +++++++++++--- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index fdc147d1e3..2ce9f3cfe8 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -1205,7 +1205,8 @@ ol.format.GML.writeSurface_ = function(node, geometry, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var srsName = goog.object.get(context, 'srsName'); - if (goog.isDefAndNotNull(srsName)) { + var writeSrsName = goog.object.get(context, 'writeSrsName'); + if (goog.isDefAndNotNull(srsName) && writeSrsName !== false) { node.setAttribute('srsName', srsName); } ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, @@ -1225,7 +1226,8 @@ ol.format.GML.writeCurve_ = function(node, geometry, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var srsName = goog.object.get(context, 'srsName'); - if (goog.isDefAndNotNull(srsName)) { + var writeSrsName = goog.object.get(context, 'writeSrsName'); + if (goog.isDefAndNotNull(srsName) && writeSrsName !== false) { node.setAttribute('srsName', srsName); } ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, @@ -1246,12 +1248,13 @@ ol.format.GML.writeMultiSurface_ = function(node, geometry, var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var srsName = goog.object.get(context, 'srsName'); + var surface = goog.object.get(context, 'surface'); if (goog.isDefAndNotNull(srsName)) { node.setAttribute('srsName', srsName); } var polygons = geometry.getPolygons(); for (var i = 0, ii = polygons.length; i < ii; ++i) { - ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, + ol.xml.pushSerializeAndPop({node: node, srsName: srsName, surface: surface}, ol.format.GML.SURFACEORPOLYGONMEMBER_SERIALIZERS_, ol.xml.makeSimpleNodeFactory('surfaceMember'), [polygons[i]], objectStack); @@ -1341,12 +1344,13 @@ ol.format.GML.writeMultiCurve_ = function(node, geometry, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var srsName = goog.object.get(context, 'srsName'); + var curve = goog.object.get(context, 'curve'); if (goog.isDefAndNotNull(srsName)) { node.setAttribute('srsName', srsName); } var lines = geometry.getLineStrings(); for (var i = 0, ii = lines.length; i < ii; ++i) { - ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, + ol.xml.pushSerializeAndPop({node: node, srsName: srsName, curve: curve}, ol.format.GML.LINESTRINGORCURVEMEMBER_SERIALIZERS_, ol.xml.makeSimpleNodeFactory('curveMember'), [lines[i]], objectStack); @@ -1382,9 +1386,10 @@ ol.format.GML.writeSurfaceOrPolygonMember_ = function(node, polygon, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); + var surface = goog.object.get(context, 'surface'); var srsName = goog.object.get(context, 'srsName'); ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - ({node: node, srsName: srsName, writeSrsName: false}), + ({node: node, srsName: srsName, writeSrsName: false, surface: surface}), ol.format.GML.GEOMETRY_SERIALIZERS_, ol.format.GML.GEOMETRY_NODE_FACTORY_, [polygon], []); }; @@ -1417,9 +1422,10 @@ ol.format.GML.writeLineStringOrCurveMember_ = function(node, line, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); + var curve = goog.object.get(context, 'curve'); var srsName = goog.object.get(context, 'srsName'); ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - ({node: node, srsName: srsName, writeSrsName: false}), + ({node: node, srsName: srsName, writeSrsName: false, curve: curve}), ol.format.GML.GEOMETRY_SERIALIZERS_, ol.format.GML.GEOMETRY_NODE_FACTORY_, [line], []); }; diff --git a/test/spec/ol/format/gmlformat.test.js b/test/spec/ol/format/gmlformat.test.js index dd094643ef..429fec83e2 100644 --- a/test/spec/ol/format/gmlformat.test.js +++ b/test/spec/ol/format/gmlformat.test.js @@ -468,7 +468,7 @@ describe('ol.format.GML', function() { expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); - it('can read a singular multicurve-curve geometry', function() { + it('can read and write a singular multicurve-curve geometry', function() { var text = '' + @@ -495,13 +495,16 @@ describe('ol.format.GML', function() { expect(g).to.be.an(ol.geom.MultiLineString); expect(g.getCoordinates()).to.eql( [[[1, 2, 0], [2, 3, 0]], [[3, 4, 0], [4, 5, 0]]]); + format = new ol.format.GML({srsName: 'CRS:84', curve: true}); + var serialized = format.writeGeometry(g); + expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); }); describe('multisurface', function() { - it('can read a singular multisurface geometry', function() { + it('can read and write a singular multisurface geometry', function() { var text = '' + @@ -541,6 +544,8 @@ describe('ol.format.GML', function() { [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]]]]); + var serialized = format.writeGeometry(g); + expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); it('can read a plural multisurface geometry', function() { @@ -585,7 +590,7 @@ describe('ol.format.GML', function() { [[[1, 2, 0], [3, 2, 0], [3, 4, 0], [1, 2, 0]]]]); }); - it('can read a multisurface-surface geometry', function() { + it('can read and write a multisurface-surface geometry', function() { var text = '' + @@ -633,6 +638,9 @@ describe('ol.format.GML', function() { [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 ol.format.GML({srsName: 'CRS:84', surface: true}); + var serialized = format.writeGeometry(g); + expect(serialized.firstElementChild).to.xmleql(ol.xml.load(text)); }); }); From 8dce3249d6cb65e6fe8087dd9024fa418c6d0def Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Fri, 28 Feb 2014 17:23:03 +0100 Subject: [PATCH 14/24] Implement writeFeatures --- src/ol/format/gmlformat.js | 108 +++++++++++++++++++++++++- test/spec/ol/format/gmlformat.test.js | 6 +- 2 files changed, 111 insertions(+), 3 deletions(-) diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index 2ce9f3cfe8..3ec268dca3 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -1465,6 +1465,76 @@ ol.format.GML.writeCurveSegments_ = function(node, line, objectStack) { }; +/** + * @param {Node} node Node. + * @param {ol.geom.Geometry} geometry Geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writeGeometry_ = function(node, geometry, objectStack) { + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ + ({node: node}), ol.format.GML.GEOMETRY_SERIALIZERS_, + ol.format.GML.GEOMETRY_NODE_FACTORY_, [geometry], []); +}; + + +/** + * @param {Node} node Node. + * @param {ol.Feature} feature Feature. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writeFeature_ = function(node, feature, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var featureNS = goog.object.get(context, 'featureNS'); + var geometryName = feature.getGeometryName(); + var serializers = {}; + serializers[featureNS] = {}; + var properties = feature.getProperties(); + var keys = [], values = []; + for (var key in properties) { + keys.push(key); + values.push(properties[key]); + if (key == geometryName) { + serializers[featureNS][key] = ol.xml.makeChildAppender( + ol.format.GML.writeGeometry_); + } else { + serializers[featureNS][key] = ol.xml.makeChildAppender( + ol.format.XSD.writeStringTextNode); + } + } + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ + ({node: node}), serializers, + ol.xml.OBJECT_PROPERTY_NODE_FACTORY, + values, + objectStack, keys); +}; + + +/** + * @param {Node} node Node. + * @param {Array.} features Features. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writeFeatureMembers_ = function(node, features, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var featureType = goog.object.get(context, 'featureType'); + var featureNS = goog.object.get(context, 'featureNS'); + //featureNS = 'http://www.opengis.net/gml'; + var serializers = {}; + serializers[featureNS] = {}; + serializers[featureNS][featureType] = ol.xml.makeChildAppender( + ol.format.GML.writeFeature_); + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ + ({node: node, featureType: featureType, featureNS: featureNS}), + serializers, + ol.xml.makeSimpleNodeFactory(featureType, featureNS), features, []); +}; + + /** * @type {Object.>} * @private @@ -1583,6 +1653,18 @@ ol.format.GML.GEOMETRY_SERIALIZERS_ = { }; +/** + * @type {Object.>} + * @private + */ +ol.format.GML.GML_SERIALIZERS_ = { + 'http://www.opengis.net/gml': { + 'featureMembers': ol.xml.makeChildAppender( + ol.format.GML.writeFeatureMembers_) + } +}; + + /** * @const * @param {*} value Value. @@ -1612,7 +1694,7 @@ ol.format.GML.GEOMETRY_NODE_FACTORY_ = function(value, objectStack, } else if (nodeName === 'MultiLineString' && multiCurve === true) { nodeName = 'MultiCurve'; } - return ol.xml.createElementNS(parentNode.namespaceURI, + return ol.xml.createElementNS('http://www.opengis.net/gml', nodeName); }; @@ -1630,3 +1712,27 @@ ol.format.GML.prototype.writeGeometryNode = function(geometry) { ol.format.GML.GEOMETRY_NODE_FACTORY_, [geometry], []); return geom; }; + + +/** + * @inheritDoc + */ +ol.format.GML.prototype.writeFeaturesNode = function(features) { + var collection = ol.xml.createElementNS('http://www.opengis.net/wfs', + 'FeatureCollection'); + var context = { + node: collection, + srsName: this.srsName_, + curve: this.curve_, + surface: this.surface_, + multiSurface: this.multiSurface_, + multiCurve: this.multiCurve_, + featureNS: this.featureNS_, + featureType: this.featureType_ + }; + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ + (context), ol.format.GML.GML_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('featureMembers', + 'http://www.opengis.net/gml'), [features], []); + return collection; +}; diff --git a/test/spec/ol/format/gmlformat.test.js b/test/spec/ol/format/gmlformat.test.js index 429fec83e2..334cdefb0f 100644 --- a/test/spec/ol/format/gmlformat.test.js +++ b/test/spec/ol/format/gmlformat.test.js @@ -706,7 +706,7 @@ describe('ol.format.GML', function() { describe('when parsing TOPP states GML from WFS', function() { - var features, feature; + var features, feature, text, wfsFormat; before(function(done) { afterLoadText('spec/ol/format/gml/topp-states-wfs.xml', function(xml) { try { @@ -714,7 +714,9 @@ describe('ol.format.GML', function() { 'featureNS': 'http://www.openplans.org/topp', 'featureType': 'states' }; - features = new ol.format.GML(config).readFeatures(xml); + text = xml; + wfsFormat = new ol.format.GML(config); + features = wfsFormat.readFeatures(xml); } catch (e) { done(e); } From 9b4fc06a5b411932a4f9ca48cecb43f9ae6e7d38 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Mon, 3 Mar 2014 14:01:07 +0100 Subject: [PATCH 15/24] Finish write support for features --- src/objectliterals.jsdoc | 2 + src/ol/format/gmlformat.js | 55 +++++++++++++++------------ test/spec/ol/format/gmlformat.test.js | 27 +++++++++---- 3 files changed, 53 insertions(+), 31 deletions(-) diff --git a/src/objectliterals.jsdoc b/src/objectliterals.jsdoc index 4342676075..19ef7ded72 100644 --- a/src/objectliterals.jsdoc +++ b/src/objectliterals.jsdoc @@ -321,6 +321,8 @@ * @property {boolean|undefined} multiSurface Write gml:multiSurface instead * of gml:MultiPolygon. Since the latter is deprecated in GML 3, the * default is `true´. + * @property {string|undefined} schemaLocation Optional schemaLocation to use + * when writing out the GML, this will override the default provided. */ /** diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index 3ec268dca3..a3857bd141 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -80,6 +80,15 @@ ol.format.GML = function(opt_options) { this.multiSurface_ = goog.isDef(options.multiSurface) ? options.multiSurface : true; + /** + * @private + * @type {string} + */ + this.schemaLocation_ = goog.isDef(options.schemaLocation) ? + options.schemaLocation : ('http://www.opengis.net/gml ' + + 'http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/' + + '1.0.0/gmlsf.xsd'); + goog.base(this); }; goog.inherits(ol.format.GML, ol.format.XMLFeature); @@ -1472,8 +1481,12 @@ ol.format.GML.writeCurveSegments_ = function(node, line, objectStack) { * @private */ ol.format.GML.writeGeometry_ = function(node, geometry, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var item = goog.object.clone(context); + goog.object.set(item, 'node', node); ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - ({node: node}), ol.format.GML.GEOMETRY_SERIALIZERS_, + (item), ol.format.GML.GEOMETRY_SERIALIZERS_, ol.format.GML.GEOMETRY_NODE_FACTORY_, [geometry], []); }; @@ -1485,6 +1498,10 @@ ol.format.GML.writeGeometry_ = function(node, geometry, objectStack) { * @private */ ol.format.GML.writeFeature_ = function(node, feature, objectStack) { + var fid = feature.getId(); + if (goog.isDef(fid)) { + node.setAttribute('fid', fid); + } var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var featureNS = goog.object.get(context, 'featureNS'); @@ -1504,8 +1521,10 @@ ol.format.GML.writeFeature_ = function(node, feature, objectStack) { ol.format.XSD.writeStringTextNode); } } + var item = goog.object.clone(context); + goog.object.set(item, 'node', node); ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - ({node: node}), serializers, + (item), serializers, ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, keys); @@ -1523,13 +1542,14 @@ ol.format.GML.writeFeatureMembers_ = function(node, features, objectStack) { goog.asserts.assert(goog.isObject(context)); var featureType = goog.object.get(context, 'featureType'); var featureNS = goog.object.get(context, 'featureNS'); - //featureNS = 'http://www.opengis.net/gml'; var serializers = {}; serializers[featureNS] = {}; serializers[featureNS][featureType] = ol.xml.makeChildAppender( ol.format.GML.writeFeature_); + var item = goog.object.clone(context); + goog.object.set(item, 'node', node); ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - ({node: node, featureType: featureType, featureNS: featureNS}), + (item), serializers, ol.xml.makeSimpleNodeFactory(featureType, featureNS), features, []); }; @@ -1653,18 +1673,6 @@ ol.format.GML.GEOMETRY_SERIALIZERS_ = { }; -/** - * @type {Object.>} - * @private - */ -ol.format.GML.GML_SERIALIZERS_ = { - 'http://www.opengis.net/gml': { - 'featureMembers': ol.xml.makeChildAppender( - ol.format.GML.writeFeatureMembers_) - } -}; - - /** * @const * @param {*} value Value. @@ -1718,10 +1726,12 @@ ol.format.GML.prototype.writeGeometryNode = function(geometry) { * @inheritDoc */ ol.format.GML.prototype.writeFeaturesNode = function(features) { - var collection = ol.xml.createElementNS('http://www.opengis.net/wfs', - 'FeatureCollection'); + var node = ol.xml.createElementNS('http://www.opengis.net/gml', + 'featureMembers'); + ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance', + 'xsi:schemaLocation', this.schemaLocation_); var context = { - node: collection, + node: node, srsName: this.srsName_, curve: this.curve_, surface: this.surface_, @@ -1730,9 +1740,6 @@ ol.format.GML.prototype.writeFeaturesNode = function(features) { featureNS: this.featureNS_, featureType: this.featureType_ }; - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - (context), ol.format.GML.GML_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('featureMembers', - 'http://www.opengis.net/gml'), [features], []); - return collection; + ol.format.GML.writeFeatureMembers_(node, features, [context]); + return node; }; diff --git a/test/spec/ol/format/gmlformat.test.js b/test/spec/ol/format/gmlformat.test.js index 334cdefb0f..93a075b19b 100644 --- a/test/spec/ol/format/gmlformat.test.js +++ b/test/spec/ol/format/gmlformat.test.js @@ -678,15 +678,25 @@ describe('ol.format.GML', function() { describe('when parsing TOPP states GML', function() { - var features; + var features, text, gmlFormat; before(function(done) { afterLoadText('spec/ol/format/gml/topp-states-gml.xml', function(xml) { try { + var 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'; var config = { 'featureNS': 'http://www.openplans.org/topp', - 'featureType': 'states' + 'featureType': 'states', + 'multiSurface': true, + 'srsName': 'urn:x-ogc:def:crs:EPSG:4326', + 'schemaLocation': schemaLoc }; - features = new ol.format.GML(config).readFeatures(xml); + text = xml; + gmlFormat = new ol.format.GML(config); + features = gmlFormat.readFeatures(xml); } catch (e) { done(e); } @@ -702,11 +712,16 @@ describe('ol.format.GML', function() { expect(features[0].getId()).to.equal('states.1'); }); + it('writes back features as GML', function() { + var serialized = gmlFormat.writeFeatures(features); + expect(serialized).to.xmleql(ol.xml.load(text)); + }); + }); describe('when parsing TOPP states GML from WFS', function() { - var features, feature, text, wfsFormat; + var features, feature; before(function(done) { afterLoadText('spec/ol/format/gml/topp-states-wfs.xml', function(xml) { try { @@ -714,9 +729,7 @@ describe('ol.format.GML', function() { 'featureNS': 'http://www.openplans.org/topp', 'featureType': 'states' }; - text = xml; - wfsFormat = new ol.format.GML(config); - features = wfsFormat.readFeatures(xml); + features = new ol.format.GML(config).readFeatures(xml); } catch (e) { done(e); } From 2bc5e462d1d4d4e2ef3f597c83ee2d3f0214af1b Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Mon, 3 Mar 2014 16:39:05 +0100 Subject: [PATCH 16/24] Use more intelligent node factories, less duplicate code --- src/ol/format/gmlformat.js | 112 +++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 55 deletions(-) diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index a3857bd141..486cfaebc5 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -1252,7 +1252,7 @@ ol.format.GML.writeCurve_ = function(node, geometry, objectStack) { * @param {Array.<*>} objectStack Node stack. * @private */ -ol.format.GML.writeMultiSurface_ = function(node, geometry, +ol.format.GML.writeMultiSurfaceOrPolygon_ = function(node, geometry, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); @@ -1265,31 +1265,7 @@ ol.format.GML.writeMultiSurface_ = function(node, geometry, for (var i = 0, ii = polygons.length; i < ii; ++i) { ol.xml.pushSerializeAndPop({node: node, srsName: srsName, surface: surface}, ol.format.GML.SURFACEORPOLYGONMEMBER_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('surfaceMember'), [polygons[i]], - objectStack); - } -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.MultiPolygon} geometry MultiPolygon geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML.writeMultiPolygon_ = function(node, geometry, - objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context)); - var srsName = goog.object.get(context, 'srsName'); - if (goog.isDefAndNotNull(srsName)) { - node.setAttribute('srsName', srsName); - } - var polygons = geometry.getPolygons(); - for (var i = 0, ii = polygons.length; i < ii; ++i) { - ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, - ol.format.GML.SURFACEORPOLYGONMEMBER_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('polygonMember'), [polygons[i]], + ol.format.GML.MULTISURFACEORPOLYGON_NODE_FACTORY_, [polygons[i]], objectStack); } }; @@ -1325,34 +1301,11 @@ ol.format.GML.writeMultiPoint_ = function(node, geometry, * @param {Array.<*>} objectStack Node stack. * @private */ -ol.format.GML.writeMultiLineString_ = function(node, geometry, +ol.format.GML.writeMultiCurveOrLineString_ = function(node, geometry, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var srsName = goog.object.get(context, 'srsName'); - if (goog.isDefAndNotNull(srsName)) { - node.setAttribute('srsName', srsName); - } - var lines = geometry.getLineStrings(); - for (var i = 0, ii = lines.length; i < ii; ++i) { - ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, - ol.format.GML.LINESTRINGORCURVEMEMBER_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('lineStringMember'), [lines[i]], - objectStack); - } -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.MultiLineString} geometry MultiLineString geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML.writeMultiCurve_ = function(node, geometry, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context)); - var srsName = goog.object.get(context, 'srsName'); var curve = goog.object.get(context, 'curve'); if (goog.isDefAndNotNull(srsName)) { node.setAttribute('srsName', srsName); @@ -1361,7 +1314,7 @@ ol.format.GML.writeMultiCurve_ = function(node, geometry, objectStack) { for (var i = 0, ii = lines.length; i < ii; ++i) { ol.xml.pushSerializeAndPop({node: node, srsName: srsName, curve: curve}, ol.format.GML.LINESTRINGORCURVEMEMBER_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('curveMember'), [lines[i]], + ol.format.GML.MULTICURVELINESTRING_NODE_FACTORY_, [lines[i]], objectStack); } }; @@ -1658,21 +1611,70 @@ ol.format.GML.CURVE_SERIALIZERS_ = { ol.format.GML.GEOMETRY_SERIALIZERS_ = { 'http://www.opengis.net/gml': { 'Curve': ol.xml.makeChildAppender(ol.format.GML.writeCurve_), - 'MultiCurve': ol.xml.makeChildAppender(ol.format.GML.writeMultiCurve_), + 'MultiCurve': ol.xml.makeChildAppender( + ol.format.GML.writeMultiCurveOrLineString_), 'Point': ol.xml.makeChildAppender(ol.format.GML.writePoint_), 'MultiPoint': ol.xml.makeChildAppender(ol.format.GML.writeMultiPoint_), 'LineString': ol.xml.makeChildAppender(ol.format.GML.writeLineString_), 'MultiLineString': ol.xml.makeChildAppender( - ol.format.GML.writeMultiLineString_), + ol.format.GML.writeMultiCurveOrLineString_), 'LinearRing': ol.xml.makeChildAppender(ol.format.GML.writeLinearRing_), 'Polygon': ol.xml.makeChildAppender(ol.format.GML.writePolygon_), - 'MultiPolygon': ol.xml.makeChildAppender(ol.format.GML.writeMultiPolygon_), + 'MultiPolygon': ol.xml.makeChildAppender( + ol.format.GML.writeMultiSurfaceOrPolygon_), 'Surface': ol.xml.makeChildAppender(ol.format.GML.writeSurface_), - 'MultiSurface': ol.xml.makeChildAppender(ol.format.GML.writeMultiSurface_) + 'MultiSurface': ol.xml.makeChildAppender( + ol.format.GML.writeMultiSurfaceOrPolygon_) } }; +/** + * @const + * @param {*} value Value. + * @param {Array.<*>} objectStack Object stack. + * @param {string=} opt_nodeName Node name. + * @return {Node|undefined} Node. + * @private + */ +ol.format.GML.MULTICURVELINESTRING_NODE_FACTORY_ = function(value, objectStack, + opt_nodeName) { + var parentNode = objectStack[objectStack.length - 1].node; + goog.asserts.assert(ol.xml.isNode(parentNode)); + var nodeName; + if (parentNode.nodeName === 'MultiLineString') { + nodeName = 'lineStringMember'; + } else { + nodeName = 'curveMember'; + } + return ol.xml.createElementNS('http://www.opengis.net/gml', + nodeName); +}; + + +/** + * @const + * @param {*} value Value. + * @param {Array.<*>} objectStack Object stack. + * @param {string=} opt_nodeName Node name. + * @return {Node|undefined} Node. + * @private + */ +ol.format.GML.MULTISURFACEORPOLYGON_NODE_FACTORY_ = function(value, objectStack, + opt_nodeName) { + var parentNode = objectStack[objectStack.length - 1].node; + goog.asserts.assert(ol.xml.isNode(parentNode)); + var nodeName; + if (parentNode.nodeName === 'MultiPolygon') { + nodeName = 'polygonMember'; + } else { + nodeName = 'surfaceMember'; + } + return ol.xml.createElementNS('http://www.opengis.net/gml', + nodeName); +}; + + /** * @const * @param {*} value Value. From 64060795ce6503b8f24aa61e65331865000b280a Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Tue, 4 Mar 2014 16:14:31 +0100 Subject: [PATCH 17/24] Use const for schema location --- src/ol/format/gmlformat.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index 486cfaebc5..e3ebc9c84a 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -22,6 +22,16 @@ goog.require('ol.proj'); goog.require('ol.xml'); +/** + * @const + * @type {string} + * @private + */ +ol.format.GML.schemaLocation_ = 'http://www.opengis.net/gml ' + + 'http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/' + + '1.0.0/gmlsf.xsd'; + + /** * @constructor @@ -85,9 +95,7 @@ ol.format.GML = function(opt_options) { * @type {string} */ this.schemaLocation_ = goog.isDef(options.schemaLocation) ? - options.schemaLocation : ('http://www.opengis.net/gml ' + - 'http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/' + - '1.0.0/gmlsf.xsd'); + options.schemaLocation : ol.format.GML.schemaLocation_; goog.base(this); }; From 16a09930fb39d81de777a4ecfd9364933d83fec1 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Tue, 4 Mar 2014 16:20:23 +0100 Subject: [PATCH 18/24] Use ol.format.XSD.readNonNegativeIntegerString instead of parseInt --- src/ol/format/gmlformat.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index e3ebc9c84a..ab422f6352 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -727,11 +727,13 @@ ol.format.GML.readFlatPosList_ = function(node, objectStack) { // The "dimension" attribute is from the GML 3.0.1 spec. var dim = 2; if (!goog.isNull(node.getAttribute('srsDimension'))) { - dim = parseInt(node.getAttribute('srsDimension'), 10); + dim = ol.format.XSD.readNonNegativeIntegerString( + node.getAttribute('srsDimension')); } else if (!goog.isNull(node.getAttribute('dimension'))) { - dim = parseInt(node.getAttribute('dimension'), 10); + dim = ol.format.XSD.readNonNegativeIntegerString( + node.getAttribute('dimension')); } else if (!goog.isNull(containerDimension)) { - dim = parseInt(containerDimension, 10); + dim = ol.format.XSD.readNonNegativeIntegerString(containerDimension); } var x, y, z; var flatCoordinates = []; From d7f40c11e88301f183b8e2bfe36899ec91bc9938 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Wed, 5 Mar 2014 12:51:01 +0100 Subject: [PATCH 19/24] Do not use ol.xml.pushSerializeAndPop for single items --- src/ol/format/gmlformat.js | 347 ++++++++------------ test/spec/ol/format/gml/topp-states-gml.xml | 64 ++-- test/spec/ol/format/gmlformat.test.js | 71 ++-- 3 files changed, 202 insertions(+), 280 deletions(-) diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index ab422f6352..e1224a83cf 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -22,16 +22,6 @@ goog.require('ol.proj'); goog.require('ol.xml'); -/** - * @const - * @type {string} - * @private - */ -ol.format.GML.schemaLocation_ = 'http://www.opengis.net/gml ' + - 'http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/' + - '1.0.0/gmlsf.xsd'; - - /** * @constructor @@ -102,6 +92,16 @@ ol.format.GML = function(opt_options) { goog.inherits(ol.format.GML, ol.format.XMLFeature); +/** + * @const + * @type {string} + * @private + */ +ol.format.GML.schemaLocation_ = 'http://www.opengis.net/gml ' + + 'http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/' + + '1.0.0/gmlsf.xsd'; + + /** * @param {Node} node Node. * @param {Array.<*>} objectStack Object stack. @@ -1060,9 +1060,26 @@ ol.format.GML.writePos_ = function(node, value, objectStack) { }; +/** + * @param {Array.} point Point geometry. + * @param {string=} opt_srsName Optional srsName + * @return {string} + * @private + */ +ol.format.GML.getCoords_ = function(point, opt_srsName) { + var axisOrientation = 'enu'; + if (goog.isDefAndNotNull(opt_srsName)) { + axisOrientation = ol.proj.get(opt_srsName).getAxisOrientation(); + } + return ((axisOrientation.substr(0, 2) === 'en') ? + point[0] + ' ' + point[1] : + point[1] + ' ' + point[0]); +}; + + /** * @param {Node} node Node. - * @param {ol.geom.Point} value Point geometry. + * @param {ol.geom.LineString|ol.geom.LinearRing} value Geometry. * @param {Array.<*>} objectStack Node stack. * @private */ @@ -1070,10 +1087,6 @@ ol.format.GML.writePosList_ = function(node, value, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var srsName = goog.object.get(context, 'srsName'); - var axisOrientation = 'enu'; - if (goog.isDefAndNotNull(srsName)) { - axisOrientation = ol.proj.get(srsName).getAxisOrientation(); - } // only 2d for simple features profile var points = value.getCoordinates(); var len = points.length; @@ -1081,50 +1094,12 @@ ol.format.GML.writePosList_ = function(node, value, objectStack) { var point; for (var i = 0; i < len; ++i) { point = points[i]; - if (axisOrientation.substr(0, 2) === 'en') { - parts[i] = point[0] + ' ' + point[1]; - } else { - parts[i] = point[1] + ' ' + point[0]; - } + parts[i] = ol.format.GML.getCoords_(point, srsName); } ol.format.XSD.writeStringTextNode(node, parts.join(' ')); }; -/** - * @const - * @param {*} value Value. - * @param {Array.<*>} objectStack Object stack. - * @param {string=} opt_nodeName Node name. - * @return {Node|undefined} Node. - * @private - */ -ol.format.GML.POS_NODE_FACTORY_ = ol.xml.makeSimpleNodeFactory('pos'); - - -/** - * @const - * @param {*} value Value. - * @param {Array.<*>} objectStack Object stack. - * @param {string=} opt_nodeName Node name. - * @return {Node|undefined} Node. - * @private - */ -ol.format.GML.POSLIST_NODE_FACTORY_ = ol.xml.makeSimpleNodeFactory('posList'); - - -/** - * @type {Object.>} - * @private - */ -ol.format.GML.FLAT_COORDINATES_SERIALIZERS_ = { - 'http://www.opengis.net/gml': { - 'pos': ol.xml.makeChildAppender(ol.format.GML.writePos_), - 'posList': ol.xml.makeChildAppender(ol.format.GML.writePosList_) - } -}; - - /** * @param {Node} node Node. * @param {ol.geom.Point} geometry Point geometry. @@ -1135,33 +1110,12 @@ ol.format.GML.writePoint_ = function(node, geometry, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var srsName = goog.object.get(context, 'srsName'); - var writeSrsName = goog.object.get(context, 'writeSrsName'); - if (goog.isDefAndNotNull(srsName) && writeSrsName !== false) { + if (goog.isDefAndNotNull(srsName)) { node.setAttribute('srsName', srsName); } - ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, - ol.format.GML.FLAT_COORDINATES_SERIALIZERS_, - ol.format.GML.POS_NODE_FACTORY_, [geometry], []); -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.LineString} geometry LineString geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML.writeLineString_ = function(node, geometry, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context)); - var srsName = goog.object.get(context, 'srsName'); - var writeSrsName = goog.object.get(context, 'writeSrsName'); - if (goog.isDefAndNotNull(srsName) && writeSrsName !== false) { - node.setAttribute('srsName', srsName); - } - ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, - ol.format.GML.FLAT_COORDINATES_SERIALIZERS_, - ol.format.GML.POSLIST_NODE_FACTORY_, [geometry], []); + var pos = ol.xml.createElementNS(node.namespaceURI, 'pos'); + node.appendChild(pos); + ol.format.GML.writePos_(pos, geometry, objectStack); }; @@ -1175,13 +1129,32 @@ ol.format.GML.writeLinearRing_ = function(node, geometry, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var srsName = goog.object.get(context, 'srsName'); - var writeSrsName = goog.object.get(context, 'writeSrsName'); - if (writeSrsName !== false && goog.isDefAndNotNull(srsName)) { + if (goog.isDefAndNotNull(srsName)) { node.setAttribute('srsName', srsName); } - ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, - ol.format.GML.FLAT_COORDINATES_SERIALIZERS_, - ol.format.GML.POSLIST_NODE_FACTORY_, [geometry], []); + var posList = ol.xml.createElementNS(node.namespaceURI, 'posList'); + node.appendChild(posList); + ol.format.GML.writePosList_(posList, geometry, objectStack); +}; + + +/** + * @param {*} value Value. + * @param {Array.<*>} objectStack Object stack. + * @param {string=} opt_nodeName Node name. + * @return {Node} Node. + * @private + */ +ol.format.GML.RING_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) { + var context = objectStack[objectStack.length - 1]; + var parentNode = context.node; + goog.asserts.assert(goog.isObject(context)); + var exteriorWritten = goog.object.get(context, 'exteriorWritten'); + if (!goog.isDef(exteriorWritten)) { + goog.object.set(context, 'exteriorWritten', true); + } + return ol.xml.createElementNS(parentNode.namespaceURI, + goog.isDef(exteriorWritten) ? 'interior' : 'exterior'); }; @@ -1195,22 +1168,14 @@ ol.format.GML.writePolygon_ = function(node, geometry, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var srsName = goog.object.get(context, 'srsName'); - var writeSrsName = goog.object.get(context, 'writeSrsName'); - if (writeSrsName !== false && goog.isDefAndNotNull(srsName)) { + if (node.nodeName !== 'PolygonPatch' && goog.isDefAndNotNull(srsName)) { node.setAttribute('srsName', srsName); } var rings = geometry.getLinearRings(); - for (var i = 0, ii = rings.length; i < ii; ++i) { - if (i === 0) { - ol.xml.pushSerializeAndPop({node: node, srsName: srsName, - writeSrsName: false}, ol.format.GML.RING_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('exterior'), [rings[i]], objectStack); - } else { - ol.xml.pushSerializeAndPop({node: node, srsName: srsName, - writeSrsName: false}, ol.format.GML.RING_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('interior'), [rings[i]], objectStack); - } - } + ol.xml.pushSerializeAndPop( + {node: node, srsName: srsName}, + ol.format.GML.RING_SERIALIZERS_, ol.format.GML.RING_NODE_FACTORY_, + rings, objectStack); }; @@ -1224,14 +1189,12 @@ ol.format.GML.writeSurface_ = function(node, geometry, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var srsName = goog.object.get(context, 'srsName'); - var writeSrsName = goog.object.get(context, 'writeSrsName'); - if (goog.isDefAndNotNull(srsName) && writeSrsName !== false) { + if (goog.isDefAndNotNull(srsName)) { node.setAttribute('srsName', srsName); } - ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, - ol.format.GML.PATCH_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('patches'), [geometry], - objectStack); + var patches = ol.xml.createElementNS(node.namespaceURI, 'patches'); + node.appendChild(patches); + ol.format.GML.writeSurfacePatches_(patches, geometry, objectStack); }; @@ -1245,14 +1208,31 @@ ol.format.GML.writeCurve_ = function(node, geometry, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var srsName = goog.object.get(context, 'srsName'); - var writeSrsName = goog.object.get(context, 'writeSrsName'); - if (goog.isDefAndNotNull(srsName) && writeSrsName !== false) { + if (goog.isDefAndNotNull(srsName)) { node.setAttribute('srsName', srsName); } - ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, - ol.format.GML.SEGMENT_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('segments'), [geometry], - objectStack); + var segments = ol.xml.createElementNS(node.namespaceURI, 'segments'); + node.appendChild(segments); + ol.format.GML.writeCurveSegments_(segments, geometry, objectStack); +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.LineString} geometry LineString geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML.writeLineString_ = function(node, geometry, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context)); + var srsName = goog.object.get(context, 'srsName'); + if (node.nodeName !== 'LineStringSegment' && goog.isDefAndNotNull(srsName)) { + node.setAttribute('srsName', srsName); + } + var posList = ol.xml.createElementNS(node.namespaceURI, 'posList'); + node.appendChild(posList); + ol.format.GML.writePosList_(posList, geometry, objectStack); }; @@ -1272,12 +1252,10 @@ ol.format.GML.writeMultiSurfaceOrPolygon_ = function(node, geometry, node.setAttribute('srsName', srsName); } var polygons = geometry.getPolygons(); - for (var i = 0, ii = polygons.length; i < ii; ++i) { - ol.xml.pushSerializeAndPop({node: node, srsName: srsName, surface: surface}, - ol.format.GML.SURFACEORPOLYGONMEMBER_SERIALIZERS_, - ol.format.GML.MULTISURFACEORPOLYGON_NODE_FACTORY_, [polygons[i]], - objectStack); - } + ol.xml.pushSerializeAndPop({node: node, srsName: srsName, surface: surface}, + ol.format.GML.SURFACEORPOLYGONMEMBER_SERIALIZERS_, + ol.format.GML.MULTISURFACEORPOLYGON_NODE_FACTORY_, polygons, + objectStack); }; @@ -1296,12 +1274,10 @@ ol.format.GML.writeMultiPoint_ = function(node, geometry, node.setAttribute('srsName', srsName); } var points = geometry.getPoints(); - for (var i = 0, ii = points.length; i < ii; ++i) { - ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, - ol.format.GML.POINTMEMBER_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('pointMember'), [points[i]], - objectStack); - } + ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, + ol.format.GML.POINTMEMBER_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('pointMember'), points, + objectStack); }; @@ -1321,12 +1297,10 @@ ol.format.GML.writeMultiCurveOrLineString_ = function(node, geometry, node.setAttribute('srsName', srsName); } var lines = geometry.getLineStrings(); - for (var i = 0, ii = lines.length; i < ii; ++i) { - ol.xml.pushSerializeAndPop({node: node, srsName: srsName, curve: curve}, - ol.format.GML.LINESTRINGORCURVEMEMBER_SERIALIZERS_, - ol.format.GML.MULTICURVELINESTRING_NODE_FACTORY_, [lines[i]], - objectStack); - } + ol.xml.pushSerializeAndPop({node: node, srsName: srsName, curve: curve}, + ol.format.GML.LINESTRINGORCURVEMEMBER_SERIALIZERS_, + ol.format.GML.MULTICURVELINESTRING_NODE_FACTORY_, lines, + objectStack); }; @@ -1337,14 +1311,9 @@ ol.format.GML.writeMultiCurveOrLineString_ = function(node, geometry, * @private */ ol.format.GML.writeRing_ = function(node, ring, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context)); - var srsName = goog.object.get(context, 'srsName'); - var writeSrsName = goog.object.get(context, 'writeSrsName'); - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - ({node: node, srsName: srsName, writeSrsName: writeSrsName}), - ol.format.GML.GEOMETRY_SERIALIZERS_, - ol.format.GML.GEOMETRY_NODE_FACTORY_, [ring], []); + var linearRing = ol.xml.createElementNS(node.namespaceURI, 'LinearRing'); + node.appendChild(linearRing); + ol.format.GML.writeLinearRing_(linearRing, ring, objectStack); }; @@ -1359,11 +1328,15 @@ ol.format.GML.writeSurfaceOrPolygonMember_ = function(node, polygon, var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var surface = goog.object.get(context, 'surface'); - var srsName = goog.object.get(context, 'srsName'); - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - ({node: node, srsName: srsName, writeSrsName: false, surface: surface}), - ol.format.GML.GEOMETRY_SERIALIZERS_, - ol.format.GML.GEOMETRY_NODE_FACTORY_, [polygon], []); + var child = ol.format.GML.GEOMETRY_NODE_FACTORY_(polygon, objectStack); + if (goog.isDef(child)) { + node.appendChild(child); + if (surface === true) { + ol.format.GML.writeSurface_(child, polygon, objectStack); + } else { + ol.format.GML.writePolygon_(child, polygon, objectStack); + } + } }; @@ -1374,13 +1347,9 @@ ol.format.GML.writeSurfaceOrPolygonMember_ = function(node, polygon, * @private */ ol.format.GML.writePointMember_ = function(node, point, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context)); - var srsName = goog.object.get(context, 'srsName'); - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - ({node: node, srsName: srsName, writeSrsName: false}), - ol.format.GML.GEOMETRY_SERIALIZERS_, - ol.format.GML.GEOMETRY_NODE_FACTORY_, [point], []); + var child = ol.xml.createElementNS(node.namespaceURI, 'Point'); + node.appendChild(child); + ol.format.GML.writePoint_(child, point, objectStack); }; @@ -1395,11 +1364,15 @@ ol.format.GML.writeLineStringOrCurveMember_ = function(node, line, var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var curve = goog.object.get(context, 'curve'); - var srsName = goog.object.get(context, 'srsName'); - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - ({node: node, srsName: srsName, writeSrsName: false, curve: curve}), - ol.format.GML.GEOMETRY_SERIALIZERS_, - ol.format.GML.GEOMETRY_NODE_FACTORY_, [line], []); + var child = ol.format.GML.GEOMETRY_NODE_FACTORY_(line, objectStack); + if (goog.isDef(child)) { + node.appendChild(child); + if (curve === true) { + ol.format.GML.writeCurve_(child, line, objectStack); + } else { + ol.format.GML.writeLineString_(child, line, objectStack); + } + } }; @@ -1410,13 +1383,9 @@ ol.format.GML.writeLineStringOrCurveMember_ = function(node, line, * @private */ ol.format.GML.writeSurfacePatches_ = function(node, polygon, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context)); - var srsName = goog.object.get(context, 'srsName'); - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - ({node: node, srsName: srsName, writeSrsName: false}), - ol.format.GML.SURFACE_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('PolygonPatch'), [polygon], []); + var child = ol.xml.createElementNS(node.namespaceURI, 'PolygonPatch'); + node.appendChild(child); + ol.format.GML.writePolygon_(child, polygon, objectStack); }; @@ -1427,13 +1396,9 @@ ol.format.GML.writeSurfacePatches_ = function(node, polygon, objectStack) { * @private */ ol.format.GML.writeCurveSegments_ = function(node, line, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context)); - var srsName = goog.object.get(context, 'srsName'); - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - ({node: node, srsName: srsName, writeSrsName: false}), - ol.format.GML.CURVE_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('LineStringSegment'), [line], []); + var child = ol.xml.createElementNS(node.namespaceURI, 'LineStringSegment'); + node.appendChild(child); + ol.format.GML.writeLineString_(child, line, objectStack); }; @@ -1450,7 +1415,7 @@ ol.format.GML.writeGeometry_ = function(node, geometry, objectStack) { goog.object.set(item, 'node', node); ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (item), ol.format.GML.GEOMETRY_SERIALIZERS_, - ol.format.GML.GEOMETRY_NODE_FACTORY_, [geometry], []); + ol.format.GML.GEOMETRY_NODE_FACTORY_, [geometry], objectStack); }; @@ -1514,7 +1479,8 @@ ol.format.GML.writeFeatureMembers_ = function(node, features, objectStack) { ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (item), serializers, - ol.xml.makeSimpleNodeFactory(featureType, featureNS), features, []); + ol.xml.makeSimpleNodeFactory(featureType, featureNS), features, + objectStack); }; @@ -1557,28 +1523,6 @@ ol.format.GML.LINESTRINGORCURVEMEMBER_SERIALIZERS_ = { }; -/** - * @type {Object.>} - * @private - */ -ol.format.GML.PATCH_SERIALIZERS_ = { - 'http://www.opengis.net/gml': { - 'patches': ol.xml.makeChildAppender(ol.format.GML.writeSurfacePatches_) - } -}; - - -/** - * @type {Object.>} - * @private - */ -ol.format.GML.SEGMENT_SERIALIZERS_ = { - 'http://www.opengis.net/gml': { - 'segments': ol.xml.makeChildAppender(ol.format.GML.writeCurveSegments_) - } -}; - - /** * @type {Object.>} * @private @@ -1591,29 +1535,6 @@ ol.format.GML.RING_SERIALIZERS_ = { }; -/** - * @type {Object.>} - * @private - */ -ol.format.GML.SURFACE_SERIALIZERS_ = { - 'http://www.opengis.net/gml': { - 'PolygonPatch': ol.xml.makeChildAppender(ol.format.GML.writePolygon_) - } -}; - - -/** - * @type {Object.>} - * @private - */ -ol.format.GML.CURVE_SERIALIZERS_ = { - 'http://www.opengis.net/gml': { - 'LineStringSegment': ol.xml.makeChildAppender( - ol.format.GML.writeLineString_) - } -}; - - /** * @type {Object.>} * @private diff --git a/test/spec/ol/format/gml/topp-states-gml.xml b/test/spec/ol/format/gml/topp-states-gml.xml index 33eb7c684e..2090909512 100644 --- a/test/spec/ol/format/gml/topp-states-gml.xml +++ b/test/spec/ol/format/gml/topp-states-gml.xml @@ -7,9 +7,9 @@ - + - + 37.5101 -88.0711 37.5831 -88.1341 37.6281 -88.1571 37.6601 -88.1591 37.7001 -88.1331 37.7351 -88.0721 37.8051 -88.0351 37.8171 -88.0861 37.8311 -88.0891 37.8271 -88.0421 @@ -138,9 +138,9 @@ - + - + 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 @@ -179,9 +179,9 @@ - + - + 38.5571 -75.7071 38.4631 -75.6991 38.4551 -75.3501 38.4501 -75.0931 38.4491 -75.0681 38.4491 -75.0451 38.7991 -75.0831 38.8081 -75.1901 38.9451 -75.3071 39.0121 -75.3241 @@ -227,9 +227,9 @@ - + - + 38.4801 -79.2311 38.6581 -79.1271 38.6631 -79.1211 38.6591 -79.0881 38.7071 -79.0871 38.7611 -79.0561 38.7901 -79.0551 38.7991 -79.0331 38.8461 -78.9871 38.7631 -78.8661 @@ -378,9 +378,9 @@ - + - + 38.6491 -75.7111 38.8301 -75.7241 39.1411 -75.7521 39.2471 -75.7611 39.2951 -75.7641 39.3831 -75.7721 39.7231 -75.7911 39.7221 -76.1391 39.7211 -76.2331 39.7201 -76.5701 @@ -456,9 +456,9 @@ - + - + 38.9071 -76.2931 38.9491 -76.2731 38.9231 -76.2461 38.9781 -76.2481 39.0401 -76.2991 38.9581 -76.3561 38.8541 -76.3751 38.8751 -76.3291 38.9241 -76.3421 38.9121 -76.3221 @@ -469,9 +469,9 @@ - + - + 38.4491 -75.0681 38.3221 -75.0871 38.4491 -75.0451 38.4491 -75.0681 @@ -479,9 +479,9 @@ - + - + 38.0271 -75.2701 38.0281 -75.2421 38.1241 -75.1731 38.3201 -75.0941 38.2041 -75.1641 38.0941 -75.2091 38.0371 -75.2441 38.0271 -75.2701 @@ -519,9 +519,9 @@ - + - + 37.6411 -102.0431 37.7341 -102.0431 38.2531 -102.0451 38.2631 -102.0451 38.6151 -102.0471 38.6921 -102.0471 39.0361 -102.0481 39.1261 -102.0471 39.5621 -102.0481 39.5681 -102.0481 @@ -573,9 +573,9 @@ - + - + 36.6551 -86.5101 36.6501 -86.4151 36.6431 -86.1991 36.6331 -85.9801 36.6261 -85.7851 36.6181 -85.4371 36.6261 -85.3001 36.6251 -85.2721 36.6201 -84.9981 36.6051 -84.7911 @@ -681,9 +681,9 @@ - + - + 36.4981 -89.5331 36.4981 -89.4751 36.5041 -89.4811 36.5251 -89.4711 36.5471 -89.4811 36.5591 -89.4931 36.5641 -89.5301 36.5571 -89.5561 36.5411 -89.5681 36.5181 -89.5661 @@ -722,9 +722,9 @@ - + - + 37.0011 -95.0711 37.0001 -95.0321 36.9961 -94.6201 37.0601 -94.6201 37.3271 -94.6181 37.3601 -94.6181 37.6501 -94.6181 37.6791 -94.6191 38.0301 -94.6161 38.0551 -94.6171 @@ -795,9 +795,9 @@ - + - + 36.5461 -79.1441 36.5431 -78.7961 36.5461 -78.7371 36.5411 -78.4581 36.5451 -78.3211 36.5521 -78.0511 36.5521 -77.8981 36.5531 -77.7631 36.5531 -77.3201 36.5561 -77.1771 @@ -907,9 +907,9 @@ - + - + 38.0271 -75.2701 37.9181 -75.3461 37.9001 -75.3781 37.9011 -75.3441 37.8751 -75.3861 37.8881 -75.3391 37.9621 -75.2981 38.0281 -75.2421 38.0271 -75.2701 @@ -918,9 +918,9 @@ - + - + 37.5521 -75.8671 37.5561 -75.9301 37.5211 -75.9541 37.4791 -75.9651 37.4841 -75.9341 37.3081 -76.0181 37.1261 -75.9701 37.1421 -75.9311 37.3671 -75.8971 37.4181 -75.8261 @@ -965,9 +965,9 @@ - + - + 36.9531 -89.1041 36.9771 -89.1071 36.9881 -89.1291 36.9861 -89.1931 37.0281 -89.2101 37.0411 -89.2371 37.0871 -89.2641 37.0911 -89.2841 37.0851 -89.3031 37.0601 -89.3091 diff --git a/test/spec/ol/format/gmlformat.test.js b/test/spec/ol/format/gmlformat.test.js index 93a075b19b..473fbcc9a6 100644 --- a/test/spec/ol/format/gmlformat.test.js +++ b/test/spec/ol/format/gmlformat.test.js @@ -88,9 +88,10 @@ describe('ol.format.GML', function() { '' + ' ' + - ' ' + + ' ' + ' ' + - ' ' + + ' ' + ' 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 ' + @@ -153,17 +154,17 @@ describe('ol.format.GML', function() { '' + ' ' + - ' ' + + ' ' + ' 1 2 3 2 3 4 1 2' + ' ' + ' ' + ' ' + - ' ' + + ' ' + ' 2 3 2 5 4 5 2 3' + ' ' + ' ' + ' ' + - ' ' + + ' ' + ' 3 4 3 6 5 6 3 4' + ' ' + ' ' + @@ -188,17 +189,17 @@ describe('ol.format.GML', function() { ' ' + ' ' + ' ' + - ' ' + + ' ' + ' 1 2 3 2 3 4 1 2' + ' ' + ' ' + ' ' + - ' ' + + ' ' + ' 2 3 2 5 4 5 2 3' + ' ' + ' ' + ' ' + - ' ' + + ' ' + ' 3 4 3 6 5 6 3 4' + ' ' + ' ' + @@ -261,17 +262,17 @@ describe('ol.format.GML', function() { '' + ' ' + - ' ' + + ' ' + ' 1 2' + ' ' + ' ' + ' ' + - ' ' + + ' ' + ' 2 3' + ' ' + ' ' + ' ' + - ' ' + + ' ' + ' 3 4' + ' ' + ' ' + @@ -313,12 +314,12 @@ describe('ol.format.GML', function() { '' + ' ' + - ' ' + + ' ' + ' 1 2 2 3' + ' ' + ' ' + ' ' + - ' ' + + ' ' + ' 3 4 4 5' + ' ' + ' ' + @@ -360,28 +361,28 @@ describe('ol.format.GML', function() { '' + ' ' + - ' ' + + ' ' + ' ' + - ' ' + + ' ' + ' 1 2 3 2 3 4 1 2' + ' ' + ' ' + ' ' + - ' ' + + ' ' + ' 2 3 2 5 4 5 2 3' + ' ' + ' ' + ' ' + - ' ' + + ' ' + ' 3 4 3 6 5 6 3 4' + ' ' + ' ' + ' ' + ' ' + ' ' + - ' ' + + ' ' + ' ' + - ' ' + + ' ' + ' 1 2 3 2 3 4 1 2' + ' ' + ' ' + @@ -450,12 +451,12 @@ describe('ol.format.GML', function() { '' + ' ' + - ' ' + + ' ' + ' 1 2 2 3' + ' ' + ' ' + ' ' + - ' ' + + ' ' + ' 3 4 4 5' + ' ' + ' ' + @@ -473,7 +474,7 @@ describe('ol.format.GML', function() { '' + ' ' + - ' ' + + ' ' + ' ' + ' ' + ' 1 2 2 3' + @@ -482,7 +483,7 @@ describe('ol.format.GML', function() { ' ' + ' ' + ' ' + - ' ' + + ' ' + ' ' + ' ' + ' 3 4 4 5' + @@ -509,28 +510,28 @@ describe('ol.format.GML', function() { '' + ' ' + - ' ' + + ' ' + ' ' + - ' ' + + ' ' + ' 1 2 3 2 3 4 1 2' + ' ' + ' ' + ' ' + - ' ' + + ' ' + ' 2 3 2 5 4 5 2 3' + ' ' + ' ' + ' ' + - ' ' + + ' ' + ' 3 4 3 6 5 6 3 4' + ' ' + ' ' + ' ' + ' ' + ' ' + - ' ' + + ' ' + ' ' + - ' ' + + ' ' + ' 1 2 3 2 3 4 1 2' + ' ' + ' ' + @@ -595,21 +596,21 @@ describe('ol.format.GML', function() { '' + ' ' + - ' ' + + ' ' + ' ' + ' ' + ' ' + - ' ' + + ' ' + ' 1 2 3 2 3 4 1 2' + ' ' + ' ' + ' ' + - ' ' + + ' ' + ' 2 3 2 5 4 5 2 3' + ' ' + ' ' + ' ' + - ' ' + + ' ' + ' 3 4 3 6 5 6 3 4' + ' ' + ' ' + @@ -618,11 +619,11 @@ describe('ol.format.GML', function() { ' ' + ' ' + ' ' + - ' ' + + ' ' + ' ' + ' ' + ' ' + - ' ' + + ' ' + ' 1 2 3 2 3 4 1 2' + ' ' + ' ' + From ba2d35fc572a7dc9ca6d09870786df5f6794ddd6 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Wed, 5 Mar 2014 13:05:31 +0100 Subject: [PATCH 20/24] Cache serializers on the context --- src/ol/format/gmlformat.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index e1224a83cf..54e50463fe 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -1434,25 +1434,31 @@ ol.format.GML.writeFeature_ = function(node, feature, objectStack) { goog.asserts.assert(goog.isObject(context)); var featureNS = goog.object.get(context, 'featureNS'); var geometryName = feature.getGeometryName(); - var serializers = {}; - serializers[featureNS] = {}; + if (!goog.isDef(context.serializers)) { + context.serializers = {}; + context.serializers[featureNS] = {}; + } var properties = feature.getProperties(); var keys = [], values = []; for (var key in properties) { keys.push(key); values.push(properties[key]); if (key == geometryName) { - serializers[featureNS][key] = ol.xml.makeChildAppender( - ol.format.GML.writeGeometry_); + if (!(key in context.serializers[featureNS])) { + context.serializers[featureNS][key] = ol.xml.makeChildAppender( + ol.format.GML.writeGeometry_); + } } else { - serializers[featureNS][key] = ol.xml.makeChildAppender( - ol.format.XSD.writeStringTextNode); + if (!(key in context.serializers[featureNS])) { + context.serializers[featureNS][key] = ol.xml.makeChildAppender( + ol.format.XSD.writeStringTextNode); + } } } var item = goog.object.clone(context); goog.object.set(item, 'node', node); ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - (item), serializers, + (item), context.serializers, ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, keys); From 718b54c29290f8256d596e3e61fdd99ebd85b7f6 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Wed, 5 Mar 2014 13:12:14 +0100 Subject: [PATCH 21/24] Do not clone the context for every feature --- src/ol/format/gmlformat.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index 54e50463fe..ac789a007e 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -1412,7 +1412,7 @@ ol.format.GML.writeGeometry_ = function(node, geometry, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var item = goog.object.clone(context); - goog.object.set(item, 'node', node); + item.node = node; ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (item), ol.format.GML.GEOMETRY_SERIALIZERS_, ol.format.GML.GEOMETRY_NODE_FACTORY_, [geometry], objectStack); @@ -1455,8 +1455,8 @@ ol.format.GML.writeFeature_ = function(node, feature, objectStack) { } } } - var item = goog.object.clone(context); - goog.object.set(item, 'node', node); + var item = objectStack[0]; + item.node = node; ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (item), context.serializers, ol.xml.OBJECT_PROPERTY_NODE_FACTORY, @@ -1481,7 +1481,7 @@ ol.format.GML.writeFeatureMembers_ = function(node, features, objectStack) { serializers[featureNS][featureType] = ol.xml.makeChildAppender( ol.format.GML.writeFeature_); var item = goog.object.clone(context); - goog.object.set(item, 'node', node); + item.node = node; ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (item), serializers, From e1b2af6cde2f06542e4e3f0223626c55403d871a Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Wed, 5 Mar 2014 14:08:46 +0100 Subject: [PATCH 22/24] Combine surface/polygon and linestring/curve writers --- src/ol/format/gmlformat.js | 95 ++++++++++++-------------------------- 1 file changed, 30 insertions(+), 65 deletions(-) diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index ac789a007e..857a013314 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -1164,37 +1164,24 @@ ol.format.GML.RING_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) { * @param {Array.<*>} objectStack Node stack. * @private */ -ol.format.GML.writePolygon_ = function(node, geometry, objectStack) { +ol.format.GML.writeSurfaceOrPolygon_ = function(node, geometry, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var srsName = goog.object.get(context, 'srsName'); if (node.nodeName !== 'PolygonPatch' && goog.isDefAndNotNull(srsName)) { node.setAttribute('srsName', srsName); } - var rings = geometry.getLinearRings(); - ol.xml.pushSerializeAndPop( - {node: node, srsName: srsName}, - ol.format.GML.RING_SERIALIZERS_, ol.format.GML.RING_NODE_FACTORY_, - rings, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.Polygon} geometry Polygon geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML.writeSurface_ = function(node, geometry, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context)); - var srsName = goog.object.get(context, 'srsName'); - if (goog.isDefAndNotNull(srsName)) { - node.setAttribute('srsName', srsName); + if (node.nodeName === 'Polygon' || node.nodeName === 'PolygonPatch') { + var rings = geometry.getLinearRings(); + ol.xml.pushSerializeAndPop( + {node: node, srsName: srsName}, + ol.format.GML.RING_SERIALIZERS_, ol.format.GML.RING_NODE_FACTORY_, + rings, objectStack); + } else if (node.nodeName === 'Surface') { + var patches = ol.xml.createElementNS(node.namespaceURI, 'patches'); + node.appendChild(patches); + ol.format.GML.writeSurfacePatches_(patches, geometry, objectStack); } - var patches = ol.xml.createElementNS(node.namespaceURI, 'patches'); - node.appendChild(patches); - ol.format.GML.writeSurfacePatches_(patches, geometry, objectStack); }; @@ -1204,35 +1191,22 @@ ol.format.GML.writeSurface_ = function(node, geometry, objectStack) { * @param {Array.<*>} objectStack Node stack. * @private */ -ol.format.GML.writeCurve_ = function(node, geometry, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context)); - var srsName = goog.object.get(context, 'srsName'); - if (goog.isDefAndNotNull(srsName)) { - node.setAttribute('srsName', srsName); - } - var segments = ol.xml.createElementNS(node.namespaceURI, 'segments'); - node.appendChild(segments); - ol.format.GML.writeCurveSegments_(segments, geometry, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.LineString} geometry LineString geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML.writeLineString_ = function(node, geometry, objectStack) { +ol.format.GML.writeCurveOrLineString_ = function(node, geometry, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); var srsName = goog.object.get(context, 'srsName'); if (node.nodeName !== 'LineStringSegment' && goog.isDefAndNotNull(srsName)) { node.setAttribute('srsName', srsName); } - var posList = ol.xml.createElementNS(node.namespaceURI, 'posList'); - node.appendChild(posList); - ol.format.GML.writePosList_(posList, geometry, objectStack); + if (node.nodeName === 'LineString' || node.nodeName === 'LineStringSegment') { + var posList = ol.xml.createElementNS(node.namespaceURI, 'posList'); + node.appendChild(posList); + ol.format.GML.writePosList_(posList, geometry, objectStack); + } else if (node.nodeName === 'Curve') { + var segments = ol.xml.createElementNS(node.namespaceURI, 'segments'); + node.appendChild(segments); + ol.format.GML.writeCurveSegments_(segments, geometry, objectStack); + } }; @@ -1327,15 +1301,10 @@ ol.format.GML.writeSurfaceOrPolygonMember_ = function(node, polygon, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); - var surface = goog.object.get(context, 'surface'); var child = ol.format.GML.GEOMETRY_NODE_FACTORY_(polygon, objectStack); if (goog.isDef(child)) { node.appendChild(child); - if (surface === true) { - ol.format.GML.writeSurface_(child, polygon, objectStack); - } else { - ol.format.GML.writePolygon_(child, polygon, objectStack); - } + ol.format.GML.writeSurfaceOrPolygon_(child, polygon, objectStack); } }; @@ -1363,15 +1332,10 @@ ol.format.GML.writeLineStringOrCurveMember_ = function(node, line, objectStack) { var context = objectStack[objectStack.length - 1]; goog.asserts.assert(goog.isObject(context)); - var curve = goog.object.get(context, 'curve'); var child = ol.format.GML.GEOMETRY_NODE_FACTORY_(line, objectStack); if (goog.isDef(child)) { node.appendChild(child); - if (curve === true) { - ol.format.GML.writeCurve_(child, line, objectStack); - } else { - ol.format.GML.writeLineString_(child, line, objectStack); - } + ol.format.GML.writeCurveOrLineString_(child, line, objectStack); } }; @@ -1385,7 +1349,7 @@ ol.format.GML.writeLineStringOrCurveMember_ = function(node, line, ol.format.GML.writeSurfacePatches_ = function(node, polygon, objectStack) { var child = ol.xml.createElementNS(node.namespaceURI, 'PolygonPatch'); node.appendChild(child); - ol.format.GML.writePolygon_(child, polygon, objectStack); + ol.format.GML.writeSurfaceOrPolygon_(child, polygon, objectStack); }; @@ -1398,7 +1362,7 @@ ol.format.GML.writeSurfacePatches_ = function(node, polygon, objectStack) { ol.format.GML.writeCurveSegments_ = function(node, line, objectStack) { var child = ol.xml.createElementNS(node.namespaceURI, 'LineStringSegment'); node.appendChild(child); - ol.format.GML.writeLineString_(child, line, objectStack); + ol.format.GML.writeCurveOrLineString_(child, line, objectStack); }; @@ -1547,19 +1511,20 @@ ol.format.GML.RING_SERIALIZERS_ = { */ ol.format.GML.GEOMETRY_SERIALIZERS_ = { 'http://www.opengis.net/gml': { - 'Curve': ol.xml.makeChildAppender(ol.format.GML.writeCurve_), + 'Curve': ol.xml.makeChildAppender(ol.format.GML.writeCurveOrLineString_), 'MultiCurve': ol.xml.makeChildAppender( ol.format.GML.writeMultiCurveOrLineString_), 'Point': ol.xml.makeChildAppender(ol.format.GML.writePoint_), 'MultiPoint': ol.xml.makeChildAppender(ol.format.GML.writeMultiPoint_), - 'LineString': ol.xml.makeChildAppender(ol.format.GML.writeLineString_), + 'LineString': ol.xml.makeChildAppender( + ol.format.GML.writeCurveOrLineString_), 'MultiLineString': ol.xml.makeChildAppender( ol.format.GML.writeMultiCurveOrLineString_), 'LinearRing': ol.xml.makeChildAppender(ol.format.GML.writeLinearRing_), - 'Polygon': ol.xml.makeChildAppender(ol.format.GML.writePolygon_), + 'Polygon': ol.xml.makeChildAppender(ol.format.GML.writeSurfaceOrPolygon_), 'MultiPolygon': ol.xml.makeChildAppender( ol.format.GML.writeMultiSurfaceOrPolygon_), - 'Surface': ol.xml.makeChildAppender(ol.format.GML.writeSurface_), + 'Surface': ol.xml.makeChildAppender(ol.format.GML.writeSurfaceOrPolygon_), 'MultiSurface': ol.xml.makeChildAppender( ol.format.GML.writeMultiSurfaceOrPolygon_) } From 75f139bb272469f719e18e5a282219c93425f6bf Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Wed, 5 Mar 2014 14:18:32 +0100 Subject: [PATCH 23/24] Use a single node factory for more multi geometries --- src/ol/format/gmlformat.js | 38 +++++++++++--------------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index 857a013314..618baf93b3 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -1228,7 +1228,7 @@ ol.format.GML.writeMultiSurfaceOrPolygon_ = function(node, geometry, var polygons = geometry.getPolygons(); ol.xml.pushSerializeAndPop({node: node, srsName: srsName, surface: surface}, ol.format.GML.SURFACEORPOLYGONMEMBER_SERIALIZERS_, - ol.format.GML.MULTISURFACEORPOLYGON_NODE_FACTORY_, polygons, + ol.format.GML.MULTIGEOMETRY_MEMBER_NODE_FACTORY_, polygons, objectStack); }; @@ -1273,7 +1273,7 @@ ol.format.GML.writeMultiCurveOrLineString_ = function(node, geometry, var lines = geometry.getLineStrings(); ol.xml.pushSerializeAndPop({node: node, srsName: srsName, curve: curve}, ol.format.GML.LINESTRINGORCURVEMEMBER_SERIALIZERS_, - ol.format.GML.MULTICURVELINESTRING_NODE_FACTORY_, lines, + ol.format.GML.MULTIGEOMETRY_MEMBER_NODE_FACTORY_, lines, objectStack); }; @@ -1533,24 +1533,14 @@ ol.format.GML.GEOMETRY_SERIALIZERS_ = { /** * @const - * @param {*} value Value. - * @param {Array.<*>} objectStack Object stack. - * @param {string=} opt_nodeName Node name. - * @return {Node|undefined} Node. + * @type {Object.} * @private */ -ol.format.GML.MULTICURVELINESTRING_NODE_FACTORY_ = function(value, objectStack, - opt_nodeName) { - var parentNode = objectStack[objectStack.length - 1].node; - goog.asserts.assert(ol.xml.isNode(parentNode)); - var nodeName; - if (parentNode.nodeName === 'MultiLineString') { - nodeName = 'lineStringMember'; - } else { - nodeName = 'curveMember'; - } - return ol.xml.createElementNS('http://www.opengis.net/gml', - nodeName); +ol.format.GML.MULTIGEOMETRY_TO_MEMBER_NODENAME_ = { + 'MultiLineString': 'lineStringMember', + 'MultiCurve': 'curveMember', + 'MultiPolygon': 'polygonMember', + 'MultiSurface': 'surfaceMember' }; @@ -1562,18 +1552,12 @@ ol.format.GML.MULTICURVELINESTRING_NODE_FACTORY_ = function(value, objectStack, * @return {Node|undefined} Node. * @private */ -ol.format.GML.MULTISURFACEORPOLYGON_NODE_FACTORY_ = function(value, objectStack, - opt_nodeName) { +ol.format.GML.MULTIGEOMETRY_MEMBER_NODE_FACTORY_ = function(value, + objectStack, opt_nodeName) { var parentNode = objectStack[objectStack.length - 1].node; goog.asserts.assert(ol.xml.isNode(parentNode)); - var nodeName; - if (parentNode.nodeName === 'MultiPolygon') { - nodeName = 'polygonMember'; - } else { - nodeName = 'surfaceMember'; - } return ol.xml.createElementNS('http://www.opengis.net/gml', - nodeName); + ol.format.GML.MULTIGEOMETRY_TO_MEMBER_NODENAME_[parentNode.nodeName]); }; From dd9311e79e5d037354097e26025425ff5b5c0247 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Wed, 5 Mar 2014 16:30:23 +0100 Subject: [PATCH 24/24] Revert to cloning the context object --- src/ol/format/gmlformat.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ol/format/gmlformat.js b/src/ol/format/gmlformat.js index 618baf93b3..0eaeabf093 100644 --- a/src/ol/format/gmlformat.js +++ b/src/ol/format/gmlformat.js @@ -1419,7 +1419,7 @@ ol.format.GML.writeFeature_ = function(node, feature, objectStack) { } } } - var item = objectStack[0]; + var item = goog.object.clone(context); item.node = node; ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (item), context.serializers, @@ -1619,7 +1619,6 @@ ol.format.GML.prototype.writeFeaturesNode = function(features) { ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance', 'xsi:schemaLocation', this.schemaLocation_); var context = { - node: node, srsName: this.srsName_, curve: this.curve_, surface: this.surface_,