Add Insert, Update and Delete writers
This change also adds some type annotations for better type checking, introduces different write options for writing transactions and queries, and provides new writeGetFeature and writeTransaction methods.
This commit is contained in:
@@ -595,6 +595,32 @@
|
||||
* calculations.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ol.parser.WFSWriteGetFeatureOptions
|
||||
* @property {string} featureNS The namespace URI used for features.
|
||||
* @property {string} featurePrefix The prefix for the feature namespace.
|
||||
* @property {Array.<string>} featureTypes The feature type names.
|
||||
* @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 {string|undefined} outputFormat Output format.
|
||||
* @property {Array.<Object>} nativeElements Native elements. Currently not
|
||||
* supported.
|
||||
* @property {number} maxFeatures Maximum number of features to fetch.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ol.parser.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} ol.source.BingMapsOptions
|
||||
* @property {string|undefined} culture Culture code. Default is `en-us`.
|
||||
|
||||
@@ -1,31 +1,22 @@
|
||||
goog.provide('ol.parser.ogc.WFS_v1');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.dom.xml');
|
||||
goog.require('ol.expr.Call');
|
||||
goog.require('ol.expr.Identifier');
|
||||
goog.require('ol.expr.Literal');
|
||||
goog.require('ol.geom.Geometry');
|
||||
goog.require('ol.parser.XML');
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {{featureNS: string,
|
||||
featurePrefix: string,
|
||||
featureTypes: Array.<string>,
|
||||
handle: string,
|
||||
outputFormat: string,
|
||||
nativeElements: Array.<{
|
||||
vendorId: string,
|
||||
safeToIgnore: boolean,
|
||||
value: string
|
||||
}>,
|
||||
maxFeatures: number}}
|
||||
*/
|
||||
ol.parser.WFSWriteOptions;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.parser.XML}
|
||||
* @param {Object=} opt_options Options which will be set on this object.
|
||||
*/
|
||||
ol.parser.ogc.WFS_v1 = function() {
|
||||
ol.parser.ogc.WFS_v1 = function(opt_options) {
|
||||
this.defaultNamespaceURI = 'http://www.opengis.net/wfs';
|
||||
|
||||
// TODO set errorProperty
|
||||
this.readers = {};
|
||||
this.readers[this.defaultNamespaceURI] = {
|
||||
@@ -36,8 +27,13 @@ ol.parser.ogc.WFS_v1 = function() {
|
||||
};
|
||||
this.writers = {};
|
||||
this.writers[this.defaultNamespaceURI] = {
|
||||
/**
|
||||
* @param {ol.parser.WFSWriteGetFeatureOptions} options Options.
|
||||
* @return {{node: Node,
|
||||
* options: ol.parser.WFSWriteGetFeatureOptions}} Object.
|
||||
* @this {ol.parser.XML}
|
||||
*/
|
||||
'GetFeature': function(options) {
|
||||
options = /** @type {ol.parser.WFSWriteOptions} */(options);
|
||||
var node = this.createElementNS('wfs:GetFeature');
|
||||
node.setAttribute('service', 'WFS');
|
||||
node.setAttribute('version', this.version);
|
||||
@@ -61,29 +57,41 @@ ol.parser.ogc.WFS_v1 = function() {
|
||||
'xsi:schemaLocation', this.schemaLocation);
|
||||
return {node: node, options: options};
|
||||
},
|
||||
/**
|
||||
* @param {{inserts: Array.<ol.Feature>,
|
||||
* updates: Array.<ol.Feature>,
|
||||
* deletes: Array.<ol.Feature>,
|
||||
* options: ol.parser.WFSWriteTransactionOptions}} obj Object.
|
||||
* @return {Element} Node.
|
||||
* @this {ol.parser.XML}
|
||||
*/
|
||||
'Transaction': function(obj) {
|
||||
obj = obj || {};
|
||||
var options = /** {ol.parser.WFSWriteOptions} */(obj.options || {});
|
||||
var options = obj.options;
|
||||
this.setFeatureType(options.featureType);
|
||||
this.setFeatureNS(options.featureNS);
|
||||
if (goog.isDef(options.srsName)) {
|
||||
this.setSrsName(options.srsName);
|
||||
}
|
||||
var node = this.createElementNS('wfs:Transaction');
|
||||
node.setAttribute('service', 'WFS');
|
||||
node.setAttribute('version', this.version);
|
||||
if (goog.isDef(options.handle)) {
|
||||
node.setAttribute('handle', options.handle);
|
||||
}
|
||||
var i, ii;
|
||||
var features = obj.features;
|
||||
if (goog.isDefAndNotNull(features)) {
|
||||
// TODO implement multi option for geometry types
|
||||
var name, feature;
|
||||
for (i = 0, ii = features.length; i < ii; ++i) {
|
||||
feature = features[i];
|
||||
// TODO Update (use feature.getOriginal())
|
||||
// TODO Insert and Delete
|
||||
if (goog.isDef(name)) {
|
||||
this.writeNode(name, {
|
||||
feature: feature,
|
||||
options: options
|
||||
}, null, node);
|
||||
var i, ii, features, feature;
|
||||
var operations = {
|
||||
'Insert': obj.inserts,
|
||||
'Update': obj.updates,
|
||||
'Delete': obj.deletes
|
||||
};
|
||||
for (var name in operations) {
|
||||
features = operations[name];
|
||||
if (!goog.isNull(features)) {
|
||||
// TODO implement multi option for geometry types
|
||||
for (i = 0, ii = features.length; i < ii; ++i) {
|
||||
feature = features[i];
|
||||
this.writeNode(name, {feature: feature, options: options}, null,
|
||||
node);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,12 +102,147 @@ ol.parser.ogc.WFS_v1 = function() {
|
||||
}
|
||||
return node;
|
||||
},
|
||||
/**
|
||||
* @param {{vendorId: string, safeToIgnore: boolean, value: string}}
|
||||
* nativeElement Native element.
|
||||
* @return {Node} Node.
|
||||
* @this {ol.parser.XML}
|
||||
*/
|
||||
'Native': function(nativeElement) {
|
||||
var node = this.createElementNS('wfs:Native');
|
||||
node.setAttribute('vendorId', nativeElement.vendorId);
|
||||
node.setAttribute('safeToIgnore', nativeElement.safeToIgnore);
|
||||
node.appendChild(this.createTextNode(nativeElement.value));
|
||||
return node;
|
||||
},
|
||||
/**
|
||||
* @param {{feature: ol.Feature,
|
||||
* options: ol.parser.WFSWriteTransactionOptions}} obj Object.
|
||||
* @return {Element} Node.
|
||||
* @this {ol.parser.XML}
|
||||
*/
|
||||
'Insert': function(obj) {
|
||||
var feature = obj.feature;
|
||||
var options = obj.options;
|
||||
var node = this.createElementNS('wfs:Insert');
|
||||
if (goog.isDef(options) && goog.isDef(options.handle)) {
|
||||
this.setAttributeNS(node, this.defaultNamespaceURI, 'handle',
|
||||
options.handle);
|
||||
}
|
||||
if (goog.isDef(options.srsName)) {
|
||||
this.setSrsName(options.srsName);
|
||||
}
|
||||
this.writeNode('_typeName', feature, options.featureNS, node);
|
||||
return node;
|
||||
},
|
||||
/**
|
||||
* @param {{feature: ol.Feature,
|
||||
* options: ol.parser.WFSWriteTransactionOptions}} obj Object.
|
||||
* @return {Element} Node.
|
||||
* @this {ol.parser.XML}
|
||||
*/
|
||||
'Update': function(obj) {
|
||||
var feature = obj.feature;
|
||||
var options = obj.options;
|
||||
var node = this.createElementNS('wfs:Update');
|
||||
this.setAttributeNS(node, this.defaultNamespaceURI, 'typeName',
|
||||
(goog.isDef(options.featureNS) ? options.featurePrefix + ':' : '') +
|
||||
options.featureType);
|
||||
if (goog.isDef(options.handle)) {
|
||||
this.setAttributeNS(node, this.defaultNamespaceURI, 'handle',
|
||||
options.handle);
|
||||
}
|
||||
if (goog.isDef(options.featureNS)) {
|
||||
node.setAttribute('xmlns:' + options.featurePrefix, options.featureNS);
|
||||
}
|
||||
|
||||
// add in fields
|
||||
var original = feature.getOriginal();
|
||||
var originalAttributes = goog.isNull(original) ?
|
||||
undefined : original.getAttributes();
|
||||
var attributes = feature.getAttributes();
|
||||
var attribute;
|
||||
for (var key in attributes) {
|
||||
attribute = attributes[key];
|
||||
// TODO Only add geometries whose values have changed
|
||||
if (goog.isDef(attribute) && (attribute instanceof ol.geom.Geometry ||
|
||||
(!goog.isDef(originalAttributes) ||
|
||||
attribute != originalAttributes[key]))) {
|
||||
this.writeNode('Property', {name: key, value: attribute}, null, node);
|
||||
}
|
||||
}
|
||||
|
||||
// add feature id filter
|
||||
var fid = feature.getId();
|
||||
goog.asserts.assert(goog.isDef(fid));
|
||||
this.writeNode('Filter', new ol.expr.Call(new ol.expr.Identifier(
|
||||
ol.expr.functions.FID), [new ol.expr.Literal(fid)]),
|
||||
'http://www.opengis.net/ogc', node);
|
||||
|
||||
return node;
|
||||
},
|
||||
'Property': function(obj) {
|
||||
var node = this.createElementNS('wfs:Property');
|
||||
this.writeNode('Name', obj.name, null, node);
|
||||
if (!goog.isNull(obj.value)) {
|
||||
this.writeNode('Value', obj.value, null, node);
|
||||
}
|
||||
return node;
|
||||
},
|
||||
/**
|
||||
* @param {string} name Name.
|
||||
* @return {Element} Node.
|
||||
* @this {ol.parser.XML}
|
||||
*/
|
||||
'Name': function(name) {
|
||||
var node = this.createElementNS('wfs:Name');
|
||||
node.appendChild(this.createTextNode(name));
|
||||
return node;
|
||||
},
|
||||
/**
|
||||
* @param {string|ol.geom.Geometry} obj Object.
|
||||
* @return {Element} Node.
|
||||
* @this {ol.parser.XML}
|
||||
*/
|
||||
'Value': function(obj) {
|
||||
var node;
|
||||
if (obj instanceof ol.geom.Geometry) {
|
||||
node = this.createElementNS('wfs:Value');
|
||||
node.appendChild(
|
||||
this.getFilterParser().getGmlParser().writeGeometry(obj));
|
||||
} else {
|
||||
goog.asserts.assertString(obj);
|
||||
node = this.createElementNS('wfs:Value');
|
||||
node.appendChild(this.createTextNode(obj));
|
||||
}
|
||||
return node;
|
||||
},
|
||||
/**
|
||||
* @param {{feature: ol.Feature,
|
||||
* options: ol.parser.WFSWriteTransactionOptions}} obj Object.
|
||||
* @return {Element} Node.
|
||||
* @this {ol.parser.ogc.GML}
|
||||
*/
|
||||
'Delete': function(obj) {
|
||||
var feature = obj.feature;
|
||||
var options = obj.options;
|
||||
var node = this.createElementNS('wfs:Delete');
|
||||
this.setAttributeNS(node, this.defaultNamespaceURI, 'typeName',
|
||||
(goog.isDef(options.featureNS) ? options.featurePrefix + ':' : '') +
|
||||
options.featureType);
|
||||
if (goog.isDef(options.handle)) {
|
||||
this.setAttributeNS(node, options.defaultNamespaceURI, 'handle',
|
||||
options.handle);
|
||||
}
|
||||
if (goog.isDef(options.featureNS)) {
|
||||
node.setAttribute('xmlns:' + options.featurePrefix, options.featureNS);
|
||||
}
|
||||
var fid = feature.getId();
|
||||
goog.asserts.assert(goog.isDef(fid));
|
||||
this.writeNode('Filter', new ol.expr.Call(new ol.expr.Identifier(
|
||||
ol.expr.functions.FID), [new ol.expr.Literal(fid)]),
|
||||
'http://www.opengis.net/ogc', node);
|
||||
return node;
|
||||
}
|
||||
};
|
||||
goog.base(this);
|
||||
@@ -204,13 +347,27 @@ ol.parser.ogc.WFS_v1.prototype.read = function(data) {
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<ol.Feature>} features The features to write out.
|
||||
* @param {ol.parser.WFSWriteOptions} options Write options.
|
||||
* @param {ol.parser.WFSWriteGetFeatureOptions} options Options.
|
||||
* @return {string} A serialized WFS GetFeature query.
|
||||
*/
|
||||
ol.parser.ogc.WFS_v1.prototype.writeGetFeature = function(options) {
|
||||
var root = this.writers[this.defaultNamespaceURI]['GetFeature']
|
||||
.call(this, options);
|
||||
return this.serialize(root);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @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 {ol.parser.WFSWriteTransactionOptions} options Write options.
|
||||
* @return {string} A serialized WFS transaction.
|
||||
*/
|
||||
ol.parser.ogc.WFS_v1.prototype.write = function(features, options) {
|
||||
var root = this.writeNode('Transaction', {features: features,
|
||||
options: options});
|
||||
ol.parser.ogc.WFS_v1.prototype.writeTransaction =
|
||||
function(inserts, updates, deletes, options) {
|
||||
var root = this.writeNode('Transaction', {inserts: inserts,
|
||||
updates: updates, deletes: deletes, options: options});
|
||||
this.setAttributeNS(
|
||||
root, 'http://www.w3.org/2001/XMLSchema-instance',
|
||||
'xsi:schemaLocation', this.schemaLocation);
|
||||
|
||||
@@ -19,17 +19,15 @@ describe('ol.parser.ogc.WFS', function() {
|
||||
var url = 'spec/ol/parser/ogc/xml/wfs_v1/GetFeature.xml';
|
||||
afterLoadXml(url, function(xml) {
|
||||
var p = new ol.parser.ogc.WFS_v1_0_0();
|
||||
var output = p.writers[p.defaultNamespaceURI]['GetFeature'].
|
||||
apply(p, [{
|
||||
featureNS: 'http://www.openplans.org/topp',
|
||||
featureTypes: ['states'],
|
||||
featurePrefix: 'topp',
|
||||
handle: 'handle_g',
|
||||
maxFeatures: 1,
|
||||
outputFormat: 'json'
|
||||
}
|
||||
]);
|
||||
expect(goog.dom.xml.loadXml(p.serialize(output))).to.xmleql(xml);
|
||||
var output = p.writeGetFeature({
|
||||
featureNS: 'http://www.openplans.org/topp',
|
||||
featureTypes: ['states'],
|
||||
featurePrefix: 'topp',
|
||||
handle: 'handle_g',
|
||||
maxFeatures: 1,
|
||||
outputFormat: 'json'
|
||||
});
|
||||
expect(goog.dom.xml.loadXml(output)).to.xmleql(xml);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -38,12 +36,44 @@ describe('ol.parser.ogc.WFS', function() {
|
||||
var url = 'spec/ol/parser/ogc/xml/wfs_v1/Transaction.xml';
|
||||
afterLoadXml(url, function(xml) {
|
||||
var p = new ol.parser.ogc.WFS_v1_0_0();
|
||||
var output = p.writers[p.defaultNamespaceURI]['Transaction'].
|
||||
apply(p, [{
|
||||
options: {handle: 'handle_t'}
|
||||
}
|
||||
]);
|
||||
expect(goog.dom.xml.loadXml(p.serialize(output))).to.xmleql(xml);
|
||||
var output = p.writeTransaction(null, null, null, {handle: 'handle_t'});
|
||||
expect(goog.dom.xml.loadXml(output)).to.xmleql(xml);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('handles writing out transactions', function(done) {
|
||||
var url = 'spec/ol/parser/ogc/xml/wfs_v1/TransactionMulti.xml';
|
||||
afterLoadXml(url, function(xml) {
|
||||
var parser = new ol.parser.ogc.WFS_v1_0_0();
|
||||
|
||||
var insertFeature = new ol.Feature({
|
||||
the_geom: new ol.geom.MultiPoint([[1, 2]]),
|
||||
foo: 'bar',
|
||||
nul: null
|
||||
});
|
||||
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 output = parser.writeTransaction(inserts, updates, deletes, {
|
||||
featureNS: 'http://www.openplans.org/topp',
|
||||
featureType: 'states',
|
||||
featurePrefix: 'topp'
|
||||
});
|
||||
expect(goog.dom.xml.loadXml(output)).to.xmleql(xml);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -52,7 +82,7 @@ describe('ol.parser.ogc.WFS', function() {
|
||||
var url = 'spec/ol/parser/ogc/xml/wfs_v1/Native.xml';
|
||||
afterLoadXml(url, function(xml) {
|
||||
var p = new ol.parser.ogc.WFS_v1_1_0();
|
||||
var output = p.write(null, {nativeElements: [{
|
||||
var output = p.writeTransaction(null, null, null, {nativeElements: [{
|
||||
vendorId: 'ORACLE',
|
||||
safeToIgnore: true,
|
||||
value: 'ALTER SESSION ENABLE PARALLEL DML'
|
||||
@@ -70,14 +100,12 @@ describe('ol.parser.ogc.WFS', function() {
|
||||
var url = 'spec/ol/parser/ogc/xml/wfs_v1/GetFeatureMultiple.xml';
|
||||
afterLoadXml(url, function(xml) {
|
||||
var p = new ol.parser.ogc.WFS_v1_0_0();
|
||||
var output = p.writers[p.defaultNamespaceURI]['GetFeature'].
|
||||
apply(p, [{
|
||||
featureNS: 'http://www.openplans.org/topp',
|
||||
featureTypes: ['states', 'cities'],
|
||||
featurePrefix: 'topp'
|
||||
}
|
||||
]);
|
||||
expect(goog.dom.xml.loadXml(p.serialize(output))).to.xmleql(xml);
|
||||
var output = p.writeGetFeature({
|
||||
featureNS: 'http://www.openplans.org/topp',
|
||||
featureTypes: ['states', 'cities'],
|
||||
featurePrefix: 'topp'
|
||||
});
|
||||
expect(goog.dom.xml.loadXml(output)).to.xmleql(xml);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -87,6 +115,8 @@ describe('ol.parser.ogc.WFS', function() {
|
||||
});
|
||||
|
||||
goog.require('goog.dom.xml');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.geom.MultiPoint');
|
||||
goog.require('ol.parser.ogc.WFS');
|
||||
goog.require('ol.parser.ogc.WFS_v1_0_0');
|
||||
goog.require('ol.parser.ogc.WFS_v1_1_0');
|
||||
|
||||
@@ -1 +1 @@
|
||||
<wfs:Transaction xmlns:wfs="http://www.opengis.net/wfs" service="WFS" version="1.0.0" handle="handle_t" />
|
||||
<wfs:Transaction xmlns:wfs="http://www.opengis.net/wfs" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" service="WFS" version="1.0.0" handle="handle_t" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd"/>
|
||||
|
||||
45
test/spec/ol/parser/ogc/xml/wfs_v1/TransactionMulti.xml
Normal file
45
test/spec/ol/parser/ogc/xml/wfs_v1/TransactionMulti.xml
Normal file
@@ -0,0 +1,45 @@
|
||||
<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: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:Point>
|
||||
</gml:pointMember>
|
||||
</gml:MultiPoint>
|
||||
</feature:the_geom>
|
||||
<feature:foo>bar</feature:foo>
|
||||
</feature:states>
|
||||
</wfs:Insert>
|
||||
<wfs:Update xmlns:wfs="http://www.opengis.net/wfs" typeName="topp:states" xmlns:topp="http://www.openplans.org/topp">
|
||||
<wfs:Property>
|
||||
<wfs:Name>the_geom</wfs:Name>
|
||||
<wfs:Value>
|
||||
<gml:MultiPoint xmlns:gml="http://www.opengis.net/gml">
|
||||
<gml:pointMember>
|
||||
<gml:Point>
|
||||
<gml:coordinates decimal="." cs="," ts=" ">1,2</gml:coordinates>
|
||||
</gml:Point>
|
||||
</gml:pointMember>
|
||||
</gml:MultiPoint>
|
||||
</wfs:Value>
|
||||
</wfs:Property>
|
||||
<wfs:Property>
|
||||
<wfs:Name>foo</wfs:Name>
|
||||
<wfs:Value>bar</wfs:Value>
|
||||
</wfs:Property>
|
||||
<wfs:Property>
|
||||
<wfs:Name>nul</wfs:Name>
|
||||
</wfs:Property>
|
||||
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
|
||||
<ogc:FeatureId fid="fid.42"/>
|
||||
</ogc:Filter>
|
||||
</wfs:Update>
|
||||
<wfs:Delete xmlns:wfs="http://www.opengis.net/wfs" typeName="topp:states" xmlns:topp="http://www.openplans.org/topp">
|
||||
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
|
||||
<ogc:FeatureId fid="fid.37"/>
|
||||
</ogc:Filter>
|
||||
</wfs:Delete>
|
||||
</wfs:Transaction>
|
||||
Reference in New Issue
Block a user