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

Last change on this file since 5299 was 5266, checked in by bastiK, 12 years ago

fixed majority of javadoc warnings by replacing "{@see" by "{@link"

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