source: josm/trunk/src/org/openstreetmap/josm/io/OsmHistoryReader.java@ 5346

Last change on this file since 5346 was 5346, checked in by Don-vip, 12 years ago

fix #7867, see #7505, see #7847 - Handle deleted nodes without coordinates in history

  • Property svn:eol-style set to native
File size: 10.1 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.util.Date;
10
11import javax.xml.parsers.ParserConfigurationException;
12import javax.xml.parsers.SAXParserFactory;
13
14import org.openstreetmap.josm.data.coor.LatLon;
15import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
16import org.openstreetmap.josm.data.osm.RelationMemberData;
17import org.openstreetmap.josm.data.osm.User;
18import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
19import org.openstreetmap.josm.data.osm.history.HistoryNode;
20import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
21import org.openstreetmap.josm.data.osm.history.HistoryRelation;
22import org.openstreetmap.josm.data.osm.history.HistoryWay;
23import org.openstreetmap.josm.gui.progress.ProgressMonitor;
24import org.openstreetmap.josm.tools.DateUtils;
25import org.xml.sax.Attributes;
26import org.xml.sax.InputSource;
27import org.xml.sax.Locator;
28import org.xml.sax.SAXException;
29import org.xml.sax.helpers.DefaultHandler;
30
31/**
32 * Parser for OSM history data.
33 *
34 * It is slightly different from {@link OsmReader} because we don't build an internal graph of
35 * {@link OsmPrimitive}s. We use objects derived from {@link HistoryOsmPrimitive} instead and we
36 * keep the data in a dedicated {@link HistoryDataSet}.
37 *
38 */
39public class OsmHistoryReader {
40
41 private final InputStream in;
42 private final HistoryDataSet data;
43
44 // FIXME: this class has many similarities with OsmChangesetContentParser.Parser and should be merged
45 private class Parser extends DefaultHandler {
46
47 /** the current primitive to be read */
48 private HistoryOsmPrimitive current;
49 private Locator locator;
50
51 @Override
52 public void setDocumentLocator(Locator locator) {
53 this.locator = locator;
54 }
55
56 protected String getCurrentPosition() {
57 if (locator == null)
58 return "";
59 return "(" + locator.getLineNumber() + "," + locator.getColumnNumber() + ")";
60 }
61
62 protected void throwException(String message) throws SAXException {
63 throw new SAXException(
64 getCurrentPosition()
65 + message
66 );
67 }
68
69 protected long getMandatoryAttributeLong(Attributes attr, String name) throws SAXException{
70 String v = attr.getValue(name);
71 if (v == null) {
72 throwException(tr("Missing mandatory attribute ''{0}''.", name));
73 }
74 Long l = 0l;
75 try {
76 l = Long.parseLong(v);
77 } catch(NumberFormatException e) {
78 throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long. Got ''{1}''.", name, v));
79 }
80 if (l < 0) {
81 throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long (>=0). Got ''{1}''.", name, v));
82 }
83 return l;
84 }
85
86 protected Long getAttributeLong(Attributes attr, String name) throws SAXException {
87 String v = attr.getValue(name);
88 if (v == null)
89 return null;
90 Long l = null;
91 try {
92 l = Long.parseLong(v);
93 } catch(NumberFormatException e) {
94 throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long. Got ''{1}''.", name, v));
95 }
96 if (l < 0) {
97 throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long (>=0). Got ''{1}''.", name, v));
98 }
99 return l;
100 }
101
102 protected Double getAttributeDouble(Attributes attr, String name) throws SAXException{
103 String v = attr.getValue(name);
104 if (v == null) {
105 return null;
106 }
107 double d = 0.0;
108 try {
109 d = Double.parseDouble(v);
110 } catch(NumberFormatException e) {
111 throwException(tr("Illegal value for attribute ''{0}'' of type double. Got ''{1}''.", name, v));
112 }
113 return d;
114 }
115
116 protected String getMandatoryAttributeString(Attributes attr, String name) throws SAXException{
117 String v = attr.getValue(name);
118 if (v == null) {
119 throwException(tr("Missing mandatory attribute ''{0}''.", name));
120 }
121 return v;
122 }
123
124 protected boolean getMandatoryAttributeBoolean(Attributes attr, String name) throws SAXException{
125 String v = attr.getValue(name);
126 if (v == null) {
127 throwException(tr("Missing mandatory attribute ''{0}''.", name));
128 }
129 if ("true".equals(v)) return true;
130 if ("false".equals(v)) return false;
131 throwException(tr("Illegal value for mandatory attribute ''{0}'' of type boolean. Got ''{1}''.", name, v));
132 // not reached
133 return false;
134 }
135
136 protected HistoryOsmPrimitive createPrimitive(Attributes atts, OsmPrimitiveType type) throws SAXException {
137 long id = getMandatoryAttributeLong(atts,"id");
138 long version = getMandatoryAttributeLong(atts,"version");
139 long changesetId = getMandatoryAttributeLong(atts,"changeset");
140 boolean visible= getMandatoryAttributeBoolean(atts, "visible");
141 Long uid = getAttributeLong(atts, "uid");
142 String userStr = atts.getValue("user");
143 User user;
144 if (userStr != null) {
145 if (uid != null) {
146 user = User.createOsmUser(uid, userStr);
147 } else {
148 user = User.createLocalUser(userStr);
149 }
150 } else {
151 user = User.getAnonymous();
152 }
153 String v = getMandatoryAttributeString(atts, "timestamp");
154 Date timestamp = DateUtils.fromString(v);
155 HistoryOsmPrimitive primitive = null;
156 if (type.equals(OsmPrimitiveType.NODE)) {
157 Double lat = getAttributeDouble(atts, "lat");
158 Double lon = getAttributeDouble(atts, "lon");
159 LatLon coord = (lat != null && lon != null) ? new LatLon(lat,lon) : null;
160 primitive = new HistoryNode(
161 id,version,visible,user,changesetId,timestamp,coord
162 );
163
164 } else if (type.equals(OsmPrimitiveType.WAY)) {
165 primitive = new HistoryWay(
166 id,version,visible,user,changesetId,timestamp
167 );
168 }if (type.equals(OsmPrimitiveType.RELATION)) {
169 primitive = new HistoryRelation(
170 id,version,visible,user,changesetId,timestamp
171 );
172 }
173 return primitive;
174 }
175
176 protected void startNode(Attributes atts) throws SAXException {
177 current= createPrimitive(atts, OsmPrimitiveType.NODE);
178 }
179
180 protected void startWay(Attributes atts) throws SAXException {
181 current= createPrimitive(atts, OsmPrimitiveType.WAY);
182 }
183 protected void startRelation(Attributes atts) throws SAXException {
184 current= createPrimitive(atts, OsmPrimitiveType.RELATION);
185 }
186
187 protected void handleTag(Attributes atts) throws SAXException {
188 String key= getMandatoryAttributeString(atts, "k");
189 String value= getMandatoryAttributeString(atts, "v");
190 current.put(key,value);
191 }
192
193 protected void handleNodeReference(Attributes atts) throws SAXException {
194 long ref = getMandatoryAttributeLong(atts, "ref");
195 ((HistoryWay)current).addNode(ref);
196 }
197
198 protected void handleMember(Attributes atts) throws SAXException {
199 long ref = getMandatoryAttributeLong(atts, "ref");
200 String v = getMandatoryAttributeString(atts, "type");
201 OsmPrimitiveType type = null;
202 try {
203 type = OsmPrimitiveType.fromApiTypeName(v);
204 } catch(IllegalArgumentException e) {
205 throwException(tr("Illegal value for mandatory attribute ''{0}'' of type OsmPrimitiveType. Got ''{1}''.", "type", v));
206 }
207 String role = getMandatoryAttributeString(atts, "role");
208 RelationMemberData member = new RelationMemberData(role, type,ref);
209 ((HistoryRelation)current).addMember(member);
210 }
211
212 @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
213 if (qName.equals("node")) {
214 startNode(atts);
215 } else if (qName.equals("way")) {
216 startWay(atts);
217 } else if (qName.equals("relation")) {
218 startRelation(atts);
219 } else if (qName.equals("tag")) {
220 handleTag(atts);
221 } else if (qName.equals("nd")) {
222 handleNodeReference(atts);
223 } else if (qName.equals("member")) {
224 handleMember(atts);
225 }
226 }
227
228 @Override
229 public void endElement(String uri, String localName, String qName) throws SAXException {
230 if (qName.equals("node")
231 || qName.equals("way")
232 || qName.equals("relation")) {
233 data.put(current);
234 }
235 }
236 }
237
238 public OsmHistoryReader(InputStream source) {
239 this.in = source;
240 this.data = new HistoryDataSet();
241 }
242
243 public HistoryDataSet parse(ProgressMonitor progressMonitor) throws SAXException, IOException {
244 InputSource inputSource = new InputSource(new InputStreamReader(in, "UTF-8"));
245 progressMonitor.beginTask(tr("Parsing OSM history data ..."));
246 try {
247 SAXParserFactory.newInstance().newSAXParser().parse(inputSource, new Parser());
248 } catch (ParserConfigurationException e1) {
249 e1.printStackTrace(); // broken SAXException chaining
250 throw new SAXException(e1);
251 } finally {
252 progressMonitor.finishTask();
253 }
254 return data;
255 }
256}
Note: See TracBrowser for help on using the repository browser.