source: josm/trunk/src/org/openstreetmap/josm/io/OsmChangesetContentParser.java@ 6070

Last change on this file since 6070 was 6070, checked in by stoecker, 11 years ago

see #8853 remove tabs, trailing spaces, windows line ends, strange characters

  • Property svn:eol-style set to native
File size: 13.8 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.io.IOException;
7import java.io.InputStream;
8import java.io.InputStreamReader;
9import java.io.StringReader;
10import java.io.UnsupportedEncodingException;
11import java.util.Date;
12
13import javax.xml.parsers.ParserConfigurationException;
14import javax.xml.parsers.SAXParserFactory;
15
16import org.openstreetmap.josm.data.coor.LatLon;
17import org.openstreetmap.josm.data.osm.ChangesetDataSet;
18import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
19import org.openstreetmap.josm.data.osm.RelationMemberData;
20import org.openstreetmap.josm.data.osm.User;
21import org.openstreetmap.josm.data.osm.ChangesetDataSet.ChangesetModificationType;
22import org.openstreetmap.josm.data.osm.history.HistoryNode;
23import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
24import org.openstreetmap.josm.data.osm.history.HistoryRelation;
25import org.openstreetmap.josm.data.osm.history.HistoryWay;
26import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
27import org.openstreetmap.josm.gui.progress.ProgressMonitor;
28import org.openstreetmap.josm.tools.CheckParameterUtil;
29import org.openstreetmap.josm.tools.DateUtils;
30import org.xml.sax.Attributes;
31import org.xml.sax.InputSource;
32import org.xml.sax.Locator;
33import org.xml.sax.SAXException;
34import org.xml.sax.SAXParseException;
35import org.xml.sax.helpers.DefaultHandler;
36
37/**
38 * Parser for OSM changeset content.
39 *
40 */
41public class OsmChangesetContentParser {
42
43 private InputSource source;
44 private ChangesetDataSet data;
45
46 // FIXME: this class has many similarities with OsmHistoryReader.Parser and should be merged
47 private class Parser extends DefaultHandler {
48
49 /** the current primitive to be read */
50 private HistoryOsmPrimitive currentPrimitive;
51 /** the current change modification type */
52 private ChangesetDataSet.ChangesetModificationType currentModificationType;
53
54 private Locator locator;
55
56 @Override
57 public void setDocumentLocator(Locator locator) {
58 this.locator = locator;
59 }
60
61 protected void throwException(String message) throws OsmDataParsingException {
62 throw new OsmDataParsingException(
63 message
64 ).rememberLocation(locator);
65 }
66
67 protected void throwException(Exception e) throws OsmDataParsingException {
68 throw new OsmDataParsingException(
69 e
70 ).rememberLocation(locator);
71 }
72
73 protected long getMandatoryAttributeLong(Attributes attr, String name) throws SAXException{
74 String v = attr.getValue(name);
75 if (v == null) {
76 throwException(tr("Missing mandatory attribute ''{0}''.", name));
77 }
78 Long l = 0l;
79 try {
80 l = Long.parseLong(v);
81 } catch(NumberFormatException e) {
82 throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long. Got ''{1}''.", name, v));
83 }
84 if (l < 0) {
85 throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long (>=0). Got ''{1}''.", name, v));
86 }
87 return l;
88 }
89
90 protected Long getAttributeLong(Attributes attr, String name) throws SAXException{
91 String v = attr.getValue(name);
92 if (v == null)
93 return null;
94 Long l = null;
95 try {
96 l = Long.parseLong(v);
97 } catch(NumberFormatException e) {
98 throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long. Got ''{1}''.", name, v));
99 }
100 if (l < 0) {
101 throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long (>=0). Got ''{1}''.", name, v));
102 }
103 return l;
104 }
105
106 protected Double getAttributeDouble(Attributes attr, String name) throws SAXException{
107 String v = attr.getValue(name);
108 if (v == null) {
109 return null;
110 }
111 double d = 0.0;
112 try {
113 d = Double.parseDouble(v);
114 } catch(NumberFormatException e) {
115 throwException(tr("Illegal value for attribute ''{0}'' of type double. Got ''{1}''.", name, v));
116 }
117 return d;
118 }
119
120 protected String getMandatoryAttributeString(Attributes attr, String name) throws SAXException{
121 String v = attr.getValue(name);
122 if (v == null) {
123 throwException(tr("Missing mandatory attribute ''{0}''.", name));
124 }
125 return v;
126 }
127
128 protected boolean getMandatoryAttributeBoolean(Attributes attr, String name) throws SAXException{
129 String v = attr.getValue(name);
130 if (v == null) {
131 throwException(tr("Missing mandatory attribute ''{0}''.", name));
132 }
133 if ("true".equals(v)) return true;
134 if ("false".equals(v)) return false;
135 throwException(tr("Illegal value for mandatory attribute ''{0}'' of type boolean. Got ''{1}''.", name, v));
136 // not reached
137 return false;
138 }
139
140 protected HistoryOsmPrimitive createPrimitive(Attributes atts, OsmPrimitiveType type) throws SAXException {
141 long id = getMandatoryAttributeLong(atts,"id");
142 long version = getMandatoryAttributeLong(atts,"version");
143 long changesetId = getMandatoryAttributeLong(atts,"changeset");
144 boolean visible= getMandatoryAttributeBoolean(atts, "visible");
145
146 Long uid = getAttributeLong(atts, "uid");
147 String userStr = atts.getValue("user");
148 User user;
149 if (userStr != null) {
150 if (uid != null) {
151 user = User.createOsmUser(uid, userStr);
152 } else {
153 user = User.createLocalUser(userStr);
154 }
155 } else {
156 user = User.getAnonymous();
157 }
158
159 String v = getMandatoryAttributeString(atts, "timestamp");
160 Date timestamp = DateUtils.fromString(v);
161 HistoryOsmPrimitive primitive = null;
162 if (type.equals(OsmPrimitiveType.NODE)) {
163 Double lat = getAttributeDouble(atts, "lat");
164 Double lon = getAttributeDouble(atts, "lon");
165 LatLon coor = (lat != null && lon != null) ? new LatLon(lat,lon) : null;
166 primitive = new HistoryNode(
167 id,version,visible,user,changesetId,timestamp,coor
168 );
169
170 } else if (type.equals(OsmPrimitiveType.WAY)) {
171 primitive = new HistoryWay(
172 id,version,visible,user,changesetId,timestamp
173 );
174 }if (type.equals(OsmPrimitiveType.RELATION)) {
175 primitive = new HistoryRelation(
176 id,version,visible,user,changesetId,timestamp
177 );
178 }
179 return primitive;
180 }
181
182 protected void startNode(Attributes atts) throws SAXException {
183 currentPrimitive= createPrimitive(atts, OsmPrimitiveType.NODE);
184 }
185
186 protected void startWay(Attributes atts) throws SAXException {
187 currentPrimitive= createPrimitive(atts, OsmPrimitiveType.WAY);
188 }
189 protected void startRelation(Attributes atts) throws SAXException {
190 currentPrimitive= createPrimitive(atts, OsmPrimitiveType.RELATION);
191 }
192
193 protected void handleTag(Attributes atts) throws SAXException {
194 String key= getMandatoryAttributeString(atts, "k");
195 String value= getMandatoryAttributeString(atts, "v");
196 currentPrimitive.put(key,value);
197 }
198
199 protected void handleNodeReference(Attributes atts) throws SAXException {
200 long ref = getMandatoryAttributeLong(atts, "ref");
201 ((HistoryWay)currentPrimitive).addNode(ref);
202 }
203
204 protected void handleMember(Attributes atts) throws SAXException {
205 long ref = getMandatoryAttributeLong(atts, "ref");
206 String v = getMandatoryAttributeString(atts, "type");
207 OsmPrimitiveType type = null;
208 try {
209 type = OsmPrimitiveType.fromApiTypeName(v);
210 } catch(IllegalArgumentException e) {
211 throwException(tr("Illegal value for mandatory attribute ''{0}'' of type OsmPrimitiveType. Got ''{1}''.", "type", v));
212 }
213 String role = getMandatoryAttributeString(atts, "role");
214 RelationMemberData member = new RelationMemberData(role, type,ref);
215 ((HistoryRelation)currentPrimitive).addMember(member);
216 }
217
218 @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
219 if (qName.equals("node")) {
220 startNode(atts);
221 } else if (qName.equals("way")) {
222 startWay(atts);
223 } else if (qName.equals("relation")) {
224 startRelation(atts);
225 } else if (qName.equals("tag")) {
226 handleTag(atts);
227 } else if (qName.equals("nd")) {
228 handleNodeReference(atts);
229 } else if (qName.equals("member")) {
230 handleMember(atts);
231 } else if (qName.equals("osmChange")) {
232 // do nothing
233 } else if (qName.equals("create")) {
234 currentModificationType = ChangesetModificationType.CREATED;
235 } else if (qName.equals("modify")) {
236 currentModificationType = ChangesetModificationType.UPDATED;
237 } else if (qName.equals("delete")) {
238 currentModificationType = ChangesetModificationType.DELETED;
239 } else {
240 System.err.println(tr("Warning: unsupported start element ''{0}'' in changeset content at position ({1},{2}). Skipping.", qName, locator.getLineNumber(), locator.getColumnNumber()));
241 }
242 }
243
244 @Override
245 public void endElement(String uri, String localName, String qName) throws SAXException {
246 if (qName.equals("node")
247 || qName.equals("way")
248 || qName.equals("relation")) {
249 if (currentModificationType == null) {
250 throwException(tr("Illegal document structure. Found node, way, or relation outside of ''create'', ''modify'', or ''delete''."));
251 }
252 data.put(currentPrimitive, currentModificationType);
253 } else if (qName.equals("osmChange")) {
254 // do nothing
255 } else if (qName.equals("create")) {
256 currentModificationType = null;
257 } else if (qName.equals("modify")) {
258 currentModificationType = null;
259 } else if (qName.equals("delete")) {
260 currentModificationType = null;
261 } else if (qName.equals("tag")) {
262 // do nothing
263 } else if (qName.equals("nd")) {
264 // do nothing
265 } else if (qName.equals("member")) {
266 // do nothing
267 } else {
268 System.err.println(tr("Warning: unsupported end element ''{0}'' in changeset content at position ({1},{2}). Skipping.", qName, locator.getLineNumber(), locator.getColumnNumber()));
269 }
270 }
271
272 @Override
273 public void error(SAXParseException e) throws SAXException {
274 throwException(e);
275 }
276
277 @Override
278 public void fatalError(SAXParseException e) throws SAXException {
279 throwException(e);
280 }
281 }
282
283 /**
284 * Create a parser
285 *
286 * @param source the input stream with the changeset content as XML document. Must not be null.
287 * @throws IllegalArgumentException thrown if source is null.
288 */
289 public OsmChangesetContentParser(InputStream source) throws UnsupportedEncodingException {
290 CheckParameterUtil.ensureParameterNotNull(source, "source");
291 this.source = new InputSource(new InputStreamReader(source, "UTF-8"));
292 data = new ChangesetDataSet();
293 }
294
295 public OsmChangesetContentParser(String source) {
296 CheckParameterUtil.ensureParameterNotNull(source, "source");
297 this.source = new InputSource(new StringReader(source));
298 data = new ChangesetDataSet();
299 }
300
301 /**
302 * Parses the content
303 *
304 * @param progressMonitor the progress monitor. Set to {@link NullProgressMonitor#INSTANCE}
305 * if null
306 * @return the parsed data
307 * @throws OsmDataParsingException thrown if something went wrong. Check for chained
308 * exceptions.
309 */
310 public ChangesetDataSet parse(ProgressMonitor progressMonitor) throws OsmDataParsingException {
311 if (progressMonitor == null) {
312 progressMonitor = NullProgressMonitor.INSTANCE;
313 }
314 try {
315 progressMonitor.beginTask("");
316 progressMonitor.indeterminateSubTask(tr("Parsing changeset content ..."));
317 SAXParserFactory.newInstance().newSAXParser().parse(source, new Parser());
318 } catch(OsmDataParsingException e){
319 throw e;
320 } catch (ParserConfigurationException e) {
321 throw new OsmDataParsingException(e);
322 } catch(SAXException e) {
323 throw new OsmDataParsingException(e);
324 } catch(IOException e) {
325 throw new OsmDataParsingException(e);
326 } finally {
327 progressMonitor.finishTask();
328 }
329 return data;
330 }
331
332 /**
333 * Parses the content from the input source
334 *
335 * @return the parsed data
336 * @throws OsmDataParsingException thrown if something went wrong. Check for chained
337 * exceptions.
338 */
339 public ChangesetDataSet parse() throws OsmDataParsingException {
340 return parse(null);
341 }
342}
Note: See TracBrowser for help on using the repository browser.