// This software is released into the Public Domain. See copying.txt for details. package org.openstreetmap.osmosis.xml.v0_6.impl; import java.util.logging.Logger; import org.xml.sax.Attributes; import org.openstreetmap.osmosis.core.OsmosisRuntimeException; import org.openstreetmap.osmosis.core.task.v0_6.Sink; import org.openstreetmap.osmosis.xml.common.BaseElementProcessor; import org.openstreetmap.osmosis.xml.common.ElementProcessor; /** * Provides an element processor implementation for an osm element. * * @author Brett Henderson */ public class OsmElementProcessor extends SourceElementProcessor { private static final Logger LOG = Logger.getLogger(OsmElementProcessor.class.getName()); private static final String ELEMENT_NAME_BOUND_LEGACY = "bound"; private static final String ELEMENT_NAME_BOUNDS = "bounds"; private static final String ELEMENT_NAME_NODE = "node"; private static final String ELEMENT_NAME_WAY = "way"; private static final String ELEMENT_NAME_RELATION = "relation"; private static final String ATTRIBUTE_NAME_VERSION = "version"; private static final String ATTRIBUTE_NAME_GENERATOR = "generator"; private NodeElementProcessor nodeElementProcessor; private WayElementProcessor wayElementProcessor; private RelationElementProcessor relationElementProcessor; private boolean foundBound = false; private boolean foundEntities = false; private boolean validateVersion; private String generator; /** * Creates a new instance (coordinates are required). * * @param parentProcessor * The parent of this element processor. * @param sink * The sink for receiving processed data. * @param enableDateParsing * If true, dates will be parsed from xml data, else the current * date will be used thus saving parsing time. * @param validateVersion If true, a version attribute will be checked and validated. */ public OsmElementProcessor( BaseElementProcessor parentProcessor, Sink sink, boolean enableDateParsing, boolean validateVersion) { this(parentProcessor, sink, enableDateParsing, validateVersion, true); } /** * Creates a new instance. * * @param parentProcessor * The parent of this element processor. * @param sink * The sink for receiving processed data. * @param enableDateParsing * If true, dates will be parsed from xml data, else the current * date will be used thus saving parsing time. * @param validateVersion If true, a version attribute will be checked and validated. * @param coordinatesRequired * If true, nodes without lat and lon attributes set will cause an exception. */ public OsmElementProcessor( BaseElementProcessor parentProcessor, Sink sink, boolean enableDateParsing, boolean validateVersion, boolean coordinatesRequired) { super(parentProcessor, sink, enableDateParsing); this.validateVersion = validateVersion; nodeElementProcessor = new NodeElementProcessor(this, getSink(), enableDateParsing, coordinatesRequired); wayElementProcessor = new WayElementProcessor(this, getSink(), enableDateParsing); relationElementProcessor = new RelationElementProcessor(this, getSink(), enableDateParsing); } /** * {@inheritDoc} */ public void begin(Attributes attributes) { if (validateVersion) { String fileVersion; fileVersion = attributes.getValue(ATTRIBUTE_NAME_VERSION); if (!XmlConstants.OSM_VERSION.equals(fileVersion)) { LOG.warning( "Expected version " + XmlConstants.OSM_VERSION + " but received " + fileVersion + "." ); } } generator = attributes.getValue(ATTRIBUTE_NAME_GENERATOR); } /** * Retrieves the appropriate child element processor for the newly * encountered nested element. * * @param uri * The element uri. * @param localName * The element localName. * @param qName * The element qName. * @return The appropriate element processor for the nested element. */ @Override public ElementProcessor getChild(String uri, String localName, String qName) { if (ELEMENT_NAME_BOUNDS.equals(qName) || ELEMENT_NAME_BOUND_LEGACY.equals(qName)) { if (foundEntities) { throw new OsmosisRuntimeException("Bound element must come before any entities."); } if (foundBound) { throw new OsmosisRuntimeException("Only one bound element allowed."); } foundBound = true; if (ELEMENT_NAME_BOUND_LEGACY.equals(qName)) { LOG.fine("Legacy <bound> element encountered."); return new LegacyBoundElementProcessor(this, getSink(), true); } else { return new BoundsElementProcessor(this, getSink(), true, generator); } } else if (ELEMENT_NAME_NODE.equals(qName)) { foundEntities = true; return nodeElementProcessor; } else if (ELEMENT_NAME_WAY.equals(qName)) { foundEntities = true; return wayElementProcessor; } else if (ELEMENT_NAME_RELATION.equals(qName)) { foundEntities = true; return relationElementProcessor; } return super.getChild(uri, localName, qName); } /** * {@inheritDoc} */ public void end() { // This class produces no data and therefore doesn't need to do anything // when the end of the element is reached. } }