Add write support for Transaction

This commit is contained in:
Bart van den Eijnden
2014-03-10 14:58:03 +01:00
parent 2ce92ac6a2
commit 4e5e75f525
5 changed files with 257 additions and 19 deletions

View File

@@ -346,6 +346,18 @@
* @property {ol.Extent|undefined} bbox Extent to use for the BBOX filter.
*/
/**
* @typedef {Object} olx.format.WFSWriteTransactionOptions
* @property {string} featureNS The namespace URI used for features.
* @property {string} featurePrefix The prefix for the feature namespace.
* @property {string} featureType The feature type name.
* @property {string|undefined} srsName SRS name. No srsName attribute will be
* set on geometries when this is not provided.
* @property {string|undefined} handle Handle.
* @property {Array.<Object>} nativeElements Native elements. Currently not
* supported.
*/
/**
* @typedef {Object} olx.interaction.DoubleClickZoomOptions
* @property {number|undefined} duration Animation duration in milliseconds. Default is `250`.

View File

@@ -1419,9 +1419,8 @@ ol.format.GML.writeGeometry = function(node, geometry, objectStack) {
* @param {Node} node Node.
* @param {ol.Feature} feature Feature.
* @param {Array.<*>} objectStack Node stack.
* @private
*/
ol.format.GML.writeFeature_ = function(node, feature, objectStack) {
ol.format.GML.writeFeature = function(node, feature, objectStack) {
var fid = feature.getId();
if (goog.isDef(fid)) {
node.setAttribute('fid', fid);
@@ -1437,17 +1436,20 @@ ol.format.GML.writeFeature_ = function(node, feature, objectStack) {
var properties = feature.getProperties();
var keys = [], values = [];
for (var key in properties) {
keys.push(key);
values.push(properties[key]);
if (key == geometryName) {
if (!(key in context.serializers[featureNS])) {
context.serializers[featureNS][key] = ol.xml.makeChildAppender(
ol.format.GML.writeGeometry);
}
} else {
if (!(key in context.serializers[featureNS])) {
context.serializers[featureNS][key] = ol.xml.makeChildAppender(
ol.format.XSD.writeStringTextNode);
var value = properties[key];
if (!goog.isNull(value)) {
keys.push(key);
values.push(value);
if (key == geometryName) {
if (!(key in context.serializers[featureNS])) {
context.serializers[featureNS][key] = ol.xml.makeChildAppender(
ol.format.GML.writeGeometry);
}
} else {
if (!(key in context.serializers[featureNS])) {
context.serializers[featureNS][key] = ol.xml.makeChildAppender(
ol.format.XSD.writeStringTextNode);
}
}
}
}
@@ -1455,7 +1457,7 @@ ol.format.GML.writeFeature_ = function(node, feature, objectStack) {
item.node = node;
ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */
(item), context.serializers,
ol.xml.OBJECT_PROPERTY_NODE_FACTORY,
ol.xml.makeSimpleNodeFactory(undefined, featureNS),
values,
objectStack, keys);
};
@@ -1475,7 +1477,7 @@ ol.format.GML.writeFeatureMembers_ = function(node, features, objectStack) {
var serializers = {};
serializers[featureNS] = {};
serializers[featureNS][featureType] = ol.xml.makeChildAppender(
ol.format.GML.writeFeature_);
ol.format.GML.writeFeature);
var item = goog.object.clone(context);
item.node = node;
ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */

View File

@@ -6,6 +6,7 @@ goog.require('goog.object');
goog.require('ol.format.GML');
goog.require('ol.format.XMLFeature');
goog.require('ol.format.XSD');
goog.require('ol.geom.Geometry');
goog.require('ol.xml');
@@ -287,6 +288,124 @@ ol.format.WFS.QUERY_SERIALIZERS_ = {
};
/**
* @param {Node} node Node.
* @param {ol.Feature} feature Feature.
* @param {Array.<*>} objectStack Node stack.
* @private
*/
ol.format.WFS.writeFeature_ = function(node, feature, 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');
var child = ol.xml.createElementNS(featureNS, featureType);
node.appendChild(child);
ol.format.GML.writeFeature(child, feature, objectStack);
};
/**
* @param {Node} node Node.
* @param {number|string} fid Feature identifier.
* @param {Array.<*>} objectStack Node stack.
* @private
*/
ol.format.WFS.writeOgcFidFilter_ = function(node, fid, objectStack) {
var filter = ol.xml.createElementNS('http://www.opengis.net/ogc', 'Filter');
var child = ol.xml.createElementNS('http://www.opengis.net/ogc', 'FeatureId');
filter.appendChild(child);
child.setAttribute('fid', fid);
node.appendChild(filter);
};
/**
* @param {Node} node Node.
* @param {ol.Feature} feature Feature.
* @param {Array.<*>} objectStack Node stack.
* @private
*/
ol.format.WFS.writeDelete_ = function(node, feature, objectStack) {
var context = objectStack[objectStack.length - 1];
goog.asserts.assert(goog.isObject(context));
var featureType = goog.object.get(context, 'featureType');
var featurePrefix = goog.object.get(context, 'featurePrefix');
node.setAttribute('typeName', featurePrefix + ':' + featureType);
var fid = feature.getId();
if (goog.isDef(fid)) {
ol.format.WFS.writeOgcFidFilter_(node, fid, objectStack);
}
};
/**
* @param {Node} node Node.
* @param {ol.Feature} feature Feature.
* @param {Array.<*>} objectStack Node stack.
* @private
*/
ol.format.WFS.writeUpdate_ = function(node, feature, objectStack) {
var context = objectStack[objectStack.length - 1];
goog.asserts.assert(goog.isObject(context));
var featureType = goog.object.get(context, 'featureType');
var featurePrefix = goog.object.get(context, 'featurePrefix');
node.setAttribute('typeName', featurePrefix + ':' + featureType);
var fid = feature.getId();
if (goog.isDef(fid)) {
var keys = feature.getKeys();
var values = [];
for (var i = 0, ii = keys.length; i < ii; i++) {
var value = feature.get(keys[i]);
if (goog.isDef(value)) {
values.push({name: keys[i], value: value});
}
}
ol.xml.pushSerializeAndPop({node: node},
ol.format.WFS.TRANSACTION_SERIALIZERS_,
ol.xml.makeSimpleNodeFactory('Property'), values,
objectStack);
ol.format.WFS.writeOgcFidFilter_(node, fid, objectStack);
}
};
/**
* @param {Node} node Node.
* @param {Object} pair Property name and value.
* @param {Array.<*>} objectStack Node stack.
* @private
*/
ol.format.WFS.writeProperty_ = function(node, pair, objectStack) {
var name = ol.xml.createElementNS('http://www.opengis.net/wfs', 'Name');
node.appendChild(name);
ol.format.XSD.writeStringTextNode(name, pair.name);
if (goog.isDefAndNotNull(pair.value)) {
var value = ol.xml.createElementNS('http://www.opengis.net/wfs', 'Value');
node.appendChild(value);
if (pair.value instanceof ol.geom.Geometry) {
ol.format.GML.writeGeometry(value, pair.value, objectStack);
} else {
ol.format.XSD.writeStringTextNode(value, pair.value);
}
}
};
/**
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.WFS.TRANSACTION_SERIALIZERS_ = {
'http://www.opengis.net/wfs': {
'Insert': ol.xml.makeChildAppender(ol.format.WFS.writeFeature_),
'Update': ol.xml.makeChildAppender(ol.format.WFS.writeUpdate_),
'Delete': ol.xml.makeChildAppender(ol.format.WFS.writeDelete_),
'Property': ol.xml.makeChildAppender(ol.format.WFS.writeProperty_)
}
};
/**
* @param {Node} node Node.
* @param {string} featureType Feature type.
@@ -428,3 +547,48 @@ ol.format.WFS.prototype.writeGetFeature = function(options) {
ol.format.WFS.writeGetFeature_(node, options.featureTypes, [context]);
return node;
};
/**
* @param {Array.<ol.Feature>} inserts The features to insert.
* @param {Array.<ol.Feature>} updates The features to update.
* @param {Array.<ol.Feature>} deletes The features to delete.
* @param {olx.format.WFSWriteTransactionOptions} options Write options.
* @return {ArrayBuffer|Node|Object|string} Result.
*/
ol.format.WFS.prototype.writeTransaction = function(inserts, updates, deletes,
options) {
var node = ol.xml.createElementNS('http://www.opengis.net/wfs',
'Transaction');
node.setAttribute('service', 'WFS');
node.setAttribute('version', '1.1.0');
if (goog.isDef(options)) {
if (goog.isDef(options.handle)) {
node.setAttribute('handle', options.handle);
}
}
ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance',
'xsi:schemaLocation', this.schemaLocation_);
if (goog.isDefAndNotNull(inserts)) {
ol.xml.pushSerializeAndPop({node: node, featureNS: options.featureNS,
featureType: options.featureType},
ol.format.WFS.TRANSACTION_SERIALIZERS_,
ol.xml.makeSimpleNodeFactory('Insert'), inserts,
[]);
}
if (goog.isDefAndNotNull(updates)) {
ol.xml.pushSerializeAndPop({node: node, featureNS: options.featureNS,
featureType: options.featureType, featurePrefix: options.featurePrefix},
ol.format.WFS.TRANSACTION_SERIALIZERS_,
ol.xml.makeSimpleNodeFactory('Update'), updates,
[]);
}
if (goog.isDefAndNotNull(deletes)) {
ol.xml.pushSerializeAndPop({node: node, featureNS: options.featureNS,
featureType: options.featureType, featurePrefix: options.featurePrefix},
ol.format.WFS.TRANSACTION_SERIALIZERS_,
ol.xml.makeSimpleNodeFactory('Delete'), deletes,
[]);
}
return node;
};

View File

@@ -1,11 +1,11 @@
<wfs:Transaction xmlns:wfs="http://www.opengis.net/wfs" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" service="WFS" version="1.0.0" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd">
<wfs:Transaction xmlns:wfs="http://www.opengis.net/wfs" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" service="WFS" version="1.1.0" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<wfs:Insert>
<feature:states xmlns:feature="http://www.openplans.org/topp">
<feature:the_geom>
<gml:MultiPoint xmlns:gml="http://www.opengis.net/gml">
<gml:pointMember>
<gml:Point>
<gml:coordinates decimal="." cs="," ts=" ">1,2</gml:coordinates>
<gml:pos>1 2</gml:pos>
</gml:Point>
</gml:pointMember>
</gml:MultiPoint>
@@ -20,7 +20,7 @@
<gml:MultiPoint xmlns:gml="http://www.opengis.net/gml">
<gml:pointMember>
<gml:Point>
<gml:coordinates decimal="." cs="," ts=" ">1,2</gml:coordinates>
<gml:pos>1 2</gml:pos>
</gml:Point>
</gml:pointMember>
</gml:MultiPoint>
@@ -42,4 +42,4 @@
<ogc:FeatureId fid="fid.37"/>
</ogc:Filter>
</wfs:Delete>
</wfs:Transaction>
</wfs:Transaction>

View File

@@ -176,9 +176,69 @@ describe('ol.format.WFS', function() {
});
describe('when writing out a Transaction request', function() {
it('creates a handle', function() {
var text =
'<wfs:Transaction xmlns:wfs="http://www.opengis.net/wfs" ' +
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
'service="WFS" version="1.1.0" handle="handle_t" ' +
'xsi:schemaLocation="http://www.opengis.net/wfs ' +
'http://schemas.opengis.net/wfs/1.1.0/wfs.xsd"/>';
var serialized = new ol.format.WFS().writeTransaction(null, null, null,
{handle: 'handle_t'});
expect(serialized).to.xmleql(ol.xml.load(text));
});
});
describe('when writing out a Transaction request', function() {
var text;
before(function(done) {
afterLoadText('spec/ol/format/wfs/TransactionMulti.xml', function(xml) {
text = xml;
done();
});
});
it('creates the correct transaction body', function() {
var format = new ol.format.WFS();
var insertFeature = new ol.Feature({
the_geom: new ol.geom.MultiPoint([[1, 2]]),
foo: 'bar',
nul: null
});
insertFeature.setGeometryName('the_geom');
var inserts = [insertFeature];
var updateFeature = new ol.Feature({
the_geom: new ol.geom.MultiPoint([[1, 2]]),
foo: 'bar',
// null value gets Property element with no Value
nul: null,
// undefined value means don't create a Property element
unwritten: undefined
});
updateFeature.setId('fid.42');
var updates = [updateFeature];
var deleteFeature = new ol.Feature();
deleteFeature.setId('fid.37');
var deletes = [deleteFeature];
var serialized = format.writeTransaction(inserts, updates, deletes, {
featureNS: 'http://www.openplans.org/topp',
featureType: 'states',
featurePrefix: 'topp'
});
expect(serialized).to.xmleql(ol.xml.load(text));
});
});
});
goog.require('ol.xml');
goog.require('ol.Feature');
goog.require('ol.geom.MultiPoint');
goog.require('ol.geom.MultiPolygon');
goog.require('ol.format.WFS');