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

Revision 4734, 13.7 KB checked in by Don-vip, 5 months ago (diff)

fix #7194 - Reworking of osmChange downloads (Fail to update a way loaded from osmChange that have been deleted after)

  • Property svn:eol-style set to native
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 {@see 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.