1 | package CommandLine;
|
---|
2 |
|
---|
3 | import static org.openstreetmap.josm.tools.I18n.tr;
|
---|
4 |
|
---|
5 | import java.io.InputStream;
|
---|
6 | import java.util.ArrayList;
|
---|
7 | import java.util.HashMap;
|
---|
8 | import java.util.LinkedList;
|
---|
9 | import java.util.List;
|
---|
10 | import java.util.Map;
|
---|
11 |
|
---|
12 | import javax.xml.parsers.ParserConfigurationException;
|
---|
13 | import javax.xml.parsers.SAXParserFactory;
|
---|
14 |
|
---|
15 | import org.openstreetmap.josm.Main;
|
---|
16 | import org.openstreetmap.josm.command.AddCommand;
|
---|
17 | import org.openstreetmap.josm.command.ChangeCommand;
|
---|
18 | import org.openstreetmap.josm.command.ChangeNodesCommand;
|
---|
19 | import org.openstreetmap.josm.command.Command;
|
---|
20 | import org.openstreetmap.josm.command.DeleteCommand;
|
---|
21 | import org.openstreetmap.josm.data.coor.LatLon;
|
---|
22 | import org.openstreetmap.josm.data.osm.*;
|
---|
23 | import org.openstreetmap.josm.io.IllegalDataException;
|
---|
24 | import org.openstreetmap.josm.io.OsmDataParsingException;
|
---|
25 | import org.openstreetmap.josm.io.UTFInputStreamReader;
|
---|
26 | import org.openstreetmap.josm.tools.DateUtils;
|
---|
27 |
|
---|
28 | import org.xml.sax.Attributes;
|
---|
29 | import org.xml.sax.InputSource;
|
---|
30 | import org.xml.sax.Locator;
|
---|
31 | import org.xml.sax.SAXException;
|
---|
32 | import org.xml.sax.SAXParseException;
|
---|
33 | import org.xml.sax.helpers.DefaultHandler;
|
---|
34 |
|
---|
35 | final class OsmToCmd {
|
---|
36 | private final DataSet targetDataSet;
|
---|
37 | private final LinkedList<Command> cmds = new LinkedList<Command>();
|
---|
38 | private HashMap<PrimitiveId, OsmPrimitive> externalIdMap; // Maps external ids to internal primitives
|
---|
39 |
|
---|
40 | public OsmToCmd(DataSet targetDataSet, InputStream stream) throws IllegalDataException {
|
---|
41 | this.targetDataSet = targetDataSet;
|
---|
42 | externalIdMap = new HashMap<PrimitiveId, OsmPrimitive>();
|
---|
43 | parseStream(stream);
|
---|
44 | }
|
---|
45 |
|
---|
46 | private void parseStream(InputStream stream) throws IllegalDataException {
|
---|
47 | try {
|
---|
48 | InputSource inputSource = new InputSource(UTFInputStreamReader.create(stream, "UTF-8"));
|
---|
49 | SAXParserFactory.newInstance().newSAXParser().parse(inputSource, new Parser());
|
---|
50 | } catch(ParserConfigurationException e) {
|
---|
51 | throw new IllegalDataException(e.getMessage(), e);
|
---|
52 | } catch (SAXParseException e) {
|
---|
53 | throw new IllegalDataException(tr("Line {0} column {1}: ", e.getLineNumber(), e.getColumnNumber()) + e.getMessage(), e);
|
---|
54 | } catch(SAXException e) {
|
---|
55 | throw new IllegalDataException(e.getMessage(), e);
|
---|
56 | } catch(Exception e) {
|
---|
57 | throw new IllegalDataException(e);
|
---|
58 | }
|
---|
59 | }
|
---|
60 |
|
---|
61 | public LinkedList<Command> getCommandList() {
|
---|
62 | return cmds;
|
---|
63 | }
|
---|
64 |
|
---|
65 | private class Parser extends DefaultHandler {
|
---|
66 | private Locator locator;
|
---|
67 |
|
---|
68 | @Override
|
---|
69 | public void setDocumentLocator(Locator locator) {
|
---|
70 | this.locator = locator;
|
---|
71 | }
|
---|
72 |
|
---|
73 | protected void throwException(String msg) throws OsmDataParsingException {
|
---|
74 | throw new OsmDataParsingException(msg).rememberLocation(locator);
|
---|
75 | }
|
---|
76 |
|
---|
77 | private OsmPrimitive currentPrimitive;
|
---|
78 | private long currentExternalId;
|
---|
79 | private List<Node> currentWayNodes = new ArrayList<Node>();
|
---|
80 | private List<RelationMember> currentRelationMembers = new ArrayList<RelationMember>();
|
---|
81 |
|
---|
82 | @Override
|
---|
83 | public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
|
---|
84 | try {
|
---|
85 | if (qName.equals("osm")) {
|
---|
86 | if (atts == null) {
|
---|
87 | throwException(tr("Missing mandatory attribute ''{0}'' of XML element {1}.", "version", "osm"));
|
---|
88 | }
|
---|
89 | String v = atts.getValue("version");
|
---|
90 | if (v == null) {
|
---|
91 | throwException(tr("Missing mandatory attribute ''{0}''.", "version"));
|
---|
92 | }
|
---|
93 | if ( !(v.equals("0.6")) ) {
|
---|
94 | throwException(tr("Unsupported version: {0}", v));
|
---|
95 | }
|
---|
96 |
|
---|
97 | // ---- PARSING NODES AND WAYS ----
|
---|
98 |
|
---|
99 | } else if (qName.equals("node")) {
|
---|
100 | Node n = new Node();
|
---|
101 | NodeData source = new NodeData();
|
---|
102 | source.setCoor(new LatLon(getDouble(atts, "lat"), getDouble(atts, "lon")));
|
---|
103 | readCommon(atts, source);
|
---|
104 | Node target = (Node)targetDataSet.getPrimitiveById( source.getUniqueId(), source.getType() );
|
---|
105 |
|
---|
106 | if (target == null || !(source.isModified() || source.isDeleted()) )
|
---|
107 | n.load(source);
|
---|
108 | else {
|
---|
109 | n.cloneFrom(target);
|
---|
110 | n.load(source);
|
---|
111 | }
|
---|
112 |
|
---|
113 | currentPrimitive = n;
|
---|
114 | externalIdMap.put(source.getPrimitiveId(), (OsmPrimitive)n);
|
---|
115 | //System.out.println("NODE " + String.valueOf(source.getUniqueId()) + " HAS MAPPED TO INNER " + String.valueOf(n.getUniqueId()) );
|
---|
116 | }
|
---|
117 | else if (qName.equals("way")) {
|
---|
118 | Way w = new Way();
|
---|
119 | WayData source = new WayData();
|
---|
120 | readCommon(atts, source);
|
---|
121 | Way target = (Way)targetDataSet.getPrimitiveById( source.getUniqueId(), source.getType() );
|
---|
122 |
|
---|
123 | if (target == null || !(source.isModified() || source.isDeleted()) )
|
---|
124 | w.load(source);
|
---|
125 | else {
|
---|
126 | w.cloneFrom(target);
|
---|
127 | w.load(source);
|
---|
128 | }
|
---|
129 |
|
---|
130 | currentPrimitive = w;
|
---|
131 | currentWayNodes.clear();
|
---|
132 | externalIdMap.put(source.getPrimitiveId(), (OsmPrimitive)w);
|
---|
133 | //System.out.println("WAY " + String.valueOf(source.getUniqueId()) + " HAS MAPPED TO INNER " + String.valueOf(w.getUniqueId()) );
|
---|
134 | }
|
---|
135 | else if (qName.equals("nd")) {
|
---|
136 | if (atts.getValue("ref") == null)
|
---|
137 | throwException(tr("Missing mandatory attribute ''{0}'' on <nd> of way {1}.", "ref", currentPrimitive.getUniqueId()));
|
---|
138 | long id = getLong(atts, "ref");
|
---|
139 | if (id == 0)
|
---|
140 | throwException(tr("Illegal value of attribute ''ref'' of element <nd>. Got {0}.", id) );
|
---|
141 | //System.out.println("NODE " + String.valueOf(id) + " HAS ADDED TO WAY " + String.valueOf(currentPrimitive.getUniqueId()));
|
---|
142 | Node node = (Node)externalIdMap.get(new SimplePrimitiveId(id, OsmPrimitiveType.NODE));
|
---|
143 | if (node == null || node.isModified()) {
|
---|
144 | node = (Node)targetDataSet.getPrimitiveById( new SimplePrimitiveId(id, OsmPrimitiveType.NODE) );
|
---|
145 | if (node == null)
|
---|
146 | throwException(tr("Missing definition of new object with id {0}.", id));
|
---|
147 | }
|
---|
148 | currentWayNodes.add(node);
|
---|
149 | }
|
---|
150 | // ---- PARSING RELATIONS ----
|
---|
151 |
|
---|
152 | else if (qName.equals("relation")) {
|
---|
153 | Relation r = new Relation();
|
---|
154 | RelationData source = new RelationData();
|
---|
155 | readCommon(atts, source);
|
---|
156 | Relation target = (Relation)targetDataSet.getPrimitiveById( source.getUniqueId(), source.getType() );
|
---|
157 |
|
---|
158 | if (target == null || !(source.isModified() || source.isDeleted()) )
|
---|
159 | r.load(source);
|
---|
160 | else {
|
---|
161 | r.cloneFrom(target);
|
---|
162 | r.load(source);
|
---|
163 | }
|
---|
164 |
|
---|
165 | currentPrimitive = r;
|
---|
166 | currentRelationMembers.clear();
|
---|
167 | externalIdMap.put(source.getPrimitiveId(), (OsmPrimitive)r);
|
---|
168 | //System.out.println("RELATION " + String.valueOf(source.getUniqueId()) + " HAS MAPPED TO INNER " + String.valueOf(r.getUniqueId()) );
|
---|
169 | }
|
---|
170 | else if (qName.equals("member")) {
|
---|
171 | if (atts.getValue("ref") == null)
|
---|
172 | throwException(tr("Missing mandatory attribute ''{0}'' on <member> of relation {1}.", "ref", currentPrimitive.getUniqueId()));
|
---|
173 | long id = getLong(atts, "ref");
|
---|
174 | if (id == 0)
|
---|
175 | throwException(tr("Illegal value of attribute ''ref'' of element <nd>. Got {0}.", id) );
|
---|
176 |
|
---|
177 | OsmPrimitiveType type = OsmPrimitiveType.NODE;
|
---|
178 | String value = atts.getValue("type");
|
---|
179 | if (value == null) {
|
---|
180 | throwException(tr("Missing attribute ''type'' on member {0} in relation {1}.", Long.toString(id), Long.toString(currentPrimitive.getUniqueId())));
|
---|
181 | }
|
---|
182 | try {
|
---|
183 | type = OsmPrimitiveType.fromApiTypeName(value);
|
---|
184 | }
|
---|
185 | catch(IllegalArgumentException e) {
|
---|
186 | throwException(tr("Illegal value for attribute ''type'' on member {0} in relation {1}. Got {2}.", Long.toString(id), Long.toString(currentPrimitive.getUniqueId()), value));
|
---|
187 | }
|
---|
188 |
|
---|
189 | String role = atts.getValue("role");
|
---|
190 |
|
---|
191 | //System.out.println("MEMBER " + value.toUpperCase() + " " +String.valueOf(id) + " HAS ADDED TO RELATION " + String.valueOf(currentPrimitive.getUniqueId()));
|
---|
192 | OsmPrimitive member = externalIdMap.get(new SimplePrimitiveId(id, type));
|
---|
193 | if (member == null) {
|
---|
194 | member = targetDataSet.getPrimitiveById(new SimplePrimitiveId(id, type));
|
---|
195 | if (member == null)
|
---|
196 | throwException(tr("Missing definition of new object with id {0}.", id));
|
---|
197 | }
|
---|
198 | RelationMember relationMember = new RelationMember(role, member);
|
---|
199 | currentRelationMembers.add(relationMember);
|
---|
200 | }
|
---|
201 |
|
---|
202 | // ---- PARSING TAGS (applicable to all objects) ----
|
---|
203 |
|
---|
204 | else if (qName.equals("tag")) {
|
---|
205 | String key = atts.getValue("k");
|
---|
206 | String value = atts.getValue("v");
|
---|
207 | if (key == null || value == null) {
|
---|
208 | throwException(tr("Missing key or value attribute in tag."));
|
---|
209 | }
|
---|
210 | currentPrimitive.put(key.intern(), value.intern());
|
---|
211 | }
|
---|
212 | else {
|
---|
213 | System.out.println(tr("Undefined element ''{0}'' found in input stream. Skipping.", qName));
|
---|
214 | }
|
---|
215 | }
|
---|
216 | catch (Exception e) {
|
---|
217 | throw new SAXParseException(e.getMessage(), locator, e);
|
---|
218 | }
|
---|
219 | }
|
---|
220 |
|
---|
221 | @Override
|
---|
222 | public void endElement(String namespaceURI, String localName, String qName) {
|
---|
223 | if (qName.equals("node")) {
|
---|
224 | if (currentPrimitive.isDeleted()) {
|
---|
225 | cmds.add(new DeleteCommand( targetDataSet.getPrimitiveById(currentPrimitive.getPrimitiveId()) ));
|
---|
226 | }
|
---|
227 | else if (currentPrimitive.isModified()) {
|
---|
228 | //System.out.println(String.valueOf(currentPrimitive.getUniqueId()) + " IS MODIFIED BY SCRIPT");
|
---|
229 | cmds.add(new ChangeCommand(Main.map.mapView.getEditLayer(), (Node)targetDataSet.getPrimitiveById(currentPrimitive.getPrimitiveId()), currentPrimitive));
|
---|
230 | }
|
---|
231 | else if (currentPrimitive.isNew()) {
|
---|
232 | cmds.add(new AddCommand(currentPrimitive));
|
---|
233 | }
|
---|
234 | }
|
---|
235 | else if (qName.equals("way")) {
|
---|
236 | ((Way)currentPrimitive).setNodes(currentWayNodes);
|
---|
237 | if (currentPrimitive.isDeleted()) {
|
---|
238 | cmds.add(new DeleteCommand( targetDataSet.getPrimitiveById(currentPrimitive.getPrimitiveId()) ));
|
---|
239 | }
|
---|
240 | else if (currentPrimitive.isModified()) {
|
---|
241 | cmds.add(new ChangeCommand(Main.map.mapView.getEditLayer(), (Way)targetDataSet.getPrimitiveById(currentPrimitive.getPrimitiveId()), currentPrimitive));
|
---|
242 | }
|
---|
243 | else if (currentPrimitive.isNew()) {
|
---|
244 | cmds.add(new AddCommand(currentPrimitive));
|
---|
245 | }
|
---|
246 | }
|
---|
247 | else if (qName.equals("relation")) {
|
---|
248 | ((Relation)currentPrimitive).setMembers(currentRelationMembers);
|
---|
249 | if (currentPrimitive.isDeleted()) {
|
---|
250 | cmds.add(new DeleteCommand( targetDataSet.getPrimitiveById(currentPrimitive.getPrimitiveId()) ));
|
---|
251 | }
|
---|
252 | else if (currentPrimitive.isModified()) {
|
---|
253 | cmds.add(new ChangeCommand(Main.map.mapView.getEditLayer(), (Relation)targetDataSet.getPrimitiveById(currentPrimitive.getPrimitiveId()), currentPrimitive));
|
---|
254 | }
|
---|
255 | else if (currentPrimitive.isNew()) {
|
---|
256 | cmds.add(new AddCommand(currentPrimitive));
|
---|
257 | }
|
---|
258 | }
|
---|
259 | }
|
---|
260 |
|
---|
261 | private double getDouble(Attributes atts, String value) {
|
---|
262 | return Double.parseDouble(atts.getValue(value));
|
---|
263 | }
|
---|
264 |
|
---|
265 | private long getLong(Attributes atts, String name) throws SAXException {
|
---|
266 | String value = atts.getValue(name);
|
---|
267 | if (value == null) {
|
---|
268 | throwException(tr("Missing required attribute ''{0}''.",name));
|
---|
269 | }
|
---|
270 | try {
|
---|
271 | return Long.parseLong(value);
|
---|
272 | }
|
---|
273 | catch(NumberFormatException e) {
|
---|
274 | throwException(tr("Illegal long value for attribute ''{0}''. Got ''{1}''.",name, value));
|
---|
275 | }
|
---|
276 | return 0; // should not happen
|
---|
277 | }
|
---|
278 |
|
---|
279 | private User createUser(String uid, String name) throws SAXException {
|
---|
280 | if (uid == null) {
|
---|
281 | if (name == null)
|
---|
282 | return null;
|
---|
283 | return User.createLocalUser(name);
|
---|
284 | }
|
---|
285 | try {
|
---|
286 | long id = Long.parseLong(uid);
|
---|
287 | return User.createOsmUser(id, name);
|
---|
288 | }
|
---|
289 | catch(NumberFormatException e) {
|
---|
290 | throwException(tr("Illegal value for attribute ''uid''. Got ''{0}''.", uid));
|
---|
291 | }
|
---|
292 | return null;
|
---|
293 | }
|
---|
294 |
|
---|
295 | void readCommon(Attributes atts, PrimitiveData current) throws SAXException {
|
---|
296 | current.setId(getLong(atts, "id"));
|
---|
297 | if (current.getUniqueId() == 0) {
|
---|
298 | throwException(tr("Illegal object with ID=0."));
|
---|
299 | }
|
---|
300 |
|
---|
301 | String time = atts.getValue("timestamp");
|
---|
302 | if (time != null && time.length() != 0) {
|
---|
303 | current.setTimestamp(DateUtils.fromString(time));
|
---|
304 | }
|
---|
305 |
|
---|
306 | String user = atts.getValue("user");
|
---|
307 | String uid = atts.getValue("uid");
|
---|
308 | current.setUser(createUser(uid, user));
|
---|
309 |
|
---|
310 | String visible = atts.getValue("visible");
|
---|
311 | if (visible != null) {
|
---|
312 | current.setVisible(Boolean.parseBoolean(visible));
|
---|
313 | }
|
---|
314 |
|
---|
315 | String versionString = atts.getValue("version");
|
---|
316 | int version = 0;
|
---|
317 | if (versionString != null) {
|
---|
318 | try {
|
---|
319 | version = Integer.parseInt(versionString);
|
---|
320 | } catch(NumberFormatException e) {
|
---|
321 | throwException(tr("Illegal value for attribute ''version'' on OSM primitive with ID {0}. Got {1}.", Long.toString(current.getUniqueId()), versionString));
|
---|
322 | }
|
---|
323 | }
|
---|
324 | current.setVersion(version);
|
---|
325 |
|
---|
326 | String action = atts.getValue("action");
|
---|
327 | if (action == null) {
|
---|
328 | // do nothing
|
---|
329 | } else if (action.equals("delete")) {
|
---|
330 | current.setDeleted(true);
|
---|
331 | current.setModified(current.isVisible());
|
---|
332 | } else if (action.equals("modify")) {
|
---|
333 | current.setModified(true);
|
---|
334 | }
|
---|
335 |
|
---|
336 | String v = atts.getValue("changeset");
|
---|
337 | if (v == null) {
|
---|
338 | current.setChangesetId(0);
|
---|
339 | } else {
|
---|
340 | try {
|
---|
341 | current.setChangesetId(Integer.parseInt(v));
|
---|
342 | } catch(NumberFormatException e) {
|
---|
343 | if (current.getUniqueId() <= 0) {
|
---|
344 | System.out.println(tr("Illegal value for attribute ''changeset'' on new object {1}. Got {0}. Resetting to 0.", v, current.getUniqueId()));
|
---|
345 | current.setChangesetId(0);
|
---|
346 | } else {
|
---|
347 | throwException(tr("Illegal value for attribute ''changeset''. Got {0}.", v));
|
---|
348 | }
|
---|
349 | }
|
---|
350 | if (current.getChangesetId() <=0) {
|
---|
351 | if (current.getUniqueId() <= 0) {
|
---|
352 | System.out.println(tr("Illegal value for attribute ''changeset'' on new object {1}. Got {0}. Resetting to 0.", v, current.getUniqueId()));
|
---|
353 | current.setChangesetId(0);
|
---|
354 | } else {
|
---|
355 | throwException(tr("Illegal value for attribute ''changeset''. Got {0}.", v));
|
---|
356 | }
|
---|
357 | }
|
---|
358 | }
|
---|
359 | }
|
---|
360 | }
|
---|
361 | }
|
---|