Changeset 769 in josm
- Timestamp:
- 2008-08-11T22:04:37+02:00 (16 years ago)
- Location:
- trunk/src/org/openstreetmap/josm/io
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/io/BoundingBoxDownloader.java
r627 r769 98 98 Main.pleaseWaitDlg.currentAction.setText(tr("Downloading OSM data...")); 99 99 final DataSet data = OsmReader.parseDataSet(in, null, Main.pleaseWaitDlg); 100 /* 101 * We're not doing this here anymore as the API now properly sets a bounds element 102 * which will get parsed. 100 103 String origin = Main.pref.get("osm-server.url")+"/"+Main.pref.get("osm-server.version", "0.5"); 101 104 Bounds bounds = new Bounds(new LatLon(lat1, lon1), new LatLon(lat2, lon2)); 102 105 DataSource src = new DataSource(bounds, origin); 103 106 data.dataSources.add(src); 107 */ 104 108 in.close(); 105 109 activeConnection = null; -
trunk/src/org/openstreetmap/josm/io/OsmReader.java
r633 r769 50 50 public class OsmReader { 51 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 52 /** 53 * This is used as (readonly) source for finding missing references when not transferred in the 54 * file. 55 */ 56 private DataSet references; 57 58 /** 59 * The dataset to add parsed objects to. 60 */ 61 private DataSet ds = new DataSet(); 62 63 /** 64 * The visitor to use to add the data to the set. 65 */ 66 private AddVisitor adder = new AddVisitor(ds); 67 68 /** 69 * All read nodes after phase 1. 70 */ 71 private Map<Long, Node> nodes = new HashMap<Long, Node>(); 72 73 // TODO: What the hack? Is this really from me? Please, clean this up! 74 private static class OsmPrimitiveData extends OsmPrimitive { 75 @Override public void visit(Visitor visitor) {} 76 public int compareTo(OsmPrimitive o) {return 0;} 77 78 public void copyTo(OsmPrimitive osm) { 79 osm.id = id; 80 osm.keys = keys; 81 osm.modified = modified; 82 osm.selected = selected; 83 osm.deleted = deleted; 84 osm.timestamp = timestamp; 85 osm.user = user; 86 osm.visible = visible; 87 osm.version = version; 88 osm.checkTagged(); 89 89 osm.checkDirectionTagged(); 90 } 91 } 92 93 /** 94 * Used as a temporary storage for relation members, before they 95 * are resolved into pointers to real objects. 96 */ 97 private static class RelationMemberData { 98 public String type; 99 public long id; 100 public RelationMember relationMember; 101 } 102 103 /** 104 * Data structure for the remaining way objects 105 */ 106 private Map<OsmPrimitiveData, Collection<Long>> ways = new HashMap<OsmPrimitiveData, Collection<Long>>(); 107 108 /** 109 * Data structure for relation objects 110 */ 111 private Map<OsmPrimitiveData, Collection<RelationMemberData>> relations = new HashMap<OsmPrimitiveData, Collection<RelationMemberData>>(); 112 113 /** 114 * List of protocol versions that will be accepted on reading 115 */ 116 private HashSet<String> allowedVersions = new HashSet<String>(); 117 118 private class Parser extends DefaultHandler { 119 /** 120 * The current osm primitive to be read. 121 */ 122 private OsmPrimitive current; 123 124 @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { 125 try { 126 if (qName.equals("osm")) { 127 if (atts == null) 128 throw new SAXException(tr("Unknown version")); 129 if (!allowedVersions.contains(atts.getValue("version"))) 130 throw new SAXException(tr("Unknown version")+": "+atts.getValue("version")); 131 } else if (qName.equals("bound")) { 132 String bbox = atts.getValue("box"); 133 String origin = atts.getValue("origin"); 134 if (origin == null) origin = ""; 135 if (bbox != null) { 136 String[] b = bbox.split(","); 137 Bounds bounds = new Bounds(); 138 if (b.length == 4) 139 bounds = new Bounds( 140 new LatLon(Double.parseDouble(b[0]),Double.parseDouble(b[1])), 141 new LatLon(Double.parseDouble(b[2]),Double.parseDouble(b[3]))); 142 DataSource src = new DataSource(bounds, origin); 143 ds.dataSources.add(src); 144 } 145 146 // ---- PARSING NODES AND WAYS ---- 147 148 } else if (qName.equals("node")) { 149 current = new Node(new LatLon(getDouble(atts, "lat"), getDouble(atts, "lon"))); 150 readCommon(atts, current); 151 nodes.put(current.id, (Node)current); 152 } else if (qName.equals("way")) { 153 current = new OsmPrimitiveData(); 154 readCommon(atts, current); 155 ways.put((OsmPrimitiveData)current, new ArrayList<Long>()); 156 } else if (qName.equals("nd")) { 157 Collection<Long> list = ways.get(current); 158 if (list == null) 159 throw new SAXException(tr("Found <nd> element in non-way.")); 160 long id = getLong(atts, "ref"); 161 if (id == 0) 162 throw new SAXException(tr("<nd> has zero ref")); 163 list.add(id); 164 165 // ---- PARSING RELATIONS ---- 166 167 } else if (qName.equals("relation")) { 168 current = new OsmPrimitiveData(); 169 readCommon(atts, current); 170 relations.put((OsmPrimitiveData)current, new LinkedList<RelationMemberData>()); 171 } else if (qName.equals("member")) { 172 Collection<RelationMemberData> list = relations.get(current); 173 if (list == null) 174 throw new SAXException(tr("Found <member> tag on non-relation.")); 175 RelationMemberData emd = new RelationMemberData(); 176 emd.relationMember = new RelationMember(); 177 emd.id = getLong(atts, "ref"); 178 emd.type=atts.getValue("type"); 179 emd.relationMember.role = atts.getValue("role"); 180 181 if (emd.id == 0) 182 throw new SAXException(tr("Incomplete <member> specification with ref=0")); 183 184 list.add(emd); 185 186 // ---- PARSING TAGS (applicable to all objects) ---- 187 188 } else if (qName.equals("tag")) { 189 current.put(atts.getValue("k"), atts.getValue("v")); 190 } 191 } catch (NumberFormatException x) { 192 x.printStackTrace(); // SAXException does not chain correctly 193 throw new SAXException(x.getMessage(), x); 194 } catch (NullPointerException x) { 195 x.printStackTrace(); // SAXException does not chain correctly 196 throw new SAXException(tr("NullPointerException, Possibly some missing tags."), x); 197 } 198 } 199 200 private double getDouble(Attributes atts, String value) { 201 return Double.parseDouble(atts.getValue(value)); 202 } 203 } 204 205 /** 206 * Constructor initializes list of allowed protocol versions. 207 */ 208 public OsmReader() { 209 // first add the main server version 210 allowedVersions.add(Main.pref.get("osm-server.version", "0.5")); 211 // now also add all compatible versions 212 String[] additionalVersions = 213 Main.pref.get("osm-server.additional-versions", "").split("/,/"); 214 if (additionalVersions.length == 1 && additionalVersions[0].length() == 0) 215 additionalVersions = new String[] {}; 216 allowedVersions.addAll(Arrays.asList(additionalVersions)); 217 } 218 219 /** 220 * Read out the common attributes from atts and put them into this.current. 221 */ 222 void readCommon(Attributes atts, OsmPrimitive current) throws SAXException { 223 current.id = getLong(atts, "id"); 224 if (current.id == 0) 225 throw new SAXException(tr("Illegal object with id=0")); 226 227 String time = atts.getValue("timestamp"); 228 if (time != null && time.length() != 0) { 229 /* Do not parse the date here since it wastes a HUGE amount of time. 230 * Moved into OsmPrimitive. 231 try { 232 current.timestamp = DateParser.parse(time); 233 } catch (ParseException e) { 234 e.printStackTrace(); 235 throw new SAXException(tr("Couldn't read time format \"{0}\".",time)); 236 } 237 */ 238 current.timestamp = time; 239 } 240 241 // user attribute added in 0.4 API 242 String user = atts.getValue("user"); 243 if (user != null) { 244 // do not store literally; get object reference for string 245 current.user = User.get(user); 246 } 247 248 // visible attribute added in 0.4 API 249 String visible = atts.getValue("visible"); 250 if (visible != null) { 251 current.visible = Boolean.parseBoolean(visible); 252 } 253 254 // oldversion attribute added in 0.6 API 255 256 // Note there is an asymmetry here: the server will send 257 // the version as "version" the client sends it as 258 // "oldversion". So we take both since which we receive will 259 // depend on reading from a file or reading from the server 260 261 String version = atts.getValue("version"); 262 if (version != null) { 263 current.version = Integer.parseInt(version); 264 } 265 version = atts.getValue("old_version"); 266 if (version != null) { 267 current.version = Integer.parseInt(version); 268 } 269 270 String action = atts.getValue("action"); 271 if (action == null) 272 return; 273 if (action.equals("delete")) 274 current.delete(true); 275 else if (action.startsWith("modify")) 276 current.modified = true; 277 } 278 private long getLong(Attributes atts, String value) throws SAXException { 279 String s = atts.getValue(value); 280 if (s == null) 281 throw new SAXException(tr("Missing required attribute \"{0}\".",value)); 282 return Long.parseLong(s); 283 } 284 285 private Node findNode(long id) { 286 Node n = nodes.get(id); 287 if (n != null) 288 return n; 289 for (Node node : references.nodes) 290 if (node.id == id) 291 return node; 292 // TODO: This has to be changed to support multiple layers. 293 for (Node node : Main.ds.nodes) 294 if (node.id == id) 295 return new Node(node); 296 return null; 90 } 91 } 92 93 /** 94 * Used as a temporary storage for relation members, before they 95 * are resolved into pointers to real objects. 96 */ 97 private static class RelationMemberData { 98 public String type; 99 public long id; 100 public RelationMember relationMember; 101 } 102 103 /** 104 * Data structure for the remaining way objects 105 */ 106 private Map<OsmPrimitiveData, Collection<Long>> ways = new HashMap<OsmPrimitiveData, Collection<Long>>(); 107 108 /** 109 * Data structure for relation objects 110 */ 111 private Map<OsmPrimitiveData, Collection<RelationMemberData>> relations = new HashMap<OsmPrimitiveData, Collection<RelationMemberData>>(); 112 113 /** 114 * List of protocol versions that will be accepted on reading 115 */ 116 private HashSet<String> allowedVersions = new HashSet<String>(); 117 118 private class Parser extends DefaultHandler { 119 /** 120 * The current osm primitive to be read. 121 */ 122 private OsmPrimitive current; 123 private String generator; 124 125 @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { 126 try { 127 if (qName.equals("osm")) { 128 if (atts == null) 129 throw new SAXException(tr("Unknown version")); 130 if (!allowedVersions.contains(atts.getValue("version"))) 131 throw new SAXException(tr("Unknown version")+": "+atts.getValue("version")); 132 // save generator attribute for later use when creating DataSource objects 133 generator = atts.getValue("generator"); 134 135 136 } else if (qName.equals("bound")) { 137 // old style bounds. 138 // TODO: remove this around 1st October 2008. 139 // - this is a bit of a hack; since we still write out old style bound objects, 140 // we don't want to load them both. so when writing, we add a "note" tag the our 141 // old-style bound, and when reading, ignore those with a "note". 142 String note = atts.getValue("note"); 143 if (note == null) { 144 System.out.println("Notice: old style <bound> element detected; support for these will be dropped in a future release."); 145 String bbox = atts.getValue("box"); 146 String origin = atts.getValue("origin"); 147 if (origin == null) origin = ""; 148 if (bbox != null) { 149 String[] b = bbox.split(","); 150 Bounds bounds = new Bounds(); 151 if (b.length == 4) 152 bounds = new Bounds( 153 new LatLon(Double.parseDouble(b[0]),Double.parseDouble(b[1])), 154 new LatLon(Double.parseDouble(b[2]),Double.parseDouble(b[3]))); 155 DataSource src = new DataSource(bounds, origin); 156 ds.dataSources.add(src); 157 } 158 } 159 } else if (qName.equals("bounds")) { 160 // new style bounds. 161 String minlon = atts.getValue("minlon"); 162 String minlat = atts.getValue("minlat"); 163 String maxlon = atts.getValue("maxlon"); 164 String maxlat = atts.getValue("maxlat"); 165 String origin = atts.getValue("origin"); 166 if (minlon != null && maxlon != null && minlat != null && maxlat != null) { 167 if (origin == null) origin = generator; 168 Bounds bounds = new Bounds( 169 new LatLon(Double.parseDouble(minlat), Double.parseDouble(minlon)), 170 new LatLon(Double.parseDouble(maxlat), Double.parseDouble(maxlon))); 171 DataSource src = new DataSource(bounds, origin); 172 ds.dataSources.add(src); 173 } 174 175 // ---- PARSING NODES AND WAYS ---- 176 177 } else if (qName.equals("node")) { 178 current = new Node(new LatLon(getDouble(atts, "lat"), getDouble(atts, "lon"))); 179 readCommon(atts, current); 180 nodes.put(current.id, (Node)current); 181 } else if (qName.equals("way")) { 182 current = new OsmPrimitiveData(); 183 readCommon(atts, current); 184 ways.put((OsmPrimitiveData)current, new ArrayList<Long>()); 185 } else if (qName.equals("nd")) { 186 Collection<Long> list = ways.get(current); 187 if (list == null) 188 throw new SAXException(tr("Found <nd> element in non-way.")); 189 long id = getLong(atts, "ref"); 190 if (id == 0) 191 throw new SAXException(tr("<nd> has zero ref")); 192 list.add(id); 193 194 // ---- PARSING RELATIONS ---- 195 196 } else if (qName.equals("relation")) { 197 current = new OsmPrimitiveData(); 198 readCommon(atts, current); 199 relations.put((OsmPrimitiveData)current, new LinkedList<RelationMemberData>()); 200 } else if (qName.equals("member")) { 201 Collection<RelationMemberData> list = relations.get(current); 202 if (list == null) 203 throw new SAXException(tr("Found <member> tag on non-relation.")); 204 RelationMemberData emd = new RelationMemberData(); 205 emd.relationMember = new RelationMember(); 206 emd.id = getLong(atts, "ref"); 207 emd.type=atts.getValue("type"); 208 emd.relationMember.role = atts.getValue("role"); 209 210 if (emd.id == 0) 211 throw new SAXException(tr("Incomplete <member> specification with ref=0")); 212 213 list.add(emd); 214 215 // ---- PARSING TAGS (applicable to all objects) ---- 216 217 } else if (qName.equals("tag")) { 218 current.put(atts.getValue("k"), atts.getValue("v")); 219 } 220 } catch (NumberFormatException x) { 221 x.printStackTrace(); // SAXException does not chain correctly 222 throw new SAXException(x.getMessage(), x); 223 } catch (NullPointerException x) { 224 x.printStackTrace(); // SAXException does not chain correctly 225 throw new SAXException(tr("NullPointerException, Possibly some missing tags."), x); 226 } 227 } 228 229 private double getDouble(Attributes atts, String value) { 230 return Double.parseDouble(atts.getValue(value)); 231 } 232 } 233 234 /** 235 * Constructor initializes list of allowed protocol versions. 236 */ 237 public OsmReader() { 238 // first add the main server version 239 allowedVersions.add(Main.pref.get("osm-server.version", "0.5")); 240 // now also add all compatible versions 241 String[] additionalVersions = 242 Main.pref.get("osm-server.additional-versions", "").split("/,/"); 243 if (additionalVersions.length == 1 && additionalVersions[0].length() == 0) 244 additionalVersions = new String[] {}; 245 allowedVersions.addAll(Arrays.asList(additionalVersions)); 246 } 247 248 /** 249 * Read out the common attributes from atts and put them into this.current. 250 */ 251 void readCommon(Attributes atts, OsmPrimitive current) throws SAXException { 252 current.id = getLong(atts, "id"); 253 if (current.id == 0) 254 throw new SAXException(tr("Illegal object with id=0")); 255 256 String time = atts.getValue("timestamp"); 257 if (time != null && time.length() != 0) { 258 /* Do not parse the date here since it wastes a HUGE amount of time. 259 * Moved into OsmPrimitive. 260 try { 261 current.timestamp = DateParser.parse(time); 262 } catch (ParseException e) { 263 e.printStackTrace(); 264 throw new SAXException(tr("Couldn't read time format \"{0}\".",time)); 265 } 266 */ 267 current.timestamp = time; 268 } 269 270 // user attribute added in 0.4 API 271 String user = atts.getValue("user"); 272 if (user != null) { 273 // do not store literally; get object reference for string 274 current.user = User.get(user); 275 } 276 277 // visible attribute added in 0.4 API 278 String visible = atts.getValue("visible"); 279 if (visible != null) { 280 current.visible = Boolean.parseBoolean(visible); 281 } 282 283 // oldversion attribute added in 0.6 API 284 285 // Note there is an asymmetry here: the server will send 286 // the version as "version" the client sends it as 287 // "oldversion". So we take both since which we receive will 288 // depend on reading from a file or reading from the server 289 290 String version = atts.getValue("version"); 291 if (version != null) { 292 current.version = Integer.parseInt(version); 293 } 294 version = atts.getValue("old_version"); 295 if (version != null) { 296 current.version = Integer.parseInt(version); 297 } 298 299 String action = atts.getValue("action"); 300 if (action == null) 301 return; 302 if (action.equals("delete")) 303 current.delete(true); 304 else if (action.startsWith("modify")) 305 current.modified = true; 306 } 307 private long getLong(Attributes atts, String value) throws SAXException { 308 String s = atts.getValue(value); 309 if (s == null) 310 throw new SAXException(tr("Missing required attribute \"{0}\".",value)); 311 return Long.parseLong(s); 312 } 313 314 private Node findNode(long id) { 315 Node n = nodes.get(id); 316 if (n != null) 317 return n; 318 for (Node node : references.nodes) 319 if (node.id == id) 320 return node; 321 // TODO: This has to be changed to support multiple layers. 322 for (Node node : Main.ds.nodes) 323 if (node.id == id) 324 return new Node(node); 325 return null; 297 326 } 298 327 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 *the Reference is not found here, Main.ds is searched and a copy of the405 406 407 408 409 410 411 412 413 414 328 private void createWays() { 329 for (Entry<OsmPrimitiveData, Collection<Long>> e : ways.entrySet()) { 330 Way w = new Way(); 331 boolean failed = false; 332 for (long id : e.getValue()) { 333 Node n = findNode(id); 334 if (n == null) { 335 failed = true; 336 break; 337 } 338 w.nodes.add(n); 339 } 340 if (failed) continue; 341 e.getKey().copyTo(w); 342 adder.visit(w); 343 } 344 345 } 346 347 /** 348 * Return the Way object with the given id, or null if it doesn't 349 * exist yet. This method only looks at ways stored in the data set. 350 * 351 * @param id 352 * @return way object or null 353 */ 354 private Way findWay(long id) { 355 for (Way wy : ds.ways) 356 if (wy.id == id) 357 return wy; 358 for (Way wy : Main.ds.ways) 359 if (wy.id == id) 360 return wy; 361 return null; 362 } 363 364 /** 365 * Return the Relation object with the given id, or null if it doesn't 366 * exist yet. This method only looks at relations stored in the data set. 367 * 368 * @param id 369 * @return relation object or null 370 */ 371 private Relation findRelation(long id) { 372 for (Relation e : ds.relations) 373 if (e.id == id) 374 return e; 375 for (Relation e : Main.ds.relations) 376 if (e.id == id) 377 return e; 378 return null; 379 } 380 381 /** 382 * Create relations. This is slightly different than n/s/w because 383 * unlike other objects, relations may reference other relations; it 384 * is not guaranteed that a referenced relation will have been created 385 * before it is referenced. So we have to create all relations first, 386 * and populate them later. 387 */ 388 private void createRelations() { 389 390 // pass 1 - create all relations 391 for (Entry<OsmPrimitiveData, Collection<RelationMemberData>> e : relations.entrySet()) { 392 Relation en = new Relation(); 393 e.getKey().copyTo(en); 394 adder.visit(en); 395 } 396 397 // pass 2 - sort out members 398 for (Entry<OsmPrimitiveData, Collection<RelationMemberData>> e : relations.entrySet()) { 399 Relation en = findRelation(e.getKey().id); 400 if (en == null) throw new Error("Failed to create relation " + e.getKey().id); 401 402 for (RelationMemberData emd : e.getValue()) { 403 RelationMember em = emd.relationMember; 404 if (emd.type.equals("node")) { 405 em.member = findNode(emd.id); 406 if (em.member == null) { 407 em.member = new Node(emd.id); 408 adder.visit((Node)em.member); 409 } 410 } else if (emd.type.equals("way")) { 411 em.member = findWay(emd.id); 412 if (em.member == null) { 413 em.member = new Way(emd.id); 414 adder.visit((Way)em.member); 415 } 416 } else if (emd.type.equals("relation")) { 417 em.member = findRelation(emd.id); 418 if (em.member == null) { 419 em.member = new Relation(emd.id); 420 adder.visit((Relation)em.member); 421 } 422 } else { 423 // this is an error. 424 } 425 en.members.add(em); 426 } 427 } 428 } 429 430 /** 431 * Parse the given input source and return the dataset. 432 * @param ref The dataset that is search in for references first. If 433 * the Reference is not found here, Main.ds is searched and a copy of the 434 * elemet found there is returned. 435 */ 436 public static DataSet parseDataSet(InputStream source, DataSet ref, PleaseWaitDialog pleaseWaitDlg) throws SAXException, IOException { 437 OsmReader osm = new OsmReader(); 438 osm.references = ref == null ? new DataSet() : ref; 439 440 // phase 1: Parse nodes and read in raw ways 441 InputSource inputSource = new InputSource(new InputStreamReader(source, "UTF-8")); 442 try { 443 SAXParserFactory.newInstance().newSAXParser().parse(inputSource, osm.new Parser()); 415 444 } catch (ParserConfigurationException e1) { 416 417 445 e1.printStackTrace(); // broken SAXException chaining 446 throw new SAXException(e1); 418 447 } 419 448 420 449 if (pleaseWaitDlg != null) { 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 450 pleaseWaitDlg.progress.setValue(0); 451 pleaseWaitDlg.currentAction.setText(tr("Preparing data...")); 452 } 453 454 for (Node n : osm.nodes.values()) 455 osm.adder.visit(n); 456 457 try { 458 osm.createWays(); 459 osm.createRelations(); 460 } catch (NumberFormatException e) { 461 e.printStackTrace(); 462 throw new SAXException(tr("Illformed Node id")); 463 } 464 465 // clear all negative ids (new to this file) 466 for (OsmPrimitive o : osm.ds.allPrimitives()) 467 if (o.id < 0) 468 o.id = 0; 469 470 return osm.ds; 471 } 443 472 } -
trunk/src/org/openstreetmap/josm/io/OsmWriter.java
r627 r769 94 94 super.header(out); 95 95 for (DataSource s : ds.dataSources) { 96 out.print(" <bound box='"+ 96 // TODO: remove <bound> output after a grace period (1st October 08) 97 out.print(" <bound note='this tag is deprecated and only provided for backward compatiblity' box='"+ 97 98 s.bounds.min.lat()+","+ 98 99 s.bounds.min.lon()+","+ 99 100 s.bounds.max.lat()+","+ 101 s.bounds.max.lon()+"' "); 102 out.println("origin='"+XmlWriter.encode(s.origin)+"' />"); 103 out.print(" <bounds minlat='" + 104 s.bounds.min.lat()+"' minlon='"+ 105 s.bounds.min.lon()+"' maxlat='"+ 106 s.bounds.max.lat()+"' maxlon='"+ 100 107 s.bounds.max.lon()+"' "); 101 108 out.println("origin='"+XmlWriter.encode(s.origin)+"' />");
Note:
See TracChangeset
for help on using the changeset viewer.