/** * @module ol/format/OSMXML */ // FIXME add typedef for stack state objects import {inherits} from '../index.js'; import _ol_array_ from '../array.js'; import _ol_Feature_ from '../Feature.js'; import _ol_format_Feature_ from '../format/Feature.js'; import _ol_format_XMLFeature_ from '../format/XMLFeature.js'; import _ol_geom_GeometryLayout_ from '../geom/GeometryLayout.js'; import _ol_geom_LineString_ from '../geom/LineString.js'; import Point from '../geom/Point.js'; import _ol_geom_Polygon_ from '../geom/Polygon.js'; import _ol_obj_ from '../obj.js'; import {get as getProjection} from '../proj.js'; import _ol_xml_ from '../xml.js'; /** * @classdesc * Feature format for reading data in the * [OSMXML format](http://wiki.openstreetmap.org/wiki/OSM_XML). * * @constructor * @extends {ol.format.XMLFeature} * @api */ var _ol_format_OSMXML_ = function() { _ol_format_XMLFeature_.call(this); /** * @inheritDoc */ this.defaultDataProjection = getProjection('EPSG:4326'); }; inherits(_ol_format_OSMXML_, _ol_format_XMLFeature_); /** * @param {Node} node Node. * @param {Array.<*>} objectStack Object stack. * @private */ _ol_format_OSMXML_.readNode_ = function(node, objectStack) { var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); var state = /** @type {Object} */ (objectStack[objectStack.length - 1]); var id = node.getAttribute('id'); /** @type {ol.Coordinate} */ var coordinates = [ parseFloat(node.getAttribute('lon')), parseFloat(node.getAttribute('lat')) ]; state.nodes[id] = coordinates; var values = _ol_xml_.pushParseAndPop({ tags: {} }, _ol_format_OSMXML_.NODE_PARSERS_, node, objectStack); if (!_ol_obj_.isEmpty(values.tags)) { var geometry = new Point(coordinates); _ol_format_Feature_.transformWithOptions(geometry, false, options); var feature = new _ol_Feature_(geometry); feature.setId(id); feature.setProperties(values.tags); state.features.push(feature); } }; /** * @param {Node} node Node. * @param {Array.<*>} objectStack Object stack. * @private */ _ol_format_OSMXML_.readWay_ = function(node, objectStack) { var id = node.getAttribute('id'); var values = _ol_xml_.pushParseAndPop({ id: id, ndrefs: [], tags: {} }, _ol_format_OSMXML_.WAY_PARSERS_, node, objectStack); var state = /** @type {Object} */ (objectStack[objectStack.length - 1]); state.ways.push(values); }; /** * @param {Node} node Node. * @param {Array.<*>} objectStack Object stack. * @private */ _ol_format_OSMXML_.readNd_ = function(node, objectStack) { var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); values.ndrefs.push(node.getAttribute('ref')); }; /** * @param {Node} node Node. * @param {Array.<*>} objectStack Object stack. * @private */ _ol_format_OSMXML_.readTag_ = function(node, objectStack) { var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); values.tags[node.getAttribute('k')] = node.getAttribute('v'); }; /** * @const * @private * @type {Array.} */ _ol_format_OSMXML_.NAMESPACE_URIS_ = [ null ]; /** * @const * @type {Object.>} * @private */ _ol_format_OSMXML_.WAY_PARSERS_ = _ol_xml_.makeStructureNS( _ol_format_OSMXML_.NAMESPACE_URIS_, { 'nd': _ol_format_OSMXML_.readNd_, 'tag': _ol_format_OSMXML_.readTag_ }); /** * @const * @type {Object.>} * @private */ _ol_format_OSMXML_.PARSERS_ = _ol_xml_.makeStructureNS( _ol_format_OSMXML_.NAMESPACE_URIS_, { 'node': _ol_format_OSMXML_.readNode_, 'way': _ol_format_OSMXML_.readWay_ }); /** * @const * @type {Object.>} * @private */ _ol_format_OSMXML_.NODE_PARSERS_ = _ol_xml_.makeStructureNS( _ol_format_OSMXML_.NAMESPACE_URIS_, { 'tag': _ol_format_OSMXML_.readTag_ }); /** * Read all features from an OSM source. * * @function * @param {Document|Node|Object|string} source Source. * @param {olx.format.ReadOptions=} opt_options Read options. * @return {Array.} Features. * @api */ _ol_format_OSMXML_.prototype.readFeatures; /** * @inheritDoc */ _ol_format_OSMXML_.prototype.readFeaturesFromNode = function(node, opt_options) { var options = this.getReadOptions(node, opt_options); if (node.localName == 'osm') { var state = _ol_xml_.pushParseAndPop({ nodes: {}, ways: [], features: [] }, _ol_format_OSMXML_.PARSERS_, node, [options]); // parse nodes in ways for (var j = 0; j < state.ways.length; j++) { var values = /** @type {Object} */ (state.ways[j]); /** @type {Array.} */ var flatCoordinates = []; for (var i = 0, ii = values.ndrefs.length; i < ii; i++) { var point = state.nodes[values.ndrefs[i]]; _ol_array_.extend(flatCoordinates, point); } var geometry; if (values.ndrefs[0] == values.ndrefs[values.ndrefs.length - 1]) { // closed way geometry = new _ol_geom_Polygon_(null); geometry.setFlatCoordinates(_ol_geom_GeometryLayout_.XY, flatCoordinates, [flatCoordinates.length]); } else { geometry = new _ol_geom_LineString_(null); geometry.setFlatCoordinates(_ol_geom_GeometryLayout_.XY, flatCoordinates); } _ol_format_Feature_.transformWithOptions(geometry, false, options); var feature = new _ol_Feature_(geometry); feature.setId(values.id); feature.setProperties(values.tags); state.features.push(feature); } if (state.features) { return state.features; } } return []; }; /** * Read the projection from an OSM source. * * @function * @param {Document|Node|Object|string} source Source. * @return {ol.proj.Projection} Projection. * @api */ _ol_format_OSMXML_.prototype.readProjection; /** * Not implemented. * @inheritDoc */ _ol_format_OSMXML_.prototype.writeFeatureNode = function(feature, opt_options) {}; /** * Not implemented. * @inheritDoc */ _ol_format_OSMXML_.prototype.writeFeaturesNode = function(features, opt_options) {}; /** * Not implemented. * @inheritDoc */ _ol_format_OSMXML_.prototype.writeGeometryNode = function(geometry, opt_options) {}; export default _ol_format_OSMXML_;