diff --git a/externs/olx.js b/externs/olx.js index 57db7a97c9..78df7efe8b 100644 --- a/externs/olx.js +++ b/externs/olx.js @@ -1679,8 +1679,8 @@ olx.format.KMLOptions.prototype.defaultStyle; /** - * @typedef {{featureNS: string, - * featureType: string, + * @typedef {{featureNS: (Object.|string|undefined), + * featureType: (Array.|string|undefined), * srsName: string, * surface: (boolean|undefined), * curve: (boolean|undefined), @@ -1693,16 +1693,28 @@ olx.format.GMLOptions; /** - * Feature namespace. - * @type {string} + * Feature namespace. If not defined will be derived from GML. If multiple + * feature types have been configured which come from different feature + * namespaces, this will be an object with the keys being the prefixes used + * in the entries of featureType array. The values of the object will be the + * feature namespaces themselves. So for instance there might be a featureType + * item `topp:states` in the `featureType` array and then there will be a key + * `topp` in the featureNS object with value `http://www.openplans.org/topp`. + * @type {Object.|string|undefined} * @api stable */ olx.format.GMLOptions.prototype.featureNS; /** - * Feature type to parse. - * @type {string} + * Feature type(s) to parse. If multiple feature types need to be configured + * which come from different feature namespaces, `featureNS` will be an object + * with the keys being the prefixes used in the entries of featureType array. + * The values of the object will be the feature namespaces themselves. + * So for instance there might be a featureType item `topp:states` and then + * there will be a key named `topp` in the featureNS object with value + * `http://www.openplans.org/topp`. + * @type {Array.|string|undefined} * @api stable */ olx.format.GMLOptions.prototype.featureType; @@ -1782,8 +1794,8 @@ olx.format.GPXOptions.prototype.readExtensions; /** - * @typedef {{featureNS: string, - * featureType: string, + * @typedef {{featureNS: (Object.|string|undefined), + * featureType: (Array.|string|undefined), * gmlFormat: (ol.format.GMLBase|undefined), * schemaLocation: (string|undefined)}} * @api @@ -1793,7 +1805,7 @@ olx.format.WFSOptions; /** * The namespace URI used for features. - * @type {string} + * @type {Object.|string|undefined} * @api stable */ olx.format.WFSOptions.prototype.featureNS; @@ -1801,7 +1813,7 @@ olx.format.WFSOptions.prototype.featureNS; /** * The feature type to parse. Only used for read operations. - * @type {string} + * @type {Array.|string|undefined} * @api stable */ olx.format.WFSOptions.prototype.featureType; diff --git a/src/ol/format/gml/gmlbaseformat.js b/src/ol/format/gml/gmlbaseformat.js index 771d526b2f..97333bf651 100644 --- a/src/ol/format/gml/gmlbaseformat.js +++ b/src/ol/format/gml/gmlbaseformat.js @@ -45,13 +45,13 @@ ol.format.GMLBase = function(opt_options) { /** * @protected - * @type {string} + * @type {Array.|string|undefined} */ this.featureType = options.featureType; /** * @protected - * @type {string} + * @type {Object.|string|undefined} */ this.featureNS = options.featureNS; @@ -107,18 +107,52 @@ ol.format.GMLBase.prototype.readFeaturesInternal = function(node, objectStack) { var context = objectStack[0]; goog.asserts.assert(goog.isObject(context)); var featureType = context['featureType']; - if (!goog.isDef(featureType) && !goog.isNull(node.firstElementChild)) { - var member = node.firstElementChild; - featureType = member.nodeName.split(':').pop(); + var featureNS = context['featureNS']; + var i, ii, prefix = 'p', defaultPrefix = 'p0'; + if (!goog.isDef(featureType) && goog.isDefAndNotNull(node.childNodes)) { + featureType = [], featureNS = {}; + for (i = 0, ii = node.childNodes.length; i < ii; ++i) { + var child = node.childNodes[i]; + if (child.nodeType === 1) { + var ft = child.nodeName.split(':').pop(); + if (goog.array.indexOf(featureType, ft) === -1) { + var key; + if (!goog.object.contains(featureNS, child.namespaceURI)) { + key = prefix + goog.object.getCount(featureNS); + featureNS[key] = child.namespaceURI; + } else { + key = goog.object.findKey(featureNS, function(value) { + return value === child.namespaceURI; + }); + } + featureType.push(key + ':' + ft); + } + } + } context['featureType'] = featureType; - context['featureNS'] = member.namespaceURI; + context['featureNS'] = featureNS; + } + if (goog.isString(featureNS)) { + var ns = featureNS; + featureNS = {}; + featureNS[defaultPrefix] = ns; } - var parsers = {}; var parsersNS = {}; - parsers[featureType] = (localName == 'featureMembers') ? - ol.xml.makeArrayPusher(this.readFeatureElement, this) : - ol.xml.makeReplacer(this.readFeatureElement, this); - parsersNS[context['featureNS']] = parsers; + var featureTypes = goog.isArray(featureType) ? featureType : [featureType]; + for (var p in featureNS) { + var parsers = {}; + for (i = 0, ii = featureTypes.length; i < ii; ++i) { + var featurePrefix = featureTypes[i].indexOf(':') === -1 ? + defaultPrefix : featureTypes[i].split(':')[0]; + if (featurePrefix === p) { + parsers[featureTypes[i].split(':').pop()] = + (localName == 'featureMembers') ? + ol.xml.makeArrayPusher(this.readFeatureElement, this) : + ol.xml.makeReplacer(this.readFeatureElement, this); + } + } + parsersNS[featureNS[p]] = parsers; + } features = ol.xml.pushParseAndPop([], parsersNS, node, objectStack); } if (!goog.isDef(features)) { diff --git a/src/ol/format/wfsformat.js b/src/ol/format/wfsformat.js index 540d139506..8bc16a317f 100644 --- a/src/ol/format/wfsformat.js +++ b/src/ol/format/wfsformat.js @@ -31,13 +31,13 @@ ol.format.WFS = function(opt_options) { /** * @private - * @type {string} + * @type {Array.|string|undefined} */ this.featureType_ = options.featureType; /** * @private - * @type {string} + * @type {Object.|string|undefined} */ this.featureNS_ = options.featureNS; diff --git a/test/spec/ol/format/gml/multiple-typenames-ns.xml b/test/spec/ol/format/gml/multiple-typenames-ns.xml new file mode 100644 index 0000000000..e36469efcc --- /dev/null +++ b/test/spec/ol/format/gml/multiple-typenames-ns.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + 37.51099000000001 -88.071564 37.476273000000006 + -88.087883 37.442852 -88.311707 37.40930899999999 -88.359177 + 37.51099000000001 -88.071564 + + + + + + + Illinois + 17 + E N Cen + IL + 143986.61 + 1993.335 + 1.1430602E7 + 2924880.0 + 4202240.0 + 5552233.0 + 5878369.0 + 4199206.0 + 3741715.0 + 652603.0 + 538071.0 + 5417967.0 + 385040.0 + 1360159.0 + 828906.0 + 0.486 + 0.514 + 1747776.0 + + + + + + + 37.51099000000001 -88.071564 37.476273000000006 + -88.087883 37.442852 -88.311707 37.40930899999999 -88.359177 + 37.51099000000001 -88.071564 + + + + + 5 + unimproved road + + + diff --git a/test/spec/ol/format/gml/multiple-typenames.xml b/test/spec/ol/format/gml/multiple-typenames.xml new file mode 100644 index 0000000000..f841e5dbef --- /dev/null +++ b/test/spec/ol/format/gml/multiple-typenames.xml @@ -0,0 +1,44 @@ + + + + 3822829 + + + 3820888 + + + 296916318 + + + 37244 + + + 1641478 + + + 1244004 + + + 22259 + + + 1606103 + + + 3217145 + + + 3228576 + + + 936994 + + + 936990 + + + diff --git a/test/spec/ol/format/gmlformat.test.js b/test/spec/ol/format/gmlformat.test.js index d68aad6d27..4a86a4f324 100644 --- a/test/spec/ol/format/gmlformat.test.js +++ b/test/spec/ol/format/gmlformat.test.js @@ -1107,6 +1107,97 @@ describe('ol.format.GML3', function() { }); + describe('when parsing multiple feature types', function() { + + var features; + before(function(done) { + afterLoadText('spec/ol/format/gml/multiple-typenames.xml', function(xml) { + try { + features = new ol.format.GML({ + featureNS: 'http://localhost:8080/official', + featureType: ['planet_osm_polygon', 'planet_osm_line'] + }).readFeatures(xml); + } catch (e) { + done(e); + } + done(); + }); + }); + + it('reads all features', function() { + expect(features.length).to.be(12); + }); + + }); + + describe('when parsing multiple feature types', function() { + + var features; + before(function(done) { + afterLoadText('spec/ol/format/gml/multiple-typenames.xml', function(xml) { + try { + features = new ol.format.GML().readFeatures(xml); + } catch (e) { + done(e); + } + done(); + }); + }); + + it('reads all features with autoconfigure', function() { + expect(features.length).to.be(12); + }); + + }); + + describe('when parsing multiple feature types / namespaces', function() { + + var features; + before(function(done) { + var url = 'spec/ol/format/gml/multiple-typenames-ns.xml'; + afterLoadText(url, function(xml) { + try { + features = new ol.format.GML({ + featureNS: { + 'topp': 'http://www.openplans.org/topp', + 'sf': 'http://www.openplans.org/spearfish' + }, + featureType: ['topp:states', 'sf:roads'] + }).readFeatures(xml); + } catch (e) { + done(e); + } + done(); + }); + }); + + it('reads all features', function() { + expect(features.length).to.be(2); + }); + + }); + + describe('when parsing multiple feature types / namespaces', function() { + + var features; + before(function(done) { + var url = 'spec/ol/format/gml/multiple-typenames-ns.xml'; + afterLoadText(url, function(xml) { + try { + features = new ol.format.GML().readFeatures(xml); + } catch (e) { + done(e); + } + done(); + }); + }); + + it('reads all features with autoconfigure', function() { + expect(features.length).to.be(2); + }); + + }); + }); diff --git a/test/spec/ol/format/wfsformat.test.js b/test/spec/ol/format/wfsformat.test.js index a13def7f39..db52d424c5 100644 --- a/test/spec/ol/format/wfsformat.test.js +++ b/test/spec/ol/format/wfsformat.test.js @@ -448,6 +448,49 @@ describe('ol.format.WFS', function() { }); + describe('when parsing multiple feature types', function() { + + var features; + before(function(done) { + afterLoadText('spec/ol/format/gml/multiple-typenames.xml', function(xml) { + try { + features = new ol.format.WFS({ + featureNS: 'http://localhost:8080/official', + featureType: ['planet_osm_polygon', 'planet_osm_line'] + }).readFeatures(xml); + } catch (e) { + done(e); + } + done(); + }); + }); + + it('reads all features', function() { + expect(features.length).to.be(12); + }); + + }); + + describe('when parsing multiple feature types', function() { + + var features; + before(function(done) { + afterLoadText('spec/ol/format/gml/multiple-typenames.xml', function(xml) { + try { + features = new ol.format.WFS().readFeatures(xml); + } catch (e) { + done(e); + } + done(); + }); + }); + + it('reads all features with autoconfigure', function() { + expect(features.length).to.be(12); + }); + + }); + });